SharpRevenue Bulk Eligibility and Queued Requests
RunSharpRevenue (covered in the testing guide) is synchronous: one request, one payer call, one answer in the response. That is the right tool for a check at the front desk. It is the wrong tool for checking tomorrow's 3,000 appointments, because firing thousands of synchronous calls in parallel puts that load on the payers, and payers rate-limit or block senders that burst.
For volume, ClaimRev provides a queued path. You hand ClaimRev the whole list, ClaimRev feeds it to the payers at a controlled pace, and you collect the results when they are ready.
| You want to... | Use |
|---|---|
| Check one patient now and wait for the answer | RunSharpRevenue (synchronous) |
| Check hundreds or thousands of patients | Bulk upload (this page) |
| Re-run one request that failed | RunSharpRevenueInTopic (this page) |
How the queue protects you
Every request on the queued path goes through a server-side work queue that dispatches only a small, fixed number of payer calls at a time. You do not need to pace your submissions, add delays, or batch your uploads into small chunks. Upload 5,000 rows in one file and the queue drains them steadily.
The trade-off is time. Results arrive over minutes to hours depending on the size of the batch and on how much other work is in the queue, not all at once. Plan to poll, not to wait on a response.
Do not build your own fan-out on top of RunSharpRevenue to get throughput. A loop of parallel synchronous calls bypasses the queue, and the payer-side rate limits it trips apply to the whole ClaimRev connection, not just your account.
Bulk eligibility: the end-to-end flow
1. Upload an .xlsx file POST UploadBulkRtEligibilityFile -> true
2. Find your file's id POST SearchBulkInputFiles -> objectId
3. List the rows POST SearchPatientsInRtBatch -> one sharpRevenueObjectId per row
4. Fetch each result GET GetEligibility?...={id} -> 271 result
All endpoints are under https://api.claimrev.com/api/SharpRevenue/v1/ and need a bearer token (see Authentication). Results are scoped to the account your credentials are attached to.
Prerequisites
- Your account must have a Revenue Tools practice configured (practice name, state, and the vendor settings ClaimRev sets up during onboarding). Rows fail with an error if the practice is missing.
- Bulk upload runs Eligibility only (product
1). For Coverage Discovery or Demographics, useRunSharpRevenue.
Step 1: Build the file
The file must be an Excel .xlsx workbook. CSV is not accepted on this endpoint. Only the first sheet is read, and the first row is treated as a header and skipped.
Header names are ignored. Each column is read by its position, so the order below must be exact, and an empty column must still be present. Download the template rather than building the layout by hand:
GET /api/SharpRevenue/v1/GetRevenueToolProductsBulkTemplate
The response is { "fileName": "...", "fileText": "<base64>" }. Decode fileText to get the .xlsx.
| # | Column | Notes |
|---|---|---|
| A | Patient last name | Required |
| B | Patient first name | Required |
| C | Patient middle name | |
| D | Patient DOB | Required. Any unambiguous date format, e.g. 1980-04-12 |
| E | Patient gender | M / F |
| F | Patient SSN | |
| G | Visit number | Your own identifier. Returned with the result, useful for matching rows back |
| H | Service date | Defaults to the upload date if blank or unreadable |
| I | Patient address 1 | |
| J | Patient address 2 | |
| K | Patient city | |
| L | Patient state | |
| M | Patient ZIP | |
| N | NPI | Rendering or billing NPI for the check |
| O | Payer ID | Required. The Revenue Tools payer ID, not your claim payer ID. Look these up with the MCP server search_sharp_revenue_payers tool, or the sharpRevenuePayerId field on a ClaimRev payer |
| P | Subscriber ID | Member ID. Required by most payers |
| Q | Facility state | |
| R | Patient phone | |
| S | Patient email | |
| T | Subscriber first name | Fill when the subscriber is not the patient |
| U | Subscriber last name | |
| V | Subscriber SSN | |
| W | Subscriber phone | |
| X | Subscriber gender | |
| Y | Subscriber DOB | |
| Z | Client balance | |
| AA | Subscriber address 1 | |
| AB | Subscriber address 2 | |
| AC | Subscriber city | |
| AD | Subscriber state | |
| AE | Subscriber ZIP | |
| AF | Subscriber phone 2 | |
| AG | Subscriber email |
A row with an unknown payer ID is rejected on its own; the rest of the file still runs.
Step 2: Upload
curl -X POST "https://api.claimrev.com/api/SharpRevenue/v1/UploadBulkRtEligibilityFile" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@tomorrows-appointments.xlsx"
The response is true when the file was accepted, false when it could not be stored. You can attach more than one file in the same request; each becomes its own batch.
Acceptance is not processing. The file is parsed in the background a few seconds later.
Step 3: Find your batch
The upload response does not include an id, so look the file up by name. Use a file name that is unique to the upload (a timestamp works well).
POST /api/SharpRevenue/v1/SearchBulkInputFiles
Content-Type: application/json
{
"customerFileName": "tomorrows-appointments-20261001-0700.xlsx",
"batchType": "rt-eligibility"
}
[
{
"objectId": "66fb9c2e8a1d4e0012ab34cd",
"customerFileName": "tomorrows-appointments-20261001-0700.xlsx",
"batchType": "rt-eligibility",
"processStatus": 2,
"processStatusDesc": "Complete",
"statusMessage": null
}
]
processStatus | Meaning |
|---|---|
1 Ready | Uploaded, not yet parsed |
5 In Process | Rows are being read and queued |
2 Complete | Every row has been read and queued. This does not mean the eligibility results are back; see Step 4 |
4 Error | The file could not be read. statusMessage says why. Nothing was queued |
Step 4: Collect results
List the rows in the batch, passing the file's objectId:
POST /api/SharpRevenue/v1/SearchPatientsInRtBatch
Content-Type: application/json
{ "objectId": "66fb9c2e8a1d4e0012ab34cd" }
{
"totalRecords": 3000,
"results": [
{
"batchObjectId": "66fb9c2f8a1d4e0012ab34d0",
"bulkBatchObjectId": "66fb9c2e8a1d4e0012ab34cd",
"sharpRevenueObjectId": "66fb9c2f8a1d4e0012ab34cf",
"firstName": "Heath",
"lastName": "Varner",
"dateOfBirth": "2023-11-03T00:00:00",
"messages": "Queued for processing",
"requestStatus": 4
}
]
}
The whole batch is returned in one response, sorted by last name. Save each row's sharpRevenueObjectId; that is the id of the eligibility result.
Then fetch each result:
GET /api/SharpRevenue/v1/GetEligibility?sharpRevenueRtEligibilityObjectId=66fb9c2f8a1d4e0012ab34cf
The response is a visit wrapper whose sharpRevenueData has the same shape as a RunSharpRevenue response, including mappedData, isFatalError, retryLater, and responseMessage.
Knowing when a row is finished
Each batch row carries a requestStatus:
requestStatus | Meaning |
|---|---|
4 Pending | Waiting in the queue, or waiting on the payer. Poll again later |
2 Complete | Done. Fetch the result with GetEligibility |
3 Error | Done, failed. messages has the reason. You can re-run it |
GetEligibility tells you the same thing for a single id:
| What you see | Meaning |
|---|---|
retryLater: true | Still pending. Poll again later |
isFatalError: false, retryLater: false | Done. Read the 271 result in mappedData |
isFatalError: true | Done, failed. responseMessage has the reason |
A reasonable poller lists the batch every few minutes, fetches GetEligibility for rows that have left Pending, and stops once no rows are Pending. Rows that could not be queued at all come back as Error with the message Could not be queued for processing; re-run them.
Re-running a failed request
When a single result comes back with isFatalError: true because of something transient (payer timeout, payer down), you can send the same stored request through the queue again without re-uploading:
POST /api/SharpRevenue/v1/RunSharpRevenueInTopic
Content-Type: application/json
"66fb9c2f8a1d4e0012ab34cf"
The body is the sharpRevenueObjectId as a bare JSON string (quoted, not wrapped in an object). Requires the sharprevenue:realtime scope.
| Response | Meaning |
|---|---|
200 true | Queued (or already queued) |
404 | No request with that id on your account |
503 | The queue could not accept the request. The stored result is unchanged; try again later |
Notes:
- It re-runs; it does not create. The id must be an existing result, from a batch row or a
claimRevResultId. To check a new patient, use bulk upload orRunSharpRevenue. - It returns immediately.
truemeans "queued", not "succeeded". It goes through the same throttled queue as bulk rows, so it may wait behind a large batch. - The request switches to Pending right away. Poll
GetEligibilitywith the id you sent:retryLater: trueuntil the re-run finishes, then the new result, which overwrites the old one. - Re-running a request that is still waiting in the queue is a no-op. It returns
truewithout queueing a second payer call, so a double-click or a retry loop cannot send the same check twice. - A request that the payer side left pending can be re-run. Some results, Coverage Discovery in particular, can stay pending at the clearinghouse indefinitely. If a result has shown
retryLater: truefor more than an hour, re-run it rather than polling forever. - Fix the data first. Re-running sends the exact same request. If the failure was bad input (wrong member ID, wrong payer), a re-run fails the same way; correct the data and submit a new row instead.
Endpoint summary
| Method | Endpoint | Purpose |
|---|---|---|
GET | GetRevenueToolProductsBulkTemplate | Download the .xlsx template (base64) |
POST | UploadBulkRtEligibilityFile | Upload a batch (multipart form, .xlsx) |
POST | SearchBulkInputFiles | Find a batch by file name; read its parse status |
POST | SearchPatientsInRtBatch | List rows in a batch with their result ids |
GET | GetEligibility | Fetch one result by sharpRevenueObjectId |
POST | RunSharpRevenueInTopic | Re-queue one existing request |
Full request and response schemas are in the API Reference.