Authentication
Every authenticated call carries two headers, and the install handshake is how an integration gets them without a human. This page shows the flow working and the four rejections that prove the gate is real. What is faithful versus simplified is on Real vs. simulated.
The two-header convention
Section titled “The two-header convention”Every authenticated call carries two headers, the same shape the real API uses:
Authorization: Bearer <api_key>Partly-Integration-ID: <integration_id>The lone exception is the install call itself (integrations.insert), which is unauthenticated. It is how you obtain those two values in the first place.
Provision credentials without a human (the install handshake)
Section titled “Provision credentials without a human (the install handshake)”A real integration shouldn’t run on a hand-pasted key. The install call exchanges an OAuth grant for a fresh, long-lived credential:
-
You hold an OAuth grant:
client_id,client_secret, and a single-useaccess_code. (The sandbox seeds demo fixtures so you can run this immediately.) -
Exchange it at the one unauthenticated endpoint:
Terminal window curl -s -X POST \https://partifact-mock.thanhvuttv.workers.dev/api/2026-01/integrations.insert \-H "Content-Type: application/json" \-d '{"client_id":"partifact_client_demo","client_secret":"secret_demo_8f3a","access_code":"ac_demo_valid_15m"}' -
You get back a fresh credential, a new
api_key+integration_idevery time:{ "api_key": "partifact_caa7bb17f08447dca1474ff8f74b2158","integration_id": "e7019e6d-9b61-4932-b45b-e792547cdb5a" } -
Use those two values as the
Authorization: BearerandPartly-Integration-IDheaders on every subsequent call.
The shortcut: pre-loaded demo credentials
Section titled “The shortcut: pre-loaded demo credentials”You don’t have to run the install to start. The sandbox pre-loads ready-to-use repairer and supplier credentials wired to the seeded Corolla job, so you can make an authenticated call with zero setup. The exact values live on Credentials and tokens.
Use the install handshake (above) to prove the contract end to end; use the pre-loaded creds to drive the seeded job immediately.
Proof the gate is real: the rejection model
Section titled “Proof the gate is real: the rejection model”Auth that can’t reject anything isn’t auth. Each failure is a type-tagged body (the variant object is the response; the HTTP status is added for realism). All four are live right now:
| Try this | Response | Meaning |
|---|---|---|
Install with an unknown client_id | 404 {"type":"integration_not_found"} | no such integration client |
Install with a bad or already-used access_code | 401 {"type":"invalid_access_code"} | the grant code is invalid or spent (single-use) |
| Any call with a missing or wrong bearer | 401 {"type":"unauthorized"} | not authenticated |
| A repairer key calling a supplier-scope method | 403 {"type":"forbidden"} | authenticated, but wrong role/scope |
# wrong scope: a repairer credential on a supplier-only method:curl -s -o /dev/null -w "%{http_code}\n" -X POST \ https://partifact-mock.thanhvuttv.workers.dev/api/2026-01/supplier.procurements.confirm \ -H "Authorization: Bearer partifact_demo_repairer_3f8a1c0d9e2b4a67b1c2" \ -H "Partly-Integration-ID: 0c000000-0000-4000-8000-000000000001" \ -H "Content-Type: application/json" -d '{"identity":{"id":"00000000-0000-4000-8000-000000000000"}}'# -> 403 {"type":"forbidden"}The distinction between unauthorized (no or bad credential), forbidden (right credential, wrong role), and not_found (right role, wrong org, where a cross-org read is hidden, not denied) is the same privacy-preserving scoping the real contract uses.
Where to go next
Section titled “Where to go next”- The sandbox API: the wire convention, lifecycle, and machine surfaces.
- The builder test: watch an agent perform this handshake on first run, then build the integration.
- Credentials and tokens: the one page listing every test credential and the demo token.