Developers
Connect your AI agent to ClaimCompass
Give Claude, ChatGPT, Cursor or your own code access to your firm's claims, notes, documents, tasks, contacts and leads. It works through an MCP server, which AI apps speak natively, and a plain REST API for scripts.
- • MCP server:
https://www.claimcompass.io/api/mcp(Streamable HTTP) - • REST API:
https://www.claimcompass.io/api/v1(JSON) - • Every connection acts as a bot: its own account in your firm, read-only until an owner allows more, $9/month while active. Everything it does is logged under its name.
Quickstart
- 1. Claude or ChatGPT? Add a custom connector with the URL below. You'll sign in to ClaimCompass as a firm owner, pick or create a bot, and approve. No key needed.
https://www.claimcompass.io/api/mcp
- 2. Anything else? As a firm owner, open Settings → Bots, add a bot and copy its key (it starts with
ccb_and is shown once). The page shows the setup for your app with the key filled in, and turns green when the first request arrives. - 3. Try it. Ask your agent “Which claims changed this week?” or call
whoami.
Connect your app
Replace ccb_YOUR_BOT_KEY with your bot's key. Apps marked “no key needed” sign in with OAuth instead. Menus in other companies' apps change from time to time; if a step doesn't match, look for “custom connector” or “MCP server” in that app's settings.
Claudeno key needed
claude.ai, the Claude desktop app and Claude mobile. No key needed.
- 1. In Claude, open Settings → Connectors and choose “Add custom connector”.
- 2. Name it Claim Compass and paste this URL:
https://www.claimcompass.io/api/mcp
- 3. Click Connect. Sign in to Claim Compass as a firm owner, pick the bot Claude should act as (or create one), and approve.
- 4. In a chat, turn the connector on from the tools menu and ask something like “What claims changed this week?”
- 5. On a Team or Enterprise plan, an organization owner adds the connector once under Organization settings → Connectors; each person then connects it.
ChatGPTno key needed
Custom connector in developer mode (Plus, Pro, Business). No key needed.
- 1. In ChatGPT, open Settings → Apps & Connectors → Advanced settings and turn on Developer mode.
- 2. Back in Apps & Connectors, choose Create. Name it Claim Compass, paste this MCP server URL and set Authentication to OAuth:
https://www.claimcompass.io/api/mcp
- 3. Sign in to Claim Compass as a firm owner when asked, pick the bot, and approve.
- 4. In a new chat, choose Developer mode from the + menu and enable Claim Compass.
Claude Code
Anthropic's coding agent in the terminal.
- 1. Add the server with your bot key:
claude mcp add --transport http claimcompass https://www.claimcompass.io/api/mcp \ --header "Authorization: Bearer ccb_YOUR_BOT_KEY"
- 2. Or add it without a key, then run /mcp inside Claude Code and choose Authenticate to sign in with OAuth:
claude mcp add --transport http claimcompass https://www.claimcompass.io/api/mcp
- 3. Check it: run /mcp in Claude Code; claimcompass should show as connected.
Cursor
Add to ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project).
- 1. Add this server entry. Leave out "headers" to sign in with OAuth instead.
{ "mcpServers": { "claimcompass": { "url": "https://www.claimcompass.io/api/mcp", "headers": { "Authorization": "Bearer ccb_YOUR_BOT_KEY" } } } } - 2. Open Cursor Settings → MCP; claimcompass should show a green dot and its tools.
VS Code
GitHub Copilot agent mode. VS Code asks for the key once and stores it securely.
- 1. Create .vscode/mcp.json in your workspace (or run “MCP: Open User Configuration”) with:
{ "servers": { "claimcompass": { "type": "http", "url": "https://www.claimcompass.io/api/mcp", "headers": { "Authorization": "Bearer ${input:claimcompass-key}" } } }, "inputs": [ { "type": "promptString", "id": "claimcompass-key", "description": "Claim Compass bot key", "password": true } ] } - 2. Click Start above the server entry and paste your key when asked. Leave out "headers" and "inputs" to sign in with OAuth instead.
- 3. In Copilot Chat, switch to Agent mode; the Claim Compass tools appear in the tools list.
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json.
- 1. Add this server entry, then refresh the MCP servers list in Cascade:
{ "mcpServers": { "claimcompass": { "serverUrl": "https://www.claimcompass.io/api/mcp", "headers": { "Authorization": "Bearer ccb_YOUR_BOT_KEY" } } } }
Codex CLI
OpenAI's coding agent. The key is read from an environment variable.
- 1. Add to ~/.codex/config.toml:
[mcp_servers.claimcompass] url = "https://www.claimcompass.io/api/mcp" bearer_token_env_var = "CLAIMCOMPASS_KEY"
- 2. Set the key in the shell you run Codex from:
export CLAIMCOMPASS_KEY=ccb_YOUR_BOT_KEY
Gemini CLI
Add to ~/.gemini/settings.json.
- 1. Add this server entry, then run /mcp in Gemini CLI to check it:
{ "mcpServers": { "claimcompass": { "httpUrl": "https://www.claimcompass.io/api/mcp", "headers": { "Authorization": "Bearer ccb_YOUR_BOT_KEY" } } } }
Your own code
Any MCP client library, or plain HTTP to the REST API.
- 1. Test the key from a terminal. A working key answers with the bot's name and firm:
curl -s https://www.claimcompass.io/api/mcp \ -H "Authorization: Bearer ccb_YOUR_BOT_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"whoami","arguments":{}}}' - 2. Python, with the official MCP SDK (pip install mcp):
import asyncio from mcp import ClientSession from mcp.client.streamable_http import streamablehttp_client async def main(): headers = {"Authorization": "Bearer ccb_YOUR_BOT_KEY"} async with streamablehttp_client("https://www.claimcompass.io/api/mcp", headers=headers) as (read, write, _): async with ClientSession(read, write) as session: await session.initialize() result = await session.call_tool("search_claims", {"limit": 5}) print(result.structuredContent) asyncio.run(main()) - 3. TypeScript, with the official MCP SDK (npm i @modelcontextprotocol/sdk):
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; const transport = new StreamableHTTPClientTransport(new URL("https://www.claimcompass.io/api/mcp"), { requestInit: { headers: { Authorization: "Bearer ccb_YOUR_BOT_KEY" } }, }); const client = new Client({ name: "my-bot", version: "1.0.0" }); await client.connect(transport); console.log(await client.callTool({ name: "whoami", arguments: {} })); - 4. Or skip MCP and call the REST API:
curl -s "https://www.claimcompass.io/api/v1/claims?limit=5" -H "Authorization: Bearer ccb_YOUR_BOT_KEY"
Authentication
Bot keys
Send the key on every request as Authorization: Bearer ccb_…. Keys don't expire. Replace one any time from Settings → Bots (the old key stops at once), and disable the bot to cut it off completely.
OAuth 2.1
For apps that only take a URL. An unauthenticated request to the MCP server gets a 401 whose WWW-Authenticate header points to the protected-resource metadata, and standard MCP clients take it from there:
- • Resource metadata:
/.well-known/oauth-protected-resource - • Server metadata:
/.well-known/oauth-authorization-server - • Dynamic client registration (
/oauth/register), authorization code with PKCE S256 only, refresh tokens that rotate on each use, and revocation at/oauth/revoke. - • Access tokens last 60 minutes; refresh tokens 60 days.
On the consent screen a firm owner picks which bot the app acts as. The app then has exactly that bot's access, and shows under the bot in Settings → Bots, where it can be disconnected. Replacing the bot's key also disconnects its apps.
Permissions and approvals
- • Per-area access: an owner sets each bot to Off, Read, or Read & write for claims, contacts, leads, tasks, notes, documents, email and carriers, in Settings → Bots. Presets are Read only (the default), Full access and Custom.
- • A bot isn't shown tools outside its areas, and calling one is refused with a message naming the area (REST:
403forbidden_area). Callwhoami(orGET /api/v1/me) to see what the bot may do. - • Read & write lets a bot create and update records in that area: claims, notes, tasks, contacts and leads, upload documents, assign claims, move a claim to a stage (closing needs a reason, and settled claims are closed by a person), add key dates, schedule inspections and mark dates done. Bots can read a claim's financials but can't record payments. The same checks and audit trail apply as for a person.
- • Needs approval: sending email from a claim and deleting a document are never immediate. They're filed in Approvals for a person to accept or decline; poll
get_approval_requestto see what happened. - • If the firm's subscription lapses, changes stop (
402) and reads may follow.
MCP tools
Protocol versions 2025-11-25 back to 2024-11-05. Tools return JSON as text and as structuredContent; a failed call comes back with isError: true and a message the model can act on.
whoamiReadThis bot's name, what it may do in each area (claims, contacts, leads, tasks, notes, documents, email, carriers), which teams' claims it is limited to (if any) and the firm it belongs to. Call it first.
search_claimsReadList the firm's claims, most recently changed first. Filter by a search term (claim or carrier number, policyholder name, address), by status, or by last change.
| query | string | Claim number, carrier claim number, name or address. |
| status | string[] | Only claims in these statuses. |
| updated_since | string (ISO 8601) | ISO 8601 timestamp. |
| limit | integer | Page size, default 25. |
| cursor | string | next_cursor from the previous page. |
get_claimReadOne claim: status, phase, loss, policyholder, property, policy, carrier and assignee.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
list_claim_notesReadNotes on a claim, newest first, with who wrote each one.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| limit | integer | Page size, default 25. |
| cursor | string | next_cursor from the previous page. |
list_claim_documentsReadDocuments filed on a claim, newest first. Use get_document_download_url to read one.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| limit | integer | Page size, default 25. |
| cursor | string | next_cursor from the previous page. |
get_document_download_urlReadA signed link to download one document, valid for 15 minutes.
| document_id* | string | Document id from list_claim_documents. |
list_tasksReadThe firm's tasks, most recently changed first, optionally for one claim or status.
| claim | string | Claim id or claim number, e.g. CC-202610-0042. |
| status | string[] | Only tasks in these statuses. |
| limit | integer | Page size, default 25. |
| cursor | string | next_cursor from the previous page. |
get_taskReadOne task: title, status, due date, assignee and the claim it belongs to.
| task_id* | string | Task id from list_tasks. |
search_carriersReadInsurance carriers matching a name, from the carrier directory and the carriers this firm has used. Florida-market entries come first; when several match, prefer the one with florida: true. Results carry the claims phone, email, fax and mailing address when known, the firm's own (saved with save_carrier_contact) ahead of the directory's. Pass the result's name as carrier_name on create_claim or update_claim.
| query | string | Carrier name as written, e.g. Edison Insurance Company. |
| limit | integer | Default 10. |
search_contactsReadThe firm's contacts (policyholders and others), by name, email or phone.
| query | string | |
| limit | integer | Page size, default 25. |
| cursor | string | next_cursor from the previous page. |
get_contactReadOne contact, with the claims they are a party to and their role on each.
| contact_id* | string |
list_leadsReadThe firm's leads (prospective claims), most recently changed first.
| status | string[] | Only leads in these statuses. |
| limit | integer | Page size, default 25. |
| cursor | string | next_cursor from the previous page. |
get_leadReadOne lead with its contact details, loss and follow-up date.
| lead_id* | string |
list_approval_requestsReadEmails and deletions this bot asked for, newest first, with whether a person approved, rejected or is still deciding.
| status | "pending" | "approved" | "rejected" | "failed" | "cancelled"[] | |
| limit | integer | Page size, default 25. |
| cursor | string | next_cursor from the previous page. |
get_approval_requestReadOne request this bot filed, and what happened to it.
| request_id* | string |
list_team_membersReadThe firm's active members (user_id, name, email, role and teams) and its teams. Use it to find the user_id for an assignee on create_claim, create_task, assign_claim or schedule_inspection. Never guess a user id.
get_claim_financialsReadWhat the claim's Financials tab shows: PA and carrier estimates and the gap, payments received (settlement, paid before and after the PA contract, depreciation, client net), the PA fee (percent, earned, invoiced, collected, outstanding), costs and margin, and the checks recorded with how each was split. Amounts are US dollars as numbers. Read only: to record one, use request_payment_record.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
list_claim_deadlinesReadA claim's deadlines (statutory and carrier deadlines the app tracks, with status suggested, confirmed, met, missed and so on) and its key dates (inspections, recorded statements, mediation and other scheduled events), soonest first. Use the ids with mark_date_done.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
list_upcoming_datesReadOpen deadlines and key dates due in the next N days (default 7) across all of the firm's open claims, each with its claim. Good for a daily or weekly review.
| days | integer | Look ahead this many days from now. Default 7. |
list_claim_inspectionsReadA claim's inspections, newest first: type, status, when scheduled or completed, the carrier's adjuster, who attends, and what was observed.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
assign_claimWrite accessAssigns or reassigns a claim's adjuster and/or team. Get the ids from list_team_members; the person must be an active member of this firm. Send assigned_to_user_id: null to leave it unassigned. Returns the claim.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| assigned_to_user_id | string | null | The adjuster's user id from list_team_members. null leaves the claim unassigned. |
| assigned_to_team_id | string | null | A team id from list_team_members. null clears the team. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
change_claim_statusWrite accessMoves a claim to a stage: intake, documents, carrier_contacted, inspection, estimate, negotiation, settlement, closed or canceled. The app's rules apply: a stage's checklist and the PA's sign-offs must be done first, and the error says what is missing. Closing or canceling needs close_reason (denied, withdrawn, duplicate or other, with a note for other). A claim that settled is closed by a person from the Closeout tab, not a bot. Returns the claim.
| claim* | string | Claim id or claim number. |
| status* | "intake" | "documents" | "carrier_contacted" | "inspection" | "estimate" | "negotiation" | "settlement" | "closed" | "canceled" | |
| note | string | Why. Required when close_reason is other. Up to 2000 characters. |
| close_reason | "denied" | "withdrawn" | "duplicate" | "other" | Required for closed or canceled: denied, withdrawn, duplicate or other. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
add_key_dateWrite accessAdds a dated event to a claim's calendar: a reinspection, recorded statement, mediation, appraisal, inspection or custom date, with a title and time. Statutory deadlines are created by the app itself; use this for dates a person tells you about. Returns the key date.
| claim* | string | Claim id or claim number. |
| title* | string | Up to 300 characters. |
| scheduled_at* | string (ISO 8601) | ISO 8601 timestamp. |
| kind | "reinspection" | "recorded_statement" | "mediation" | "appraisal" | "inspection" | "custom" | Default: custom. |
| notes | string | Up to 5000 characters. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
add_deadlineWrite accessAdds a manual deadline to a claim, the way a person does under Deadlines: a title and a due time, tracked as confirmed and marked as added by this bot. For dates a person tells you about or that a carrier letter states. Statutory and carrier deadlines the app seeds itself are not added here, and a bot can't edit or remove deadlines (nor can the app's own screens; use mark_date_done to close one). Returns the deadline.
| claim* | string | Claim id or claim number. |
| title* | string | Up to 300 characters. |
| due_at* | string (ISO 8601) | ISO 8601 timestamp. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
mark_date_doneWrite accessMarks one of a claim's deadlines as met (send deadline_id) or one of its key dates as completed (send key_date_id), from list_claim_deadlines. Send exactly one of the two.
| claim* | string | Claim id or claim number. |
| deadline_id | string | |
| key_date_id | string | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
schedule_inspectionWrite accessSchedules an inspection on a claim: type (field_adjuster, pa_inspection, carrier_inspection, joint_inspection, contractor_inspection, engineer, roofer, plumber, hygienist, virtual or reinspection), optional time, the carrier's adjuster, the member who attends and what to inspect. Returns the inspection.
| claim* | string | Claim id or claim number. |
| inspection_type* | "field_adjuster" | "pa_inspection" | "carrier_inspection" | "joint_inspection" | "contractor_inspection" | "engineer" | "roofer" | "plumber" | "hygienist" | "virtual" | "reinspection" | |
| scheduled_at | string (ISO 8601) | ISO 8601 timestamp. Leave out if not set yet. |
| carrier_adjuster_name | string | The carrier's field adjuster, if known. Up to 200 characters. |
| pa_assigned_user_id | string | Member who attends, from list_team_members. |
| areas_to_inspect | string[] | |
| documents_to_have_ready | string[] | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
create_claimWrite accessOpens a new claim and fills in whatever you send: policyholder (an existing contact or a name, email and phone), loss address and date, policy number, carrier, carrier claim number, PA fee %, Emergency / Non-Emergency and contract date. It starts at intake, unassigned unless you name a member. Check search_claims first so you don't open a duplicate, and send an idempotency_key so a retry doesn't open it twice.
| loss_type | string | Wind, hail, water, fire and so on. Up to 100 characters. |
| description | string | Up to 5000 characters. |
| assigned_to_user_id | string | A team member's user id. Default: unassigned. |
| assigned_to_team_id | string | A team id from list_team_members. A bot limited to some teams opens claims on one of them: with a single team this is optional, with several it is required. |
| policyholder_contact_id | string | Link an existing contact (from search_contacts or create_contact) as the policyholder. If the claim already has a policyholder, the name, email and phone fields update that contact instead. |
| policyholder_first_name | string | Up to 100 characters. |
| policyholder_middle_name | string | Middle name or initial, if given. Up to 100 characters. |
| policyholder_last_name | string | Up to 100 characters. |
| policyholder_email | string (email) | Up to 320 characters. |
| policyholder_phone | string | Up to 40 characters. |
| loss_address_line1 | string | Street address of the damaged property. Up to 200 characters. |
| loss_address_line2 | string | Up to 200 characters. |
| loss_city | string | Up to 100 characters. |
| loss_state | string | Two-letter state, e.g. FL. Up to 50 characters. |
| loss_postal_code | string | Up to 20 characters. |
| date_of_loss | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| policy_number | string | Up to 100 characters. |
| carrier_name | string | The insurance carrier. Use the exact name search_carriers returns. Up to 200 characters. |
| carrier_claim_number | string | The carrier's own claim number. Up to 100 characters. |
| policy_effective_date | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| policy_expiration_date | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| deductible | string | As written on the policy, e.g. 2% or $2,500. Up to 50 characters. |
| policy_limit | string | Dwelling (Coverage A) limit. Up to 50 characters. |
| pa_fee_percent | number | null | The PA fee from the representation contract, as a percent (10 for 10%, 12.5 for 12.5%). Fee earned and PA fee invoices are figured from it. null clears it. |
| contract_emergency | boolean | null | The contract's Emergency / Non-Emergency box: true for Emergency, false for Non-Emergency, null to clear. Leave it out when the copy doesn't show which box is checked. |
| contract_signed_at | string | string (ISO 8601) | When the representation contract was signed. Marks the contract signed, which closes the intake task and starts reading the claim's documents into the file. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
update_claimWrite accessUpdates a claim: narrative (description, reported facts), policyholder, loss address and date, policy number, carrier, carrier claim number, PA fee %, Emergency / Non-Emergency, contract date. Only the fields you send change.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| changes* | object | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
add_claim_noteWrite accessAdds an internal note to a claim, signed with this bot's name.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| body* | string | Up to 20000 characters. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
create_taskWrite accessCreates a task on a claim, optionally due on a date and assigned to a member. Check list_tasks first so you don't create a duplicate, and send an idempotency_key so a retry doesn't create it twice.
| claim* | string | Claim id or claim number. |
| title* | string | Up to 300 characters. |
| description | string | Up to 5000 characters. |
| due_at | string (ISO 8601) | ISO 8601 timestamp. |
| assignee_user_id | string | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
update_task_statusWrite accessMoves a task to open, in_progress, completed or cancelled.
| task_id* | string | |
| status* | "open" | "in_progress" | "completed" | "cancelled" | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
create_contactWrite accessAdds a person to the firm's contacts. Check search_contacts first so you don't add a duplicate, and send an idempotency_key so a retry doesn't add them twice.
| first_name | string | Up to 100 characters. |
| middle_name | string | Middle name or initial, if given. Up to 100 characters. |
| last_name | string | Up to 100 characters. |
| string (email) | Up to 320 characters. | |
| phone | string | Up to 40 characters. |
| address_line1 | string | Up to 200 characters. |
| address_line2 | string | Apartment, suite or unit. Up to 200 characters. |
| city | string | Up to 100 characters. |
| state | string | Up to 50 characters. |
| postal_code | string | Up to 20 characters. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
update_contactWrite accessUpdates a contact. Only the fields you send change.
| contact_id* | string | |
| changes* | object | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
create_leadWrite accessAdds a lead (a prospective claim), unassigned unless you name a member. Check list_leads first so you don't add a duplicate, and send an idempotency_key so a retry doesn't add it twice.
| first_name | string | Up to 100 characters. |
| last_name | string | Up to 100 characters. |
| string (email) | Up to 320 characters. | |
| phone | string | Up to 40 characters. |
| source | string | Up to 100 characters. |
| preferred_contact_method | string | Up to 40 characters. |
| property_type | string | Up to 100 characters. |
| loss_type | string | Up to 100 characters. |
| estimated_loss_date | string (ISO 8601) | |
| state_of_loss | string | Up to 50 characters. |
| address_line1 | string | Up to 200 characters. |
| city | string | Up to 100 characters. |
| postal_code | string | Up to 20 characters. |
| damage_description | string | Up to 10000 characters. |
| notes | string | Up to 10000 characters. |
| follow_up_at | string (ISO 8601) | |
| assigned_to_user_id | string | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
update_leadWrite accessUpdates a lead. Only the fields you send change.
| lead_id* | string | |
| changes* | object | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
save_carrier_contactWrite accessSaves this firm's own claims phone, email, fax, mailing address or notes for an insurance carrier. The firm's claims use them ahead of the built-in carrier directory, which is shared by every firm and can't be edited. Only the fields you send change; null clears one. Don't save one person's direct line or email as the claims contact.
| carrier_name* | string | The carrier, as search_carriers names it. Up to 200 characters. |
| claims_phone | string | null | |
| claims_email | string (email) | null | |
| claims_fax | string | null | |
| claims_mailing_address | string | null | One line. |
| notes | string | null | Anything the firm's team should know, e.g. which desk handles hurricane claims. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
upload_documentWrite accessFiles a document (up to 3 MB, base64) on a claim.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| file_name* | string | Up to 255 characters. |
| mime_type* | string | e.g. application/pdf, image/jpeg. Up to 150 characters. |
| document_type | "policy" | "letter_of_representation" | "carrier_letter" | "denial_letter" | "payment_letter" | "check" | "estimate" | "photo" | "invoice" | "report" | "proof_of_loss" | "appraisal_letter" | "attorney_letter" | "mold_report" | "engineering_report" | "mitigation_invoice" | "plumbing_invoice" | "settlement_offer" | "appraisal_demand" | "representation_agreement" | "w9_form" | "other" | Default: other. |
| content_base64* | string | The file, base64-encoded. Up to 3 MB. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
request_claim_emailNeeds approvalDrafts an email from a claim and asks a person on the team to approve sending it. Nothing is sent until they do. Returns the approval request.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| to* | string (email) | Up to 320 characters. |
| subject* | string | Up to 300 characters. |
| body* | string | Plain text. Blank lines split paragraphs. Up to 50000 characters. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
request_document_deletionNeeds approvalAsks a person on the team to approve deleting a document. Nothing is deleted until they do. Returns the approval request.
| document_id* | string | |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
request_payment_recordNeeds approvalAsks a person on the team to approve recording a check on a claim: the total, who it pays (allocations that add up to the total) and the check number and date. Nothing is recorded until they approve; then it goes through the same Financials checks as when a person records it. Returns the approval request. Read the result with get_claim_financials.
| claim* | string | Claim id or claim number, e.g. CC-202610-0042. |
| total_amount* | string | The check total in dollars, e.g. "12500.00". |
| check_number | string | Printed on the check. Recorded once per claim. Up to 100 characters. |
| check_date | string | string (ISO 8601) | The date on the check (YYYY-MM-DD). |
| label | string | e.g. "Dwelling ACV", "Supplement 1". Up to 200 characters. |
| before_pa_contract | boolean | True when the check was issued before the PA contract (not fee eligible). |
| endorsement_status | "pending" | "requested" | "endorsed" | "deposited" | |
| document_id | string | A document already on this claim, such as a scan of the check. |
| allocations* | object[] | Who the check pays. The amounts must add up to total_amount. |
| idempotency_key | string | Any unique string, such as a UUID. Send the same key when you retry this call and the first result is returned instead of doing it twice (kept 24 hours). Up to 255 characters. |
MCP prompts
prompts/list and prompts/get offer ready-made workflows that name the tools above. In most AI apps they show up as slash commands or a prompt picker. The instructions a firm owner writes for every bot (Settings → Bots) are put at the top of each one, and also arrive in the initialize reply, in whoami and in GET /api/v1/me as firm_instructions, marked as coming from the firm.
new_claim_from_contractNew claim from a signed contract. Open a claim from a signed representation contract: look for duplicates, create the policyholder and claim with every field, set the carrier, and file the contract.
notes(optional): Anything the person knows that the contract doesn't say.
daily_claim_reviewDaily claim review. A morning briefing: tasks due, deadlines and key dates this week, and claims that look stuck.
days(optional): How many days ahead to look. Default 7.adjuster(optional): Only this person's claims (name or email).
log_carrier_contactLog a carrier call or email. Turn a carrier call or email into a claim note, and add a task or key date for any follow-up.
claim(optional): Claim number or id, if you know it.details(optional): What was said, or paste the email.
document_intakeFile documents on a claim. File the documents the person attached on the right claim, with the right type, and note what they contain.
claim(optional): Claim number or id, if you know it.
REST API
Base URL https://www.claimcompass.io/api/v1. Bodies are JSON with Content-Type: application/json. A claim can be named by id or claim number. Creates answer 201; requests filed for approval answer 202.
GET /meReadThis bot's name, what it may do in each area (claims, contacts, leads, tasks, notes, documents, email, carriers), its firm, and firm_instructions: the instructions the firm's owner wrote for every bot (null when none).
GET /claimsReadClaims, most recently changed first.
Query
| q | string | Claim or carrier number, policyholder name or address. |
| status | string | Only these statuses. Repeat it or comma-separate. |
| updated_since | string (ISO 8601) | Only claims changed after this time. |
| limit | integer | Page size, 1–100. Default 25. |
| cursor | string | next_cursor from the previous page. |
POST /claimsWrite accessOpens a claim, with any of its policyholder, loss, policy, carrier, PA fee and Emergency fields filled in.
Body
| loss_type | string | Wind, hail, water, fire and so on. Up to 100 characters. |
| description | string | Up to 5000 characters. |
| assigned_to_user_id | string | A team member's user id. Default: unassigned. |
| assigned_to_team_id | string | A team id from list_team_members. A bot limited to some teams opens claims on one of them: with a single team this is optional, with several it is required. |
| policyholder_contact_id | string | Link an existing contact (from search_contacts or create_contact) as the policyholder. If the claim already has a policyholder, the name, email and phone fields update that contact instead. |
| policyholder_first_name | string | Up to 100 characters. |
| policyholder_middle_name | string | Middle name or initial, if given. Up to 100 characters. |
| policyholder_last_name | string | Up to 100 characters. |
| policyholder_email | string (email) | Up to 320 characters. |
| policyholder_phone | string | Up to 40 characters. |
| loss_address_line1 | string | Street address of the damaged property. Up to 200 characters. |
| loss_address_line2 | string | Up to 200 characters. |
| loss_city | string | Up to 100 characters. |
| loss_state | string | Two-letter state, e.g. FL. Up to 50 characters. |
| loss_postal_code | string | Up to 20 characters. |
| date_of_loss | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| policy_number | string | Up to 100 characters. |
| carrier_name | string | The insurance carrier. Use the exact name search_carriers returns. Up to 200 characters. |
| carrier_claim_number | string | The carrier's own claim number. Up to 100 characters. |
| policy_effective_date | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| policy_expiration_date | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| deductible | string | As written on the policy, e.g. 2% or $2,500. Up to 50 characters. |
| policy_limit | string | Dwelling (Coverage A) limit. Up to 50 characters. |
| pa_fee_percent | number | null | The PA fee from the representation contract, as a percent (10 for 10%, 12.5 for 12.5%). Fee earned and PA fee invoices are figured from it. null clears it. |
| contract_emergency | boolean | null | The contract's Emergency / Non-Emergency box: true for Emergency, false for Non-Emergency, null to clear. Leave it out when the copy doesn't show which box is checked. |
| contract_signed_at | string | string (ISO 8601) | When the representation contract was signed. Marks the contract signed, which closes the intake task and starts reading the claim's documents into the file. |
GET /carriersReadInsurance carriers matching a name, Florida-market first. Use a result's name as carrier_name.
Query
| q | string | Carrier name as written on the policy or contract. |
| limit | integer | 1–25. Default 10. |
POST /carriersWrite accessSaves the firm's own claims phone, email, fax, mailing address or notes for a carrier. They win over the shared directory on the firm's claims.
Body
| carrier_name* | string | The carrier, as search_carriers names it. Up to 200 characters. |
| claims_phone | string | null | |
| claims_email | string (email) | null | |
| claims_fax | string | null | |
| claims_mailing_address | string | null | One line. |
| notes | string | null | Anything the firm's team should know, e.g. which desk handles hurricane claims. |
GET /claims/{claim}ReadOne claim, by id or claim number (CC-…).
PATCH /claims/{claim}Write accessUpdates a claim: narrative, policyholder, loss address and date, policy, carrier, PA fee % and Emergency / Non-Emergency. Send at least one field.
Body
| loss_type | string | Up to 100 characters. |
| description | string | Up to 5000 characters. |
| client_reported_facts | string | Up to 20000 characters. |
| how_loss_happened | string | Up to 20000 characters. |
| adjuster_observations | string | Up to 20000 characters. |
| policyholder_contact_id | string | Link an existing contact (from search_contacts or create_contact) as the policyholder. If the claim already has a policyholder, the name, email and phone fields update that contact instead. |
| policyholder_first_name | string | Up to 100 characters. |
| policyholder_middle_name | string | Middle name or initial, if given. Up to 100 characters. |
| policyholder_last_name | string | Up to 100 characters. |
| policyholder_email | string (email) | Up to 320 characters. |
| policyholder_phone | string | Up to 40 characters. |
| loss_address_line1 | string | Street address of the damaged property. Up to 200 characters. |
| loss_address_line2 | string | Up to 200 characters. |
| loss_city | string | Up to 100 characters. |
| loss_state | string | Two-letter state, e.g. FL. Up to 50 characters. |
| loss_postal_code | string | Up to 20 characters. |
| date_of_loss | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| policy_number | string | Up to 100 characters. |
| carrier_name | string | The insurance carrier. Use the exact name search_carriers returns. Up to 200 characters. |
| carrier_claim_number | string | The carrier's own claim number. Up to 100 characters. |
| policy_effective_date | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| policy_expiration_date | string | string (ISO 8601) | A date (YYYY-MM-DD) or an ISO 8601 timestamp. |
| deductible | string | As written on the policy, e.g. 2% or $2,500. Up to 50 characters. |
| policy_limit | string | Dwelling (Coverage A) limit. Up to 50 characters. |
| pa_fee_percent | number | null | The PA fee from the representation contract, as a percent (10 for 10%, 12.5 for 12.5%). Fee earned and PA fee invoices are figured from it. null clears it. |
| contract_emergency | boolean | null | The contract's Emergency / Non-Emergency box: true for Emergency, false for Non-Emergency, null to clear. Leave it out when the copy doesn't show which box is checked. |
| contract_signed_at | string | string (ISO 8601) | When the representation contract was signed. Marks the contract signed, which closes the intake task and starts reading the claim's documents into the file. |
GET /team-membersReadThe firm's active members (user_id, name, email, role, teams) and its teams, to pick an assignee.
PATCH /claims/{claim}/assignmentWrite accessAssigns or reassigns the claim's adjuster and/or team.
Body
| assigned_to_user_id | string | null | The adjuster's user id from list_team_members. null leaves the claim unassigned. |
| assigned_to_team_id | string | null | A team id from list_team_members. null clears the team. |
GET /claims/{claim}/financialsReadThe claim's estimates, payments received, PA fee, costs and recorded checks. Read only; to record one, ask with request_payment_record.
GET /claims/{claim}/deadlinesReadThe claim's deadlines and key dates, soonest first.
GET /dates/upcomingReadOpen deadlines and key dates across the firm's open claims in the next days.
Query
| days | integer | Look ahead 1–90 days. Default 7. |
POST /claims/{claim}/deadlinesWrite accessAdds a manual deadline (title and due time), confirmed and marked as added by the bot. Seeded statute and carrier deadlines can't be added, edited or removed.
Body
| title* | string | Up to 300 characters. |
| due_at* | string (ISO 8601) | ISO 8601 timestamp. |
POST /claims/{claim}/key-datesWrite accessAdds a key date (reinspection, recorded statement, mediation and so on).
Body
| title* | string | Up to 300 characters. |
| scheduled_at* | string (ISO 8601) | ISO 8601 timestamp. |
| kind | "reinspection" | "recorded_statement" | "mediation" | "appraisal" | "inspection" | "custom" | Default: custom. |
| notes | string | Up to 5000 characters. |
POST /claims/{claim}/dates/doneWrite accessMarks a deadline met or a key date completed. Send one of the two ids.
Body
| deadline_id | string | |
| key_date_id | string |
GET /claims/{claim}/inspectionsReadThe claim's inspections, newest first.
POST /claims/{claim}/inspectionsWrite accessSchedules an inspection.
Body
| inspection_type* | "field_adjuster" | "pa_inspection" | "carrier_inspection" | "joint_inspection" | "contractor_inspection" | "engineer" | "roofer" | "plumber" | "hygienist" | "virtual" | "reinspection" | |
| scheduled_at | string (ISO 8601) | ISO 8601 timestamp. Leave out if not set yet. |
| carrier_adjuster_name | string | The carrier's field adjuster, if known. Up to 200 characters. |
| pa_assigned_user_id | string | Member who attends, from list_team_members. |
| areas_to_inspect | string[] | |
| documents_to_have_ready | string[] |
POST /claims/{claim}/statusWrite accessMoves the claim to a stage. The stage checklist and sign-offs apply; closing needs a close_reason. Settled claims are closed by a person.
Body
| status* | "intake" | "documents" | "carrier_contacted" | "inspection" | "estimate" | "negotiation" | "settlement" | "closed" | "canceled" | |
| note | string | Why. Required when close_reason is other. Up to 2000 characters. |
| close_reason | "denied" | "withdrawn" | "duplicate" | "other" | Required for closed or canceled: denied, withdrawn, duplicate or other. |
GET /claims/{claim}/notesReadNotes on a claim, newest first.
Query
| limit | integer | Page size, 1–100. Default 25. |
| cursor | string | next_cursor from the previous page. |
POST /claims/{claim}/notesWrite accessAdds a note to a claim.
Body
| body* | string | Up to 20000 characters. |
GET /claims/{claim}/documentsReadDocuments on a claim, newest first.
Query
| limit | integer | Page size, 1–100. Default 25. |
| cursor | string | next_cursor from the previous page. |
POST /claims/{claim}/documentsWrite accessUploads a document (base64 in JSON, up to 3 MB).
Body
| file_name* | string | Up to 255 characters. |
| mime_type* | string | e.g. application/pdf, image/jpeg. Up to 150 characters. |
| document_type | "policy" | "letter_of_representation" | "carrier_letter" | "denial_letter" | "payment_letter" | "check" | "estimate" | "photo" | "invoice" | "report" | "proof_of_loss" | "appraisal_letter" | "attorney_letter" | "mold_report" | "engineering_report" | "mitigation_invoice" | "plumbing_invoice" | "settlement_offer" | "appraisal_demand" | "representation_agreement" | "w9_form" | "other" | Default: other. |
| content_base64* | string | The file, base64-encoded. Up to 3 MB. |
POST /claims/{claim}/emailsNeeds approvalAsks a person to approve sending an email from the claim. Nothing is sent until they do.
Body
| to* | string (email) | Up to 320 characters. |
| subject* | string | Up to 300 characters. |
| body* | string | Plain text. Blank lines split paragraphs. Up to 50000 characters. |
POST /claims/{claim}/paymentsNeeds approvalAsks a person to approve recording a check on the claim (total, allocations, check number and date). Nothing is recorded until they do.
Body
| total_amount* | string | The check total in dollars, e.g. "12500.00". |
| check_number | string | Printed on the check. Recorded once per claim. Up to 100 characters. |
| check_date | string | string (ISO 8601) | The date on the check (YYYY-MM-DD). |
| label | string | e.g. "Dwelling ACV", "Supplement 1". Up to 200 characters. |
| before_pa_contract | boolean | True when the check was issued before the PA contract (not fee eligible). |
| endorsement_status | "pending" | "requested" | "endorsed" | "deposited" | |
| document_id | string | A document already on this claim, such as a scan of the check. |
| allocations* | object[] | Who the check pays. The amounts must add up to total_amount. |
GET /tasksReadTasks, most recently changed first.
Query
| claim | string | Only this claim's tasks. |
| status | string | Only these statuses. Repeat it or comma-separate. |
| limit | integer | Page size, 1–100. Default 25. |
| cursor | string | next_cursor from the previous page. |
POST /tasksWrite accessCreates a task on a claim.
Body
| claim* | string | Claim id or claim number. |
| title* | string | Up to 300 characters. |
| description | string | Up to 5000 characters. |
| due_at | string (ISO 8601) | ISO 8601 timestamp. |
| assignee_user_id | string |
GET /tasks/{task_id}ReadOne task.
PATCH /tasks/{task_id}Write accessChanges a task's status.
Body
| status* | "open" | "in_progress" | "completed" | "cancelled" |
GET /contactsReadContacts, by name, email or phone.
Query
| q | string | Name, email or phone. |
| limit | integer | Page size, 1–100. Default 25. |
| cursor | string | next_cursor from the previous page. |
POST /contactsWrite accessCreates a contact. Give it a name, email or phone.
Body
| first_name | string | Up to 100 characters. |
| middle_name | string | Middle name or initial, if given. Up to 100 characters. |
| last_name | string | Up to 100 characters. |
| string (email) | Up to 320 characters. | |
| phone | string | Up to 40 characters. |
| address_line1 | string | Up to 200 characters. |
| address_line2 | string | Apartment, suite or unit. Up to 200 characters. |
| city | string | Up to 100 characters. |
| state | string | Up to 50 characters. |
| postal_code | string | Up to 20 characters. |
GET /contacts/{contact_id}ReadOne contact, with the claims they're on.
PATCH /contacts/{contact_id}Write accessUpdates a contact. Send at least one field.
Body
| first_name | string | Up to 100 characters. |
| middle_name | string | Middle name or initial, if given. Up to 100 characters. |
| last_name | string | Up to 100 characters. |
| string (email) | Up to 320 characters. | |
| phone | string | Up to 40 characters. |
| address_line1 | string | Up to 200 characters. |
| address_line2 | string | Apartment, suite or unit. Up to 200 characters. |
| city | string | Up to 100 characters. |
| state | string | Up to 50 characters. |
| postal_code | string | Up to 20 characters. |
GET /leadsReadLeads, most recently changed first.
Query
| status | string | Only these statuses. Repeat it or comma-separate. |
| limit | integer | Page size, 1–100. Default 25. |
| cursor | string | next_cursor from the previous page. |
POST /leadsWrite accessCreates a lead. Give it a name, email or phone.
Body
| first_name | string | Up to 100 characters. |
| last_name | string | Up to 100 characters. |
| string (email) | Up to 320 characters. | |
| phone | string | Up to 40 characters. |
| source | string | Up to 100 characters. |
| preferred_contact_method | string | Up to 40 characters. |
| property_type | string | Up to 100 characters. |
| loss_type | string | Up to 100 characters. |
| estimated_loss_date | string (ISO 8601) | |
| state_of_loss | string | Up to 50 characters. |
| address_line1 | string | Up to 200 characters. |
| city | string | Up to 100 characters. |
| postal_code | string | Up to 20 characters. |
| damage_description | string | Up to 10000 characters. |
| notes | string | Up to 10000 characters. |
| follow_up_at | string (ISO 8601) | |
| assigned_to_user_id | string |
GET /leads/{lead_id}ReadOne lead.
PATCH /leads/{lead_id}Write accessUpdates a lead. Send at least one field.
Body
| first_name | string | Up to 100 characters. |
| last_name | string | Up to 100 characters. |
| string (email) | Up to 320 characters. | |
| phone | string | Up to 40 characters. |
| source | string | Up to 100 characters. |
| preferred_contact_method | string | Up to 40 characters. |
| property_type | string | Up to 100 characters. |
| loss_type | string | Up to 100 characters. |
| estimated_loss_date | string (ISO 8601) | |
| state_of_loss | string | Up to 50 characters. |
| address_line1 | string | Up to 200 characters. |
| city | string | Up to 100 characters. |
| postal_code | string | Up to 20 characters. |
| damage_description | string | Up to 10000 characters. |
| notes | string | Up to 10000 characters. |
| follow_up_at | string (ISO 8601) | |
| assigned_to_user_id | string |
GET /documents/{document_id}/downloadReadA signed download link, valid for 15 minutes.
DELETE /documents/{document_id}Needs approvalAsks a person to approve deleting a document. Nothing is deleted until they do.
GET /approval-requestsReadThis bot's approval requests, newest first.
Query
| status | string | Only these statuses. Repeat it or comma-separate. |
| limit | integer | Page size, 1–100. Default 25. |
| cursor | string | next_cursor from the previous page. |
GET /approval-requests/{request_id}ReadOne approval request and what happened to it.
Webhooks
Rather than poll, have ClaimCompass call you. A firm owner or admin adds an https URL under Settings → Webhooks and picks the events. The signing secret is shown once.
Events
claim.createdClaim created. data: A claim, as GET /claims/{id} returns it.
claim.updatedClaim updated (including status changes). data: The claim after the change, same shape. A status change is a claim.updated.
document.uploadedDocument uploaded. data: The document's details (no file or download link).
note.createdNote added. data: The note, as the claim notes list returns it.
task.createdTask created. data: The task, as GET /tasks/{id} returns it.
task.completedTask completed. data: The task, with status completed.
lead.createdLead created. data: The lead, as GET /leads/{id} returns it.
contact.createdContact created. data: The contact, as GET /contacts/{id} returns it.
email.bouncedEmail bounced or marked as spam (Resend only; not Gmail). data: The sent email: id, claim_id, to, status (bounced or complained), reason, and whether the address is now blocked for sending. Only for mail sent through Claim Compass, not Gmail.
Request
A POST with a JSON body in this shape. data uses the same field names as the REST API.
{
"id": "evt_3f0c9a52-6d1e-4c1b-9a77-2f8f5e0d1c11",
"type": "claim.updated",
"created_at": "2026-10-16T14:03:22.114Z",
"organization_id": "0b8c…",
"data": { "id": "…", "claim_number": "…", "status": "…", "…": "…" }
}| ClaimCompass-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256 of "t.body"> |
| ClaimCompass-Event | The event type, for example claim.created. |
| ClaimCompass-Delivery | A unique id for this delivery. A resend gets a new one. |
Verify the signature
Compute the HMAC-SHA256 of <t>.<raw body> with your signing secret and compare it to v1. Reject a timestamp more than a few minutes old.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody must be the exact bytes received, before any JSON parsing.
export function verify(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const given = String(parts.v1 ?? "");
return (
given.length === expected.length &&
timingSafeEqual(Buffer.from(given), Buffer.from(expected))
);
}Delivery rules
- Answer with any 2xx within 10 seconds. Redirects are not followed and count as a failure.
- A failed delivery is retried with growing delays over several hours (7 attempts in all). The same event can arrive more than once, so dedupe on the event id.
- A webhook turns itself off after 50 failed deliveries in a row, or after 3 days with every delivery failing. The reason shows in Settings → Webhooks, where you can turn it back on.
- URLs must be https, on port 443 or 1024 and up, and resolve to a public address. Private, loopback, link-local and cloud-metadata addresses are refused when you save and on every send.
- Events carry the same fields the API returns, so a webhook never reveals more than your bots can already read. Events for a locked or lapsed firm are not sent.
- Up to 10 webhooks per firm. Delivery history (every attempt) is kept for 30 days.
Retries and duplicates
Send an idempotency key with every create or update so a retry can't make a second record: an Idempotency-Key header on REST POST and PATCH, or an idempotency_key argument on MCP tools that change something. Use any unique string, such as a UUID, and send the same one when you retry.
- • Same key, same request, within 24 hours: you get the first response back and nothing is done twice (REST adds
Idempotent-Replayed: true). - • Same key, different request:
409idempotency_key_reused. - • Two requests at once with one key: the second waits a few seconds, then gets
409 idempotency_in_progress; retry it. - • A request that fails doesn't keep its key, so retrying it works.
- • Keys belong to the bot. Search before you create, too.
Pagination, limits, errors
Lists come back as { data, next_cursor }, newest-changed first. Pass next_cursor back as cursor until it's null. Each bot may make 120 requests a minute across MCP and REST together.
REST errors look like { "error": { "code", "message" } }:
| 400 | bad_request | A field is missing or invalid; the message says which. |
| 401 | unauthorized | No key or token, or it was revoked or the bot is disabled. |
| 402 | subscription_inactive / read_only | The firm's subscription has lapsed: reads may still work, changes don't. |
| 403 | forbidden_area | The bot's access to that area (claims, contacts…) doesn't allow this; an owner can change it in Settings → Bots. The message names the area. |
| 403 | forbidden | The action isn't allowed for a bot or needs a person. |
| 409 | idempotency_key_reused / idempotency_in_progress | The Idempotency-Key was already used for a different request, or the first request with it is still running: retry in a few seconds. |
| 404 | not_found | No such record in this firm. |
| 429 | rate_limited | Over 120 requests a minute; wait for Retry-After seconds. |
| 500 | internal_error | Our fault. Retry later; we're alerted. |
Stuck? Email support@claimcompass.io with the bot's name and roughly when the request failed.