The sandbox API
This is the API both tests ran against, in one screen: the wire convention, the lifecycle, webhooks, and the error model. The typed contract is /openapi.json; generate a client from it rather than transcribing field names.
The wire convention
Section titled “The wire convention”- Base URL:
https://partifact-mock.thanhvuttv.workers.dev - Every call:
POST <base>/api/2026-01/<dotted.method>with a JSON body. The method is the last path segment, e.g..../api/2026-01/repairer.jobs.get. It is RPC over POST, date-versioned (2026-01), not REST resources. - Two headers on every call (except the install call):
Authorization: Bearer <api_key>Partly-Integration-ID: <integration_id>
Your first call, reading the seeded demo job with pre-loaded repairer credentials, no install needed:
curl -s https://partifact-mock.thanhvuttv.workers.dev/api/2026-01/repairer.jobs.get \ -H "Authorization: Bearer partifact_demo_repairer_3f8a1c0d9e2b4a67b1c2" \ -H "Partly-Integration-ID: 0c000000-0000-4000-8000-000000000001" \ -H "Content-Type: application/json" \ -d '{"identity":{"external":"CCC-2026-04817"}}'The OAuth install flow
Section titled “The OAuth install flow”A real integration provisions itself rather than using hand-pasted keys. The install call, integrations.insert, is the one method that takes no auth headers; it exchanges an OAuth grant for the api_key + integration_id every other call needs. (The sandbox also pre-loads ready-to-use repairer and supplier credentials, so you can skip the dance while exploring.) Full flow: Authentication.
The procurement lifecycle
Section titled “The procurement lifecycle”The ordered path from a vehicle to a settled invoice, wire method by wire method:
| Step | Wire method | Result |
|---|---|---|
| Prepare the vehicle | tier1.prepare | normalized vehicle |
| Find the repairer site | businesses.list | site id |
| List work providers | repairer.work-providers.list | provider ids |
| Open a repair job | repairer.jobs.insert | job |
| Identify parts | repairer.jobs.parts.insert | parts on the job |
| Get a basket | repairer.jobs.baskets.latest.get | { offers, suppliers } |
| Place the order extension | repairer.procurements.insert | order_requested |
| Confirm the order | supplier.procurements.confirm | order_confirmed ← terminal public state |
| Reconcile the invoice extension | repairer.procurements.invoices.list | itemized invoice |
Re-read state any time with repairer.jobs.get and repairer.procurements.get. To watch an agent drive this lifecycle as named tools, see the Procurement MCP.
Two of these steps go beyond the public contract, and the basket deliberately carries no currency field; both are explained on Real vs. simulated.
Signed webhooks
Section titled “Signed webhooks”State changes emit HMAC-SHA256-signed webhooks: an 8-field envelope (message_id, event type, timestamp, payload, and so on), a base64 signature in the partly-hmac-sha256 header, and a 5-minute replay window. Verifying the signature is the single most security-sensitive thing an integrator does. The paste-ready TypeScript and Python recipe is part of the contract docs the agent reads.
The error model
Section titled “The error model”Each method declares its own type-tagged union of errors, 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. (The Procurement MCP enriches these into { code, message, retryable } for agents, but the wire model is type-tagged.) The auth rejections are demonstrated live on Authentication; the full per-method union is in the typed /openapi.json.
Machine-readable surfaces
Section titled “Machine-readable surfaces”Built for agents. Prefer these over scraping HTML:
To operate the lifecycle without writing HTTP, use the Procurement MCP; to query this contract as tools, the Docs MCP.