<!-- title: For AI agents | order: 8 | summary: How a coding agent should consume these docs and the companion Rails MCP. -->

# For AI agents

You are an LLM or coding agent building an integration against **Rails Sandbox — a Rails-compatible API**. This is a faithful mock of the public `2026-01` Integrations API, plus a small set of clearly-labelled proposed extensions. It is not a real vendor's own documentation.

This page tells you how to read these docs efficiently, where the machine-readable surfaces are, and how to tell apart the two things that look similar but are not: **this docs site** (for *building* an integration) and the **companion Rails MCP server** (for *driving* one at runtime).

## Two distinct surfaces — pick the right one

| You want to… | Use | What it is |
|---|---|---|
| **Build** an integration — write HTTP/SDK code that calls the API | **This docs site** + `/openapi.json` | Prose contract, copy-paste examples, the typed OpenAPI spec |
| **Drive** the procurement lifecycle at runtime as an agent | **The companion Rails MCP server** | Intent-level tools (`open_repair_job`, `recommend_basket`, …) that wrap the same wire methods |

If your task is "implement a client / SDK / webhook receiver," stay on the docs site. If your task is "run a parts-procurement workflow end to end," connect the Rails MCP and call its tools — you do not need to hand-write HTTP requests at all.

## Machine-readable surfaces

Every page on this site is available as raw markdown, and the whole corpus is downloadable in two forms. Prefer these over scraping rendered HTML.

- **Raw markdown for any page** — append `.md` to the path, *or* send `Accept: text/markdown`. For example, [Quickstart](./quickstart.md) is fetchable as `/docs/quickstart.md`.
- **`/llms.txt`** — the index: every page's title, summary, and link, in one short file. Read this first to plan which pages you need.
- **`/llms-full.txt`** — the entire docs corpus concatenated into one file. Fetch this once if you want all the prose in a single context window instead of crawling page by page.
- **`/openapi.json`** — the typed contract (OpenAPI 3.1). This is the source of truth for request/response/error schemas. Generate a typed client from it rather than transcribing field names by hand.

```bash
# The four machine surfaces (replace the host if you self-host the mock).
curl -s https://partifact-mock-rails.thanhvuttv.workers.dev/llms.txt
curl -s https://partifact-mock-rails.thanhvuttv.workers.dev/llms-full.txt
curl -s https://partifact-mock-rails.thanhvuttv.workers.dev/openapi.json
# Any page as raw markdown — append .md:
curl -s https://partifact-mock-rails.thanhvuttv.workers.dev/docs/quickstart.md
# …or negotiate by content type:
curl -s -H "Accept: text/markdown" https://partifact-mock-rails.thanhvuttv.workers.dev/docs/quickstart
```

## Recommended reading order

Read in this sequence. Each page assumes you've read the ones before it.

1. **[Quickstart](./quickstart.md)** — the base URL, the RPC-over-POST convention, and a first call you can make in under a minute against pre-loaded demo credentials.
2. **[Authentication](./authentication.md)** — the two required headers, the OAuth install flow (`integrations.insert`), and the coded auth/install failures. Note: you can skip the OAuth dance entirely — the mock pre-loads ready-to-use repairer and supplier credentials.
3. **[Lifecycle](./lifecycle.md)** — the ordered procurement lifecycle, wire method by wire method, and the public/extension boundary.
4. **[Webhooks](./webhooks.md)** — the HMAC-signed envelope, the 5-minute replay window, and verification snippets you can paste verbatim.
5. **[Errors](./errors.md)** — the per-method type-tagged error model and what each coded variant means.
6. **[API Reference](./api-reference.md)** — the full method-by-method contract; consult per call, don't read end-to-end.

If you only have one fetch, get `/llms-full.txt` — it contains all of the above.

## The wire convention (so the examples make sense)

- **Base URL:** `https://partifact-mock-rails.thanhvuttv.workers.dev`
- **Every call:** `POST <base>/api/2026-01/<dotted.method>` with a JSON body. The dotted method name is the last path segment, e.g. `.../api/2026-01/repairer.jobs.get`.
- **Auth headers on every call** except `integrations.insert`:
  - `Authorization: Bearer <api_key>`
  - `Partly-Integration-ID: <integration_id>`

```bash
# Read the seeded demo job. Pre-loaded repairer credentials — no install needed.
curl -s https://partifact-mock-rails.thanhvuttv.workers.dev/api/2026-01/repairer.jobs.get \
  -H "Authorization: Bearer partly_demo_repairer_3f8a1c0d9e2b4a67b1c2" \
  -H "Partly-Integration-ID: 0c000000-0000-4000-8000-000000000001" \
  -H "Content-Type: application/json" \
  -d '{"identity":{"external":"CCC-2026-04817"}}'
```

## Errors name the next step

When you build against this mock, error bodies are the **wire contract** — each method declares its own type-tagged union, and the variant object *is* the response body (there is no shared `{code, message}` envelope). The HTTP status is added for realism; the body's `type` is the signal. See [Errors](./errors.md) for the full table.

If instead you DRIVE the lifecycle through the companion Rails MCP, the MCP layer goes one step further: it **enriches** every error into `{ code, message, retryable }` where `message` names the *next action* so you can self-correct from the message alone. Two rules worth internalizing:

- `retryable: true` is reserved for **transport faults** (the call never reached the server). A contract error always needs a *different* action — never a blind retry.
- After any state-changing call, **re-fetch** (`get_job` / `track_procurement`); do not assume the new state.

## The companion Rails MCP (runtime)

A separate **Rails MCP server** exposes the same procurement lifecycle as intent-level tools and resources, for an agent to drive at runtime. It wraps the wire methods documented here, so the contract is identical — you just call named tools instead of constructing HTTP requests.

It currently exposes **13 tools** and **8 resources**.

**Tools (13):** `get_started`, `get_run_metrics`, `prepare_vehicle`, `find_repairer_site`, `list_work_providers`, `open_repair_job`, `get_job`, `identify_parts`, `recommend_basket`, `track_procurement`, `confirm_procurement`, `place_procurement` ⚠, `reconcile_invoice` ⚠.

**Resources (8):** `guide://lifecycle`, `scenario://current`, `reference://suppliers`, `reference://ghca-categories`, `reference://work-providers`, `job://current`, `job://{job_id}` (template), `events://recent` (the webhook outbox).

Notes:
- Call **`get_started` first** — it returns the full tool order for the lifecycle.
- `confirm_procurement` is the only **supplier**-scope tool; everything else is repairer-scope.
- The ⚠ tools (`place_procurement`, `reconcile_invoice`) are **proposed extensions** (see below); they announce themselves at runtime via `is_extension: true`.

The distinction is the whole point: **the docs site is for writing an integration; the MCP is for an agent to operate one.** A coding agent implementing a an API client reads these pages and `/openapi.json`. An agent running a repair-shop procurement workflow connects the MCP and calls its tools.

## Install & connect the MCP (deployed — no local build)

Both MCP servers are **live on Cloudflare Workers**, so you can connect and test without cloning or building anything. Both speak **Streamable HTTP**. The **Rails MCP** is gated by a shared access token (it drives stateful, per-tenant sandboxes); the **Docs MCP** is **public and read-only** — no token. For the Rails MCP a connector UI (such as claude.ai) takes a URL, so the token rides in the path (or send it as an `Authorization: Bearer <token>` header).

### 1. The Rails MCP — *operate* the lifecycle

The runtime server described above (13 tools + 8 resources). Connect it at:

```
https://partifact-rails-mcp.thanhvuttv.workers.dev/mcp/<MCP_ACCESS_TOKEN>/<your-slot>
```

- `<MCP_ACCESS_TOKEN>` — the shared token provided with your invite. It only gates the endpoint against random traffic.
- `<your-slot>` — **any name you choose** (`[a-z0-9_-]`). It selects your **own private sandbox**, seeded fresh with the same Corolla job (external reference `CCC-2026-04817`). Two people on two slots never touch each other's data; to start over, just change the name. Idle slots self-reset after ~1 hour.

In **claude.ai → Settings → Connectors → Add custom connector**, paste the URL and save. Then, in a fresh chat with the connector enabled, ask the agent to drive the job — e.g. *"Using only the Rails MCP tools, take the 2019 Toyota Corolla job (`CCC-2026-04817`) through to a reconciled invoice, and tell me what you did at each step."* The agent orients itself from `get_started` / `guide://lifecycle` / `scenario://current` alone.

### 2. The Docs MCP — *read these docs* as tools

A separate, read-only server that exposes **this documentation** as tools (`list_docs`, `get_doc`, `search_docs`) — for an agent that would rather query the docs than crawl the rendered site. It is **public** (no token) and stateless:

```
https://partifact-docs-mcp.thanhvuttv.workers.dev/mcp
```

No token, no slot — its corpus is already public (the same markdown this site serves), so there is nothing to gate. For example, `search_docs("verify webhook signature")` returns the [Webhooks](./webhooks.md) page.

### Liveness check (no token needed)

```bash
curl https://partifact-rails-mcp.thanhvuttv.workers.dev/   # the runtime MCP — expect a 200 liveness line
curl https://partifact-docs-mcp.thanhvuttv.workers.dev/    # the docs MCP — expect a 200 liveness line
```

> A local, zero-config install over **stdio** (Claude Desktop / Claude Code / Cursor) is also available for development — it runs the mock in-process, with no token and no slot. The deployed URLs above are the canonical way to test with no local build.

## Fidelity boundary — read before you trust a field

This sandbox is faithful to the public `2026-01` contract, with two explicit additions. Hold the line on the following.

**The public lifecycle terminates at `order_confirmed`.** `supplier.procurements.confirm` transitions a procurement `order_requested → order_confirmed`, which is the **terminal public state** of the `2026-01` contract.

**Two proposed extensions go beyond it.** `place_procurement` (`repairer.procurements.insert`) and `reconcile_invoice` (`repairer.procurements.invoices.list`) are clearly-labelled proposed extensions, NOT part of the public `2026-01` API. Wherever they appear they carry this banner verbatim:

> (Proposed extension beyond the public 2026-01 API — the public contract stops at `order_confirmed`; this completes the buyer loop.)

Their HTTP responses carry `x_extension: true`; the MCP equivalents carry `is_extension: true`. Treat these as a *proposal*, not the shipped contract.

**The basket carries no currency.** The basket response (`repairer.jobs.baskets.latest.get`, returning `{ offers, suppliers }`) has **no `currency` field** — not on the envelope, not on an offer. Currency is a procurement-level concept (D52): it first appears later in the lifecycle as `currency_code` on the procurement. The MCP's *projected* basket derives an `NZD` label purely as a presentation-layer convenience; the wire basket itself asserts no currency. If you read a currency off a basket offer, you are inventing it — go to the procurement instead.

## Where to go next

- [Quickstart](./quickstart.md) — make your first authenticated call.
- [API Reference](./api-reference.md) — the full method-by-method contract.
- `/openapi.json` — generate a typed client instead of transcribing schemas.
