Authentication
API key setup, scopes, rate limits, and security best practices
All API requests require a Bearer token in the Authorization header.
Authorization: Bearer atb_live_your_key_hereGetting a key
Create API keys from Settings > Developer in the Atribu dashboard. Each key is scoped to a single profile.
Show once
Keys are shown exactly once at creation. Store them securely — you cannot retrieve them later.
Scopes
Each API key has granular scopes that control what data it can access.
Analytics (read-only)
| Scope | Access | Endpoints |
|---|---|---|
analytics:read | Read aggregated analytics: overview, timeseries, breakdowns, quality, touches, and channel/referrer/page/keyword/country/device/browser/OS dimensions. | 137 |
campaigns:read | Read campaign, ad set and ad performance: ROAS, trends, archetypes, creative patterns, DM ads, forecast outlook and top performers. | 36 |
conversions:read | Read conversion counts and revenue, including cash-only revenue and conversion timeseries. | 7 |
realtime:read | Read the live visitor count. | 1 |
PII (read-only)
PII scopes
customers:read and visitors:read expose personal data (names, emails, journey details). Only grant these when your integration specifically needs customer-level data.
| Scope | Access | Endpoints |
|---|---|---|
customers:read | Read the customer list and per-customer journey detail — personally identifiable information. | 19 |
visitors:read | Read the visitor list — personally identifiable information. | 2 |
Commerce (read-only)
| Scope | Access | Endpoints |
|---|---|---|
commerce:read | Read the merchant's product catalogue (products, variants, stock and prices) and look an order up by number, email or phone. Returns no customer identity. | 2 |
Conversion export (read, write)
| Scope | Access | Endpoints |
|---|---|---|
exports:read | Read the conversion-export/signal-sync surface: Meta CAPI wiring diagnostics, dataset quality, Custom Audiences, export deliveries, and the compliance state behind Platform-Safe Mode. | 26 |
exports:write | Configure the conversion-export pipeline: create, edit and disable export destinations (Meta dataset/pixel, Google Ads conversion action) and the signal rules that map a conversion definition to a platform event, and send a Meta test event. | 30 |
Provisioning (write)
| Scope | Access | Endpoints |
|---|---|---|
workspaces:write | Create a workspace (POST /api/v1/workspaces). Not granted by any OAuth connect scope; an MCP user token holds it through the mcp:write grant. | 0 |
profiles:write | Create a profile inside a workspace the caller already belongs to (POST /api/v1/profiles). Not granted by any OAuth connect scope; an MCP user token holds it through the mcp:write grant. | 0 |
Attribution & goals (write)
| Scope | Access | Endpoints |
|---|---|---|
events:write | Ingest server-side outcome events (e.g. a closed sale) via POST /api/v1/events. | 3 |
goals:write | Create, list and edit conversion goal definitions. | 14 |
attribution:write | Trigger an attribution recompute for a profile. | 41 |
tracking:write | Configure a site's tracking installation: issue and revoke tracking keys, change the tracker's session/enrichment settings (which enqueues a full attribution replay), and start an install verification. | 11 |
reports:write | Create, schedule, generate and send attribution reports (report schedules, deliveries and send). | 13 |
campaigns:apply | Apply or dismiss a campaign recommendation. Not granted by default — a workspace admin must opt a key into it. | 5 |
creatives:write | Queue an on-demand AI analysis of one ad's creative (POST /api/v1/ads/{id}/creative-analysis). Each accepted call queues a model call against the workspace's daily creative-analysis allowance, so it is capped per profile and per key per day and is not granted by default — a workspace admin must opt a key into it. | 5 |
Calendar (read, write, manage)
| Scope | Access | Endpoints |
|---|---|---|
calendar.read | Read-only access to Atribu booking calendars and their events. | 5 |
calendar | Create, update and delete events on Atribu booking calendars. | 6 |
calendar.manage | Create, list and share (ACL) Atribu booking calendars. | 8 |
Messaging (write)
| Scope | Access | Endpoints |
|---|---|---|
whatsapp | Send and manage WhatsApp messages, templates, flows, broadcasts, calling and phone-number registration. | 47 |
instagram | Send and manage Instagram DMs, comment replies, triggers and media. | 44 |
email | Read and send connected email (Gmail/Outlook): drafts, threads, labels and search. | 8 |
Messaging (read-only)
| Scope | Access | Endpoints |
|---|---|---|
whatsapp:read | Read WhatsApp conversations, messages, templates and broadcasts. A read-only subset of whatsapp, which also allows sending and managing them. | 4 |
Inbox conversations (read, write)
PII scopes
conversations:read and conversations:write expose personal data — contact names, phone numbers and message content. Only grant these when your integration specifically needs inbox-level data.
| Scope | Access | Endpoints |
|---|---|---|
conversations:read | Read the unified inbox: conversation list and message threads across WhatsApp, Instagram and email, plus organic/ad match suggestions, contact-extraction review proposals and the Instagram DM↔payment reconciliation worklist. | 8 |
conversations:write | Reply on a conversation, save an email draft, apply Gmail labels, link/unlink a conversation to a customer, and approve/reject a contact-extraction review proposal. | 7 |
Default scopes when creating a key: analytics:read, campaigns:read, conversions:read, realtime:read.
The MCP user token — one credential for both surfaces
Since #1084 an MCP user token (atb_user_…) authenticates on /api/v1 exactly as it does on
mcp.atribu.app. It is the credential for a person's own AI agent: one token, both surfaces, no
separate API key to mint per profile.
Authorization: Bearer atb_user_your_token_hereHow to get one
Through the MCP OAuth flow — the bootstrap for an agent with no Atribu account of its own.
The agent registers a client (dynamic registration + PKCE) against https://mcp.atribu.app,
builds the authorize URL and hands it to its human. The human signs in, approves the consent
screen, and the agent holds the token. See MCP authentication.
Or mint one directly if you are already signed in: POST /api/v1/me/mcp-tokens, from
Settings > Developer or from a session-authenticated call. The plaintext token is returned
once and never again.
How it differs from an API key
An API key is a tenant — it is minted for exactly one profile. A user token names a person, who may reach several. So:
?profile_id=<uuid>is required on profile-scoped routes. Its absence is a400invalid_request, never a guess. Workspace-scoped routes take?workspace_id=(or the path segment) instead.- A profile the person cannot reach answers
404 not_found— byte-identical to a profile that does not exist, so the status line can never be used to enumerate tenants. - The workspace-grain routes an API key is refused on (
/api/v1/workspaces, the cross-profile leaderboards) are open to a user token.
What the MCP scopes map to
A request's scopes are the intersection of two things: what the token's mcp:* grant maps to,
and what the person's own workspace/profile membership already grants. Neither can widen the other.
| MCP scope | API scopes it maps to |
|---|---|
mcp:read | analytics:read, campaigns:read, conversions:read, realtime:read |
mcp:read_pii | customers:read |
mcp:write | exports:read, exports:write, goals:write, attribution:write, tracking:write, reports:write, workspaces:write, profiles:write, campaigns:apply |
No MCP scope grants commerce:read, exports:read, exports:write, visitors:read,
events:write, creatives:write, or any messaging, calendar or inbox scope. Those need an
API key.
Because the answer is an intersection, a 403 insufficient_scope can mean either half is too
narrow — the message names both, so you know whether to re-consent with a wider grant or ask a
workspace admin for more access.
Routes a user token can never reach
Three groups of writes answer 403 insufficient_scope to a user token whatever its grant,
because acting on them would let a credential administer the credential system itself. Widening
the token's scopes does not change the answer; only a signed-in session (or, where it already
worked, HTTP Basic) can do these.
| Route | Why |
|---|---|
/api/v1/me/** — the whole subtree, including /me/mcp-tokens | Your account: email, password, devices, sessions — and the tokens themselves. A token that could mint tokens could mint a wider one and revoke the one you would use to cut it off. |
POST/PATCH/DELETE on /api/v1/workspaces/{id}/api-keys (and …/{id}/revoke, …/{id}/rotate) | Minting an atb_live_ key. The key's scopes are chosen by the caller and are not bounded by the MCP grant, so a token that could mint one could mint itself out of every limit above. GET (the list, prefixes only) is a read and works. |
PUT /api/v1/workspaces/{id}/mcp-settings | pii_mode and mcp_writeback_enabled are the workspace's controls over what MCP tokens may do. An agent must not be able to widen the settings that govern agents. GET works — read them and tell your human what to change. |
Account administration stays a session act
These are refusals by credential class, not by scope, so they are absent from each route's
userToken security scheme in openapi.json too — the published spec says exactly what the
runtime does. Sign in at www.atribu.app to manage your account, your
API keys and your workspace's MCP settings.
Rate limits and revocation
A user token is metered against its own rate_limit_units_per_minute, in a bucket separate from
both API keys and browser sessions — so an agent's loop cannot rate-limit its owner's dashboard,
nor the reverse. A revoked or expired token answers 401 with the same envelope a revoked API key
gets. Revoke one from Settings > Developer, or disconnect the OAuth client that holds it.
Rate limits
Default: 60 requests per minute per key.
Heavy endpoints (customers, visitors, journey detail) cost 3x — meaning they consume 3 units of your rate limit per call.
Endpoints with their own bucket
A few endpoints carry a sustained cap on top of the per-minute limit, because one call is far more work than a read. These buckets are separate from your per-minute allowance — they can neither consume it nor be consumed by it — and a 429 from one carries Retry-After.
| Endpoint | Own bucket | Why |
|---|---|---|
POST /api/v1/quality/utm/refresh | 6 scans per hour, per key | Each call runs a live 8–12 second UTM-health scan. Within 10 minutes of the last scan the endpoint returns the cached summary with refreshed: false instead of scanning again. |
POST /api/v1/profiles | 200 calls per hour, per app credential | Each call can create a user, a workspace and a profile — all durable. |
POST /api/v1/ads/{id}/creative-analysis | 30 calls per hour, per key — and a daily budget: 20 analyses per profile and 100 per API key, both per UTC day | Each accepted call queues a multimodal model call on the ad's video, so this is the one endpoint that spends the workspace's daily AI allowance. The hourly bucket is the burst guard; the daily budget is the real ceiling, and a 429 from it carries Retry-After set to the seconds until the next UTC midnight. A repeat request for the same ad and the same unchanged creative inside 24 hours returns the existing job and consumes nothing. See Creative analysis. |
| Header | Description |
|---|---|
X-RateLimit-Limit | Your total limit per minute |
X-RateLimit-Remaining | Remaining requests in current window |
X-Request-Id | Unique request ID for debugging |
When rate limited, you'll get a 429 response with a Retry-After header (seconds).
Key rotation
Rotate keys with zero downtime:
Call the Rotate endpoint — creates a new key
Both old and new keys work for 48 hours
Update your integration with the new key
The old key automatically expires after the grace period
Security best practices
Server-to-server only
This is a server-to-server API. Never expose keys in client-side JavaScript, mobile apps, or browser code.
- Use the minimum scopes needed — don't grant
customers:readif you only need analytics - Rotate keys regularly — the rotation endpoint makes this seamless
- Revoke compromised keys immediately — revocation is instant
Error responses
{
"error": {
"code": "unauthorized",
"message": "Invalid or expired API key",
"status": 401,
"request_id": "req_a1b2c3d4"
}
}| Code | Status | Meaning |
|---|---|---|
unauthorized | 401 | Missing or invalid API key |
insufficient_scope | 403 | Key doesn't have the required scope |
rate_limit_exceeded | 429 | Too many requests |
invalid_parameter | 400 | Bad query parameter |
invalid_date_range | 400 | Date range exceeds 366 days or dates are invalid |
internal_error | 500 | Server error — include the request_id when reporting |