MedBillAnalyzer

API

Seven operations

Send a bill and the Explanation of Benefits your insurer issued for the same care. Get back where the two disagree, and a letter you can send about it.

Status: live. The base URL is https://app.medbillanalyzer.com. Most operations answer immediately; check_medical_bill reads the documents with a model and usually takes 10–30 seconds, so allow a timeout of a few minutes. The document below is generated from the code that serves these operations, not written alongside it.

Shape

What the calls are

CallDoesCostsAccess
POST /v1/cases Reads the documents and compares them. Returns how many findings there are and how much is in question. Free Write
GET /v1/cases/{id} The same summary, plus every finding in detail once the case is unlocked. Free / paid Read
POST /v1/cases/{id}/unlock Given a Stripe shared payment token, charges $10 and unlocks the case in the same call. Without one, returns a checkout URL and charges nothing itself. $10 per bill Sensitive write
POST /v1/cases/{id}/outputs The dispute letter and the phone script, in the patient's name. Paid Read
GET /v1/cases/{id}/export Everything held about the case, as JSON. Needs no token and costs nothing — you cannot be charged to see what we hold about you. Free Read
POST /v1/cases/{id}/outcome What came of the letter — corrected, refused, ignored, or never sent. The answer is counted in aggregate and never recorded against the case. Free Write
DELETE /v1/cases/{id} Destroys the case. Needs the one-time delete token issued when it was created; the case id alone reads, it does not erase. Free Sensitive write

Access is how each call should be approved. A Read changes nothing. A Write creates or changes a case. A Sensitive write is a purchase or a deletion, and the person should approve it every time.

Seven, deliberately. Four do the work; two exist because a person is entitled to take their record back and to destroy it, and a right nobody can exercise through the API is not a right; one asks what came of it. An agent works better against a surface it can hold at once, so there are no other operations — only the file handoff below, which carries bytes rather than doing anything to a case.

Handoff

A file you cannot attach

An Explanation of Benefits usually sits behind the insurer’s login. There is nothing to attach and no link this service can follow — it sends no cookies and holds no credentials — so the patient downloads it and the file is handed over in two steps, then named in the scan as { "upload_id": "…" }.

CallDoesAccess
POST /v1/uploads Reserves a slot: one file, 15 minutes, held in memory only. Returns upload_id and upload_url. Write
PUT /v1/uploads/{upload_id} The file itself as the request body — raw bytes, not JSON or base64. PDF, JPEG, PNG, GIF or WebP, up to 12 MB. upload_url is where this goes; it is not a page to send the patient to. Write
GET /v1/capabilities Whether this deployment can read an uploaded document at all. Ask before asking a patient for a file. Read

Two things that bite

Read these before you call it

  • Never add the findings together. amount_in_question_cents is already de-duplicated. Two findings routinely describe the same dollars from different angles — a line billed above the contracted rate is usually also part of a bill that asks for more than the plan says is owed — so summing them overstates the problem in a letter a patient signs and sends. Use the total we give you.
  • next_step is addressed to you, not to the patient. It says things like "Ask the patient for a clearer copy". If you are rendering straight to a person, use you_can, which is the same guidance in the second person.
  • The comparison is not done by a model. A reader transcribes what is printed; fixed rules decide what it means. The same documents always produce the same findings, and every finding names the rule behind it.
  • Send the document, not your own transcription. Both work, but bill_document is read by an extractor tuned for these forms and measured against a field-accuracy harness. Your own parse is not.

Errors

Every failure says what to do

Each error carries a stable code to branch on, a message that is safe to show a patient, and guidance. The status is specific on purpose: a generic 4xx sends an agent into a debugging loop that burns the user's usage meter. The OpenAPI document lists, for each operation, the statuses it can actually answer with and the codes under each.

StatusMeans
402The case is not unlocked. Call unlock first.
409Nothing to unlock — there were no findings. Do not offer to sell anything.
415We cannot read that kind of file.
422The document was too poor to check. Ask for a clearer copy.
429Back off and retry.
503A dependency is down, or the feature is not switched on here. next_step says which, and what to do.

Also

The same operations as MCP tools

The same seven operations are also served as MCP tools at https://app.medbillanalyzer.com/mcp (Streamable HTTP, no sign-in), with the same names and the same schemas — both faces are generated from one declaration, so they cannot drift apart, and they share one store: a case created through either is the same case. Each tool carries a title and read-only or destructive annotations. To use them in Claude, add a custom connector; in Grok, use https://app.medbillanalyzer.com/mcp/grok, the same server, added the same way. check_medical_bill, get_case, unlock_case, get_case_outputs, delete_case, export_case, report_outcome.

The machine-readable description is at /openapi.json. It is generated from the routing table, so it describes what the server actually answers rather than what someone remembered to write down.