Getting started
Build with AI
Point an AI tool at the OpenAPI document, llms.txt and the markdown pages of these docs, and the MCP server that lets an AI tool do everything the API does.
Claim House is built to be used by AI tools as well as by people. Give Claude, Cursor or your own agent these resources and it can write a working eligibility integration without anyone reading X12.
Machine-readable docs#
| Resource | What it is | Address |
|---|---|---|
| OpenAPI 3.1 document | Every endpoint, field and error code, generated from the same definitions the API checks requests with, so it matches the API exactly. Agents and code generators read this. | https://sandbox.myclaimhouse.com/docs/openapi.json |
llms.txt | An index of every docs page, one line each, with its description. | https://sandbox.myclaimhouse.com/docs/llms.txt |
llms-full.txt | Every docs page as markdown, in one file, for a model's context. | https://sandbox.myclaimhouse.com/docs/llms-full.txt |
| Markdown pages | Add .md to the address of any docs page to get the page without navigation or styling. | https://sandbox.myclaimhouse.com/docs/quickstart.md |
The reference pages are generated from the API's own definitions, so a field list on a reference page and in the OpenAPI document are the same thing. The guides are written by hand and their curl examples are run against the sandbox by the tests.
Prompting tips#
- Give it the spec. Paste the
openapi.jsonaddress, orllms-full.txt, so the agent uses real field names instead of guessing. Every field issnake_case. - Start in the sandbox. Ask the agent to use a test key and the scripted member IDs:
CH-ACTIVE-FULLfor an answer,CH-NOT-FOUNDfor a rejection it can fix,CH-PAYER-DOWNfor a payer that is down. See Sandbox and scenarios. - Handle every outcome. Tell it to branch on the check's
outcome, and onrejection.kind:fix_and_resend,payer_unavailableorrejected. - Make requests safe to repeat. Tell it to send a new
Idempotency-Keyfor each new attempt, and to reuse a key only to repeat a request that got no answer. See Errors, retries and idempotency. - Keep patient data out of prompts and logs. Use made-up people. Never give an agent a live key unless you mean it to touch real patients.
A prompt that works well:
Using the Claim House API described at https://sandbox.myclaimhouse.com/docs/openapi.json, write a function that runs an
eligibility check with a test key, returns the plan's remaining annual maximum, and, when the payer
rejects the check with kind fix_and_resend, resends it once with the corrected value and parent_id.
Use the sandbox member IDs CH-NOT-FOUND and CH-ACTIVE-FULL to test both paths.MCP server#
The MCP server lets an AI tool (Claude, Cursor or your own agent) do everything the API does: find payers, keep offices and providers, run eligibility checks, send claims, upload attachments, read ERAs, manage webhooks and read usage. It has a tool for every API endpoint and a few that explain answers, with the same API key, permissions, validation, idempotency and errors as the API.
Connect to https://sandbox.myclaimhouse.com/api/mcp over streamable HTTP and send your API key as a bearer token in the Authorization header. Keep the key in an environment variable or your client's secret store, never in a file you share.
Claude Code
claude mcp add --transport http claimhouse https://sandbox.myclaimhouse.com/api/mcp \
--header "Authorization: Bearer $CLAIMHOUSE_KEY"Cursor (.cursor/mcp.json)
{
"mcpServers": {
"claimhouse": {
"url": "https://sandbox.myclaimhouse.com/api/mcp",
"headers": { "Authorization": "Bearer ${env:CLAIMHOUSE_KEY}" }
}
}
}Claude Desktop (claude_desktop_config.json, through the mcp-remote bridge, which connects a desktop client to a remote server)
{
"mcpServers": {
"claimhouse": {
"command": "npx",
"args": ["mcp-remote", "https://sandbox.myclaimhouse.com/api/mcp", "--header", "Authorization:${AUTH_HEADER}"],
"env": { "AUTH_HEADER": "Bearer ch_test_<key id>.<secret>" }
}
}
}The header argument has no space in it (Authorization:${AUTH_HEADER}) and the key is in env: on Windows, Claude Desktop and Cursor pass an argument with spaces to the bridge unquoted, which breaks it.
Any other client: a streamable HTTP server at https://sandbox.myclaimhouse.com/api/mcp, with the header Authorization: Bearer <your key>.
A test key only ever reaches the sandbox, so an agent cannot touch real patient data until you give it a live key. Live mode is not open yet, so every key is a test key today.
Tools#
There are 74 tools: one for each of the API's 69 endpoints, named after the endpoint's operation (list_claims is GET /claims), and 5 curated tools that add judgement on top. tools/list gives each tool's full description and input schema, and marks its permission (_meta.permission) and product.
tools/list is about 116 KB of descriptions and schemas for all 74 tools. Some clients keep only so many tools active at once (Cursor about 40) or send every tool's description with each prompt: in your client's tool settings, turn on the tools of the products your agent needs (for a claims agent: payers, offices, providers, patients, claims, attachments and ERAs) and leave the rest off.
The curated tools:
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
search_payers | read | no | Find a dental payer by name, payer ID or alias, with what it supports. |
check_eligibility | submit | yes | Run an eligibility check (a sandbox check with a test key); it can correct a rejected check with parent_id, and needs an idempotency_key so a retry never runs it twice. |
explain_rejection | read | no | Turn a rejection into its kind, reasons, the fields to change and suggested values. |
find_check | read | no | Find checks you already ran, by the request ID of the call or your own reference. |
read_benefits | read | no | Read the answer of a check: status, maximums, deductibles, coverage by category, per-procedure rows and what was not returned. |
The API's endpoints, by product, in the order an agent usually works through them:
Account#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_current_key | read | no | Returns the API key making the request (its name, mode and permissions) and the organization it belongs to. |
Payers#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_payer | read | no | One payer, by its Claim House ID (pyr_...), its payer ID or any alias. |
list_payers | read | no | The payer directory, ordered by name, one page at a time. |
searchPayers | read | no | Finds payers by name, payer ID or alias, best matches first (at most 25). |
Offices#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_office | read | no | One office of the key's organization and mode. |
list_offices | read | no | The offices of the key's organization, in the key's mode (test or live). |
register_office_attachments | submit | yes | Registers the office with the attachment network, once: it needs its contact name and email, its primary doctor's name, and its address, phone and tax ID. |
Providers#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
create_provider | submit | yes | Adds a dentist who renders treatment, so a claim can name them as its rendering provider. |
get_provider | read | no | One provider of the key's organization and mode. |
list_providers | read | no | The providers of the key's organization in the key's mode (test or live), by last name, one page at a time. |
update_provider | submit | yes | Changes the fields sent and leaves the rest. |
Enrollments#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
create_enrollment | submit | yes | Starts tracking the enrollment of a provider with a payer for claims, ERAs, or ERAs with EFT. |
get_enrollment | read | no | One enrollment of the key's organization and mode. |
list_enrollments | read | no | The enrollments of the key's organization in the key's mode, newest first, one page at a time. |
update_enrollment | submit | yes | Changes the fields sent and leaves the rest: the status (only along the allowed changes: an open enrollment may move to another open status or to active, paperwork submitted to the payer is never not started again, and an active one may only start over), the dates (null clears one) and the note. |
Patients#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_patient | read | no | One patient with coverage as last verified, and their newest checks, claims (void transactions left out) and payments on any of their claims (up to 25 of each), by ID and state. |
list_patients | read | no | The patients of your organization in the key's mode, newest first (by when Claim House first saw them), with coverage as last verified, open claims and open charges. |
search_patients | read | no | Finds patients by the words of their name, their date of birth or a member ID on any of their checks or claims (all that are given must match), inside the list's filters, newest first. |
Eligibility#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
create_eligibility_check | submit | yes | Asks the payer about a subscriber's (or a dependent patient's) dental coverage and returns the check: the coverage status, plan, maximums, deductibles, coverage by category and the detail for the procedure codes asked about. |
get_eligibility_check | read | no | One check of the key's organization and mode, with the request it was made from and the answer or rejection. |
list_eligibility_checks | read | no | The checks of the key's organization in the key's mode, newest first, as summaries (without the request and the benefits; read one check for those). |
Claims#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
cancel_claim_correction | submit | yes | For a claim opened for a correction (resubmit of a claim the payer accepted, paid or denied) and not yet sent again (needs attention, validated or queued): the claim gets back the content, lines, attachments and frequency it had before the correction (what the payer has: edits made since are undone; an attachment that cannot be put back is named on the timeline) and the state its payments derive (paid or denied as its payment stands, else accepted_payer); a timeline entry and claim.status_updated. |
convert_claim | submit | yes | For a predetermination whose estimate came back (state returned): makes a new claim (kind claim, a draft) with the same patient, subscriber, payer, office, provider and lines, awaiting its service dates, linked both ways (converted_from, converted_to). |
create_claim | submit | yes | Makes a dental claim from JSON. |
get_claim | read | no | One claim of the key's organization and mode, with its lines, the result of its last validation, its network references, the rejection in plain words when it was rejected, and next_step. |
get_claim_timeline | read | no | What happened to the claim, oldest first, in plain words: created, validated, queued, submitted (with the file and the claim's place in it), the 997 and 277 statuses, rejections, corrections and voids. |
get_claim_x12 | read | no | The claim as it was sent, as text: the envelope of the file it travelled in, the levels above the claim and the claim's own segments, one per line. |
list_claims | read | no | The claims of the key's organization in the key's mode, newest first, as summaries (read one claim for its lines, findings and network references). |
reconcile_claim | submit | yes | Says you posted the claim's payment in your system: a paid or denied claim becomes reconciled (a reconciled one is returned as it is). |
resubmit_claim | submit | yes | For a claim that was rejected or needs attention, or that the payer accepted, paid or denied (to correct it): applies the corrections in the body (only the fields to change, as for an update; an empty object for none), validates the claim and queues it, under the same claim ID. |
submit_claim | submit | yes | Validates a draft or a claim that needs attention and queues it when it has no errors (a claim with errors comes back as needs_attention with its findings). |
update_claim | submit | yes | Changes the fields sent and keeps the rest, while the claim is a draft, needs attention, or was rejected (correct a rejected claim, then resubmit it). |
validate_claim | submit | yes | Checks a claim body the way creating it would and stores nothing: every finding together, errors (which keep a claim from being sent) and warnings. |
void_claim | submit | yes | A claim the payer has not seen (a draft, validated, needing attention, queued, or rejected without a payer claim number) becomes voided at once. |
Attachments#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
close_attachment | submit | yes | Sends the attachment to the attachment network and closes it: it needs a document or a narrative, its office is registered with the network first when it is not, and its payer must take attachments. |
create_attachment | submit | yes | Makes an open attachment: for a claim (its office, payer and patient are taken from it), for a payer request (kind solicited: its claim and payer, and the payer's reference number), or on its own (an office and a payer that takes attachments). |
delete_attachment_document | submit | no | Removes a document and its image while the attachment is open and not yet being sent (closing sends it). |
discard_attachment | submit | no | Deletes an open attachment you no longer want (the wrong office or patient, or a payer that stopped taking attachments), with its documents and their images. |
get_attachment | read | no | One attachment of the key's organization and mode, with its documents, and once closed its number and what a claim file carries for it. |
get_attachment_document_url | read | no | A link that shows the document's image for 60 seconds: ask for a new one each time it is shown. |
list_attachment_document_types | read | no | The document types an attachment's documents can be. |
list_attachments | read | no | The attachments of the key's organization in the key's mode, newest first, each with its documents. |
update_attachment | submit | yes | Changes an open attachment not yet being sent: its narrative, and, for one made for no claim or for a claim that was voided, its patient, subscriber and service_dates (the network's record needs them; send the fields to change). |
upload_attachment_document | submit | yes | Adds an image to an open attachment, as multipart/form-data: the JPEG or PNG in the field "file", and its document type (and, for an X-ray or a photo, its date and orientation). |
Payer requests#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
answer_payer_request | submit | yes | Answers with a solicited attachment that carries the payer's reference number: the one named, else the request's open one (make it with POST /attachments, kind solicited, and upload its documents first), else a new one with the narrative given (for a request about no claim, with office_id and the patient, subscriber and service_dates, which the network's record needs). |
create_payer_request | submit | yes | Records a request that came by letter or phone, about a claim (its payer) or with a payer of its own. |
get_payer_request | read | no | One payer request of the key's organization and mode. |
list_payer_requests | read | no | The payer requests of the key's organization in the key's mode, newest first: what payers asked for about claims they have. |
ERAs#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_era | read | no | One remittance as JSON: the payment (method, trace number, date, total), whether it adds up, and every claim payment with its lines, each matched to its claim or shown unmatched (with the patient's name as the payer wrote it, to match it by hand). |
get_era_x12 | read | no | The remittance as the payer sent it, as text: your organization's remittance only, as an interchange of its own (a file shared with others is never shown), one segment per line. |
list_eras | read | no | The remittances (835) the payers sent to your organization in the key's mode, newest first, as summaries (read one for its claims and lines). |
match_era_claim | submit | yes | Matches an unmatched payment of the ERA to one of your claims (sent, in the key's mode, and able to take a payment now: not while it is being corrected, rejected or voided) by hand, and applies it: the claim's figures become the sum of its payments, and it is paid or denied. |
post_era | submit | yes | Says you posted the ERA in your system: every claim it paid or denied (and that no later remittance changed) becomes reconciled, and the ERA posted. |
Events#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_event | read | no | One event of the key's organization and mode. |
list_events | read | no | The events of the key's organization in the key's mode, newest first. |
replay_event | submit | yes | Sends the event again: one new delivery is queued for each endpoint that is enabled and subscribed to its type now (none when there is no such endpoint). |
Webhook endpoints#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
create_webhook_endpoint | submit | yes | Registers a URL to send events to. |
delete_webhook_endpoint | submit | no | Removes the endpoint and its deliveries: nothing more is sent to it. |
disable_webhook_endpoint | submit | yes | Stops sending events to the endpoint. |
enable_webhook_endpoint | submit | yes | Starts sending events to the endpoint again. |
get_webhook_endpoint | read | no | One webhook endpoint of the key's organization and mode, without its signing secret. |
list_webhook_endpoints | read | no | The webhook endpoints of the key's organization in the key's mode, newest first. |
rotate_webhook_secret | submit | yes | Replaces the endpoint's signing secret: events are signed with the new secret from now on, and the old one stops working at once. |
Reports#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_report_summary | read | no | Where money and time went in a period, for the key's organization in the key's mode: billed, paid, first-pass acceptance, median days to pay and the claims unpaid over 30 days; days to payment by payer, rejections by reason, acceptance by office and adjustments by reason. |
Usage and statements#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
get_statement | read | no | One statement with its lines: the products with their counts, reasons, rates and amounts, the fees, the minimum and the amount due, as they were when the month was closed. |
get_usage | read | no | The usage of the key's organization in a billing month, in the key's mode: for each product the billable transactions and those not billed (with the reason for each kind), the rate and the amount; for eligibility each tier's checks and price; the fees, the monthly minimum, and the amount due (the greater of the fees and the minimum, plus adjustments). |
list_statements | read | no | The monthly statements of the key's organization, newest first. |
list_usage_units | read | no | The usage records of a billing month in the key's mode, oldest first: one for each check, claim, attachment or ERA, with whether it is billable and why, and for a billable check of a billed month the price of its place in the month's tiers. |
Sandbox#
| Tool | Needs | idempotency_key | What it does |
|---|---|---|---|
list_sandbox_scenarios | read | no | The scripted payer scenarios a test key can trigger. |
Arguments and answers#
- A tool takes the endpoint's path parameters, query parameters and body fields as one object of arguments, with the same names and descriptions as the API reference. An argument the tool does not know is refused with
INVALID_REQUESTand the issue codeunknown_field. - A tool answers with the object the API returns, as JSON text and as structured content; a list has
dataandnext_cursor, and you page withcursorandlimitas in the API. A file the API returns as text (a claim's 837D, an ERA's 835) comes back as text. - When the API would answer with an error, the tool answers with
isErrorset and the API's error body (error,message,errors), so the agent can read it and fix the request. A rejected check carries the check, as it does in the API. - A tool whose
idempotency_keycolumn says yes (a write the API makes with a POST or a PATCH) needs that argument; the others take none (a read, a delete, a search sent as a POST). It plays the part of theIdempotency-Keyheader: a call repeated with the same key and the same arguments gets the first answer and never runs twice, and the same key with other arguments is refused withIDEMPOTENCY_KEY_REUSED. To resend a rejected check with fixes, send it again withparent_idset to the rejected check and a newidempotency_key. upload_attachment_documenttakes the image ascontent_base64(the JPEG or PNG in base64) with itsmedia_type, instead of a multipart form. The same limits and checks apply: an image up to 15 MB, refused by its size before it is decoded.- An eligibility check through MCP never skips a saved answer: an identical check within 60 minutes is answered from the saved one. The API's
Cache-Control: no-cacheheader has no tool argument; use the API to ask the payer again.
How it works#
- Every request is a
POSTof one JSON-RPC message tohttps://sandbox.myclaimhouse.com/api/mcp. It answers with JSON in the same response: there is no session and no event stream, andGETandDELETEanswer405. - The server speaks these versions of the MCP specification:
2025-11-25,2025-06-18,2025-03-26,2024-11-05. It answersinitializewith the version the client asks for when it speaks it, and otherwise with the newest. - The key must have
readpermission for any request (so any key can list the tools), and each tool needs the permission its table says. A key without it getsPERMISSION_DENIED, and nothing runs. - The client must accept
application/json(one that accepts onlytext/event-streamgets406). A message may nest at most 32 levels deep. - A request from a web page whose
Originis not this site's own is refused with403. MCP clients that are not browsers send noOriginand are not affected. - Requests are logged like API requests, on the Developers page of the dashboard, under the path
/api/mcp#<tool>. The log never holds the arguments. - The limits of the API apply: a request body up to 1 MB (a key with
submitmay send one as large as an upload in base64), and 45 seconds to answer.
You can try it with curl: this lists the tools.
curl "https://sandbox.myclaimhouse.com/api/mcp" \
-H "Authorization: Bearer $CLAIMHOUSE_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Try asking#
Find a payer called Delta, then check coverage for Sam Sample, born 1990-01-01, member ID CH-ACTIVE-FULL, at my test office for a D2740 crown. Tell me the remaining annual maximum and what the plan pays for the crown. Then try CH-NOT-FOUND and explain what to change.
Send a claim for that crown with my test office and its first provider, attach a bitewing X-ray, and tell me when the payer has answered and what it paid.
Give the agent made-up people only.