# Build with AI
URL: https://backworkhealth.com/docs/build-with-ai

Connect an AI agent to Backwork through MCP or the REST API, and give it the docs as Markdown.

This page lists what an AI agent needs to use Backwork: the MCP server, how it authenticates, where the docs are as Markdown, and which response fields to act on.

## Give your agent the docs [#give-your-agent-the-docs]

| URL                                                                                                | What it contains                                                                                  |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [`https://backworkhealth.com/llms.txt`](https://backworkhealth.com/llms.txt)                       | An index of the docs and every API operation, split into live in production and not available yet |
| [`https://backworkhealth.com/llms-full.txt`](https://backworkhealth.com/llms-full.txt)             | Every docs page as Markdown in one file                                                           |
| `https://backworkhealth.com/docs/<page>.md`                                                        | One page as Markdown, for example [`/docs/mcp.md`](https://backworkhealth.com/docs/mcp.md)        |
| [`https://backworkhealth.com/api/v1/openapi.json`](https://backworkhealth.com/api/v1/openapi.json) | The OpenAPI 3.1 document                                                                          |

Each docs page also has a **Copy Markdown** button and an **Open** menu that sends the page to ChatGPT, Claude, or Cursor.

Agents that discover services by well-known URLs can start from:

* [`/.well-known/api-catalog`](https://backworkhealth.com/.well-known/api-catalog): an RFC 9727 catalog that links the OpenAPI document, the docs, and the MCP server.
* [`/.well-known/mcp/server-card.json`](https://backworkhealth.com/.well-known/mcp/server-card.json): the MCP endpoint, its transport, and its OAuth metadata. MCP clients list the tools with `tools/list` after they connect.

## Connect over MCP [#connect-over-mcp]

The hosted MCP server uses Streamable HTTP at:

```text
https://backworkhealth.com/mcp
```

It runs at `mcp.backworkhealth.com`; use the `backworkhealth.com/mcp` URL, because that is the resource the OAuth tokens are issued for. In Claude Code:

```bash
claude mcp add --transport http --scope user backwork https://backworkhealth.com/mcp
```

Then run `/mcp`, select `backwork`, and sign in. See [MCP Server](/docs/mcp) for Claude Desktop, Cursor, VS Code, and Codex. MCP tool calls spend your organization's [request credits](/docs/pricing).

### OAuth [#oauth]

The hosted server accepts Backwork OAuth access tokens only, not API keys. An OAuth client finds everything it needs from the server:

1. `https://backworkhealth.com/.well-known/oauth-protected-resource` names the resource (`https://backworkhealth.com/mcp`) and the authorization server (`https://backworkhealth.com`).
2. `https://backworkhealth.com/.well-known/oauth-authorization-server` lists the authorization, token, registration, and revocation endpoints. Clients register dynamically and use PKCE with `S256`.
3. Request the scopes `backwork:mcp read`. They are read-only: actions that change data need an API key with the `write` scope.

An access token lasts 1 hour. The token response also contains a refresh token. Send it with `grant_type=refresh_token` to `https://backworkhealth.com/api/oauth/token` to get a new access token and a new refresh token, and store the new one: each refresh token works once. Using a refresh token a second time revokes every token from that consent. A refresh token expires after 7 days without use, and 30 days after the consent in any case; then the user signs in again. The [MCP Server](/docs/mcp#token-lifetimes-and-refresh) page has the full rules and the revocation call.

## Call the REST API [#call-the-rest-api]

Create a live key in [API usage and keys](https://backworkhealth.com/api-usage) (see the [Quickstart](/docs/quickstart)) and send it in the `Authorization` header:

```bash
curl "https://backworkhealth.com/api/v1/health" \
  -H "Authorization: Bearer $BACKWORK_API_KEY"
```

See [Authentication](/docs/authentication) for keys and scopes. Every call spends request credits; [Pricing and credits](/docs/pricing) lists what each endpoint costs, so an agent can budget before it plans a batch of calls.

### Check production availability first [#check-production-availability-first]

Some documented operations are not live in production yet. The OpenAPI document marks each of them with:

```json
"x-backwork-availability": "unavailable-in-production"
```

An operation without the field is live. A production request to a marked operation returns `404` with the error code `COMMERCIAL_SURFACE_UNAVAILABLE`. Do not retry it: use `GET /api/v1/releases/{releaseId}/decisions` instead. Agents should read the field from the OpenAPI document before they plan a call. The API reference and [`llms.txt`](https://backworkhealth.com/llms.txt) use the same data.

### Retry only retryable errors [#retry-only-retryable-errors]

Every error response has a `retryable` field:

```json
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded",
    "hint": "Wait the number of seconds in the Retry-After header, then retry",
    "docUrl": "https://backworkhealth.com/docs/errors#rate-limit-exceeded",
    "retryable": true
  },
  "meta": { "request_id": "req_abc123", "timestamp": "2026-01-15T10:30:00Z" }
}
```

* If `retryable` is `true`, retry with backoff. On a `429`, wait for the number of seconds in `Retry-After`.
* If `retryable` is `false`, do not retry the same request. Change the request, or show the `message` and `hint` to the user.
* A `402` with `BILLING_CREDITS_EXHAUSTED` means the organization is out of credits. Stop and tell the user; `details.requests_available` has the balance. See [When credits run out](/docs/pricing#when-credits-run-out).
* `docUrl` links to the entry for the code on [Errors](/docs/errors).

### Treat inferred codes as unconfirmed [#treat-inferred-codes-as-unconfirmed]

Code entries carry a `source`. An `inferred_title_match` code is not listed in the policy document; confirm it against the document, or route the case to a person, before acting on it. See [Code sources](/docs/code-sources).

### Send idempotency keys on writes you might retry [#send-idempotency-keys-on-writes-you-might-retry]

The operations below accept an `X-Idempotency-Key` header. Send a new unique value, such as a UUID, for each logical request, and send the same value when you retry it:

* A retry with the same key and the same body returns the stored response for 24 hours. The operation does not run again.
* The same key with a different body returns `409` `REQUEST_IDEMPOTENCY_CONFLICT`. Use a new key.
* While the first request is still running, a retry returns `409` `REQUEST_IDEMPOTENCY_IN_PROGRESS`, which is retryable.
* If Backwork cannot check the key, it returns `503` `SERVER_IDEMPOTENCY_UNAVAILABLE` and does not run the request. Retry with the same key.

A key is 1 to 255 printable ASCII characters.

| Operation                                      | Endpoint                        | Production |
| ---------------------------------------------- | ------------------------------- | ---------- |
| [`comparePolicies`](/docs/api/comparePolicies) | `POST /api/v1/policies/compare` | Live       |
| [`checkPriorAuth`](/docs/api/checkPriorAuth)   | `POST /api/v1/prior-auth/check` | Live       |
| [`validateClaim`](/docs/api/validateClaim)     | `POST /api/v1/claim-validation` | Live       |
| [`validateClaims`](/docs/api/validateClaims)   | `POST /api/v1/claims/validate`  | Live       |
