For AI agents
Everything a program needs to take a human from a fresh email to a Purchase landing in Meta — the bootstrap, the discovery documents, the readiness read, and the hand-off pattern.
You are an AI agent, or you are building one. You have no Atribu account, no workspace, no API key, and no browser of your own. This page is the whole surface, in the order you need it.
The golden path is the same thirteen steps a human walks. Twelve of them are yours. Exactly one — creating the account — is a person's, and even that happens inside a URL you hand over.
1. Read these first
| document | what it is |
|---|---|
llms.txt | the map: every product surface, every doc page, every machine-readable entry point |
llms-full.txt | every documentation page concatenated as one markdown document |
openapi.json | OpenAPI 3.1 for all of /api/v1 |
/api/docs/{path} | any single doc page as raw markdown |
Discovery documents for the OAuth surfaces, both live and standards-compliant:
https://www.atribu.app/.well-known/oauth-authorization-server # RFC 8414
https://mcp.atribu.app/mcp # Streamable-HTTP MCP2. The bootstrap: there is no signup API
Account creation is a human act behind a captcha. The bootstrap is therefore an OAuth hand-off, exactly like connecting Gmail or Cloudflare:
Register a client and build the authorize URL
Dynamic Client Registration (RFC 7591)
at POST /oauth/mcp/register. Public clients only — PKCE (S256; plain is
refused) proves the exchange.
Print the URL and stop
Open this to connect your Atribu account:
https://www.atribu.app/oauth/mcp/authorize?response_type=code&client_id=…
An unrecognised email goes straight to signup with the pending authorization preserved, and the email-confirmation link returns them to your consent screen — not to a dashboard. A user with no workspace is told so plainly: "You have no workspace yet — your agent will create one after you approve."
Exchange the code, then keep the token
POST /oauth/mcp/token. The access token lives 1 hour; the refresh token lives
60 days and rotates on every use — store the new one each time. Replaying
an old refresh token burns the whole family, which is the reuse detection
working.
Step by step, with every request and response: API quickstart · MCP quickstart.
One token, two surfaces
Since #1084 an atb_user_… token is a first-class /api/v1 principal. The
token the consent screen produced works on https://mcp.atribu.app/mcp and
on https://api.atribu.app/api/v1/*. Nothing else has to be minted, and an API
key is only for a machine job that belongs to a profile rather than to a person.
3. Call whoami before anything else
curl -sX POST https://mcp.atribu.app/mcp \
-H "Authorization: Bearer atb_user_…" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"whoami","arguments":{}}}'It costs zero units and answers with the workspaces, profiles, currency, PII
mode and write-back state the caller actually has. The REST equivalent is
GET /api/v1/workspaces, which needs no profile_id — which is exactly why it
is the right first call.
A user token must name a profile
An API key is one profile. A user token may reach several, so
?profile_id=<uuid> is required on profile-scoped routes: its absence is a
400, never a guess.
4. Bootstrap the objects
curl -sX POST https://api.atribu.app/api/v1/workspaces \
-H "Authorization: Bearer atb_user_…" -H "Content-Type: application/json" \
-d '{"name": "My Agency"}'
curl -sX POST https://api.atribu.app/api/v1/profiles \
-H "Authorization: Bearer atb_user_…" -H "Content-Type: application/json" \
-d '{"workspace_id": "WORKSPACE_ID", "name": "My Website"}'
curl -sX POST "https://api.atribu.app/api/v1/tracking/keys?profile_id=PROFILE_ID" \
-H "Authorization: Bearer atb_user_…"
curl "https://api.atribu.app/api/v1/profile/readiness?profile_id=PROFILE_ID" \
-H "Authorization: Bearer atb_user_…"Both creates are idempotent — the workspace on (you, name) for a short
window, the tracking key on "this profile already has an active one". Retrying
after a dropped connection is safe and is not a duplicate.
5. Readiness is your program counter
GET /api/v1/profile/readinessTwelve steps in golden-path order, each with a status, a why, a next and a
docs_url. summary.next_step is the first non-done step — first, not
"most important": the order is the priority.
Every non-done step's next is one of two shapes, and the difference is the
whole design:
| shape | meaning |
|---|---|
{"method": "…", "path": "…"} | a call you can make right now with the credential you hold |
{"handoff_kind": "…"} | a class of action only a person can take |
Four hand-off kinds, and each is honest about why: connect (an OAuth consent
needs a browser), sign_dpa (a signature forged on someone's behalf is not a
signature), checkout (a payment), contact_support (Atribu itself has to
change something).
Do not use onboarding_completed for this. It means one thing — a person
pressed Finish in the wizard — and every wizard step is skippable. Full
detail: Readiness.
6. The hand-off pattern
Give the user this URL. Poll this handle. Continue when it settles.
GET /api/v1/handoffs/{id}- Mint through the route for the thing you need — a hand-off with nothing
behind it is a URL nobody can complete, so there is deliberately no
POST /api/v1/handoffs. - Hand the URL over. It is returned only while
statusispending. Capture it once and give it to your user; re-poll forstatus, not for the URL. Whoever holds it can complete it — no Atribu account, no session, no desktop. - Poll. An expired hand-off is a
200withstatus: "expired", never a404. A404means the id names nothing your workspace minted.
45 minutes by default. Always read expires_at; a kind whose underlying object
has its own clock mirrors that clock instead. Full detail:
Hand-offs.
Stop polling where you can
connection.connected, connection.reconnect_required, handoff.completed,
recompute.completed, conversion.attributed, export.completed and
export.failed all fan out as webhooks (#1049). Subscribe with
providers: ["atribu"] — every platform lifecycle event carries that provider,
not a channel, and a subscription that omits it receives none of them. See
Webhooks.
7. What is live over MCP
The whole golden path is. tools/list carries real input schemas,
readOnlyHint / destructiveHint annotations, resources and prompts (#1062).
Start here:
| tool | use |
|---|---|
whoami | who am I, what can I reach, what is missing |
get_readiness | the twelve-step checklist |
list_workspaces, list_profiles | navigation |
apply_recommendation, send_meta_conversions | the two Meta write-backs, preview → dry_run → confirm |
whoami also folds in a readiness rollup — next_step plus the missing_steps
— so one free call answers "who am I and what is left". When that forwarded read
fails it answers null with a readiness_error naming the cause, never an
empty missing_steps that would read as "all done".
The onboarding family (#1058)
Sixteen tools that walk the golden path end to end, grouped by the step they serve:
| step | tools |
|---|---|
| 3 — workspace + profile | create_workspace · create_profile |
| 5 — tracker | issue_tracking_key · get_tracker_installer |
| 6–8 — connect | start_connect · get_handoff |
| 9 — conversions | list_outcome_events · suggest_conversion_definitions · create_conversion_definition · set_attribution_windows |
| 11 — send to Meta | configure_meta_capi · send_test_event |
| 12 — DPA + plan | sign_dpa · start_plan_upgrade |
| practice | create_demo_profile · delete_demo_profile |
Every write tool takes `mode`, and `preview` is free
mode: "preview" describes what the call would do and writes nothing;
mode: "confirm" performs it. Confirms are idempotent — the key is derived
from the arguments and recorded in the workspace's write-back audit — so a
retried confirm replays rather than doubling. This is the same ceremony the two
older write-backs use, not a second one.
Every one is a thin wrapper on exactly one /api/v1 route. They forward
your bearer and return what the API says; the client, the error map, the write
gates and the audit write live in one shared spine rather than sixteen copies.
So no tool holds business logic unreachable over REST — which is what makes
"drive it over MCP" and "drive it over REST" the same journey rather than two
implementations that can drift.
The approval hand-off is live (#1050)
A confirm from a principal that is not a workspace owner/admin — or any caller
passing require_approval: true — mints an approve hand-off carrying the
exact preview and writes nothing; your human approves in a signed-out
browser and you poll the same result payload back. It is what makes a
non-admin token useful instead of a dead end: before it, such a token was
refused outright with no way to ask anyone.
8. Practising against data that is not real (#1069)
curl -sX POST "https://api.atribu.app/api/v1/profiles/demo?workspace_id=WORKSPACE_ID" \
-H "Authorization: Bearer atb_user_…"Sixty days of a fictional clinic's Meta traffic, and a Meta CAPI destination
that records what it would have sent instead of calling Meta. Over MCP:
create_demo_profile / delete_demo_profile. Full detail:
Demo profile.
The engine runs for real, which is why the counts are a forecast
The seed writes inputs — ad structure, daily spend, identities, touches, and
outcome_events through the same CRM-ingest primitive every real provider uses
— then enqueues an ordinary recompute. conversions and
attribution_touchpoints across all five models come out of the pipeline,
not out of the seed, and the recompute is asynchronous. So the counts in the
response say what the recompute will produce; poll
GET /api/v1/overview for what it did.
Its own reads show its own money — that is the point — and every read that
spans a workspace's profiles leaves it out, so a demo profile can never
inflate a pacing aggregate or a leaderboard. DELETE is a hard delete, not an
archive (an archived demo would keep answering with its numbers), and deleting
nothing answers 200 with deleted: false rather than 404: a workspace with
no demo profile is the state you asked for, and a retry must not look like a
failure.
9. The skill
If your host is Claude Code, skills/atribu-attribution-skill packages the
tool vocabulary, the defaults (cash ROAS, PII masked) and the write-back safety
rules. See the skill.
Where to go next
The golden path
The thirteen steps, with an agent track on every one
API quickstart
The bootstrap in full — registration, PKCE, tokens
Readiness
Your program counter
Hand-offs
The five kinds, the statuses, the expiry rules
Errors
Every code, its status, and what to do about it
MCP tools
Every tool, its arguments, and its cost