Authentication
Partifact reproduces the API’s authentication contract — the install handshake, the two headers, the org-scoped key, and the type-tagged error model — faithfully enough to build a real client against. This page shows exactly how it works, proves the gate is real (the rejections), and is upfront about exactly what’s simplified.
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’s 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-rails.thanhvuttv.workers.dev/api/2026-01/integrations.insert \-H "Content-Type: application/json" \-d '{"client_id":"partly_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": "partly_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 & 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/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-rails.thanhvuttv.workers.dev/api/2026-01/supplier.procurements.confirm \ -H "Authorization: Bearer partly_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/bad credential), forbidden (right credential, wrong role), and not_found (right role, wrong org — a cross-org read is hidden, not denied) is the same privacy-preserving scoping the real contract uses.
What it is, and isn’t
Section titled “What it is, and isn’t”Calibrated honesty — we say exactly what we built, and own the simplification:
| Faithful to the contract | Deliberately simplified (and why) |
|---|---|
The install RPC (integrations.insert) exchanging a grant for a credential | No external authorization server — the grant is seeded demo fixtures, so the demo needs nothing stood up |
| The two-header auth on every call | No PKCE / no refresh tokens / no real token-expiry clock |
Org-scoped api_key; role/scope gating (forbidden) | Credentials live in the sandbox’s store, not a real IdP |
Single-use access codes (invalid_access_code on reuse) | The fixture is named …_15m but the enforced behaviour is single-use, not a timed window |
| The type-tagged, per-method error model | — |
We chose the self-contained stub to keep the artifact runnable and frictionless — and we’re aware of the limitation: this demonstrates the authentication contract and its failure modes, not a production security implementation. That boundary is stated, not hidden.
Where to go next
Section titled “Where to go next”- The API at a glance — the wire convention, lifecycle, and machine surfaces.
- Let the AI do the coding — watch an agent perform this handshake on first run, then build the integration.
- Credentials & tokens — the one page listing every test credential and the demo token.