Atribu
API Reference

Workspaces & Profiles

Create the container and the account being measured — the first two objects that have to exist before anything else works.

A workspace is the top-level container: billing, members, branding, API keys. A profile is one advertised business inside it — one set of ad accounts, one CRM, one tracker, one attribution answer. Every profile-scoped route on this API answers for one profile.

Most businesses need one workspace and one profile. An agency needs one workspace and a profile per client.

Creating them without a browser

Create a workspace
POST /api/v1/workspaces

Two unrelated ways to call it, sharing one URL — the same shape POST /api/v1/profiles uses.

  • Session bearer — a Supabase session token or an atb_user_… MCP token: you create your own workspace and become its owner. Body: {"name": "Acme", "timezone": "America/Santiago", "plan": "growth"}.
  • HTTP Basic — a registered consumer app creating a bare workspace for one of its users, identified by email. No profile and no delegation grant are created; follow with your own POST /api/v1/profiles.

plan defaults to starter (Free). growth / agency immediately write a trialing subscription at that plan's real limits rather than waiting for the first profile to bootstrap Free — so an agent that creates the workspace before its first POST /profiles does not silently sit on Free believing it asked for Growth. enterprise is sales-led and is not accepted here.

Safe to retry — the session branch is idempotent on (caller, name)

A retried call with the same name inside a short window returns the same workspace with created: false and 200, so a dropped connection never leaves two workspaces behind. Minutes later, the same name is a genuinely new workspace — a name is legitimately reusable. The app-credential branch has no idempotency at all: every call creates, and created is always true.

checkout — the plan you asked for, paid for in the same round trip

A growth or agency create returns a checkout hand-off alongside the new workspace, so an agent that knows which plan it wants never mints one separately:

201 Created — plan:
{
  "data": {
    "workspace_id": "…",
    "name": "Acme",
    "created": true,
    "checkout": {
      "id": "0f2f6b0a-9a2c-4f4e-9a1e-6f7f2a5c3b21",
      "url": "https://www.atribu.app/h/9tQ2mB1x…",
      "expires_at": "2026-09-05T11:30:00.000Z"
    }
  }
}

Hand checkout.url to the person who pays and poll GET /api/v1/handoffs/{id} — it is an ordinary checkout hand-off, the same object POST /api/v1/workspaces/{workspaceId}/checkout-session mints. See Billing.

Workspace creation is never blocked on billing

checkout is null for a starter request, and also null when the mint itself failed — unconfigured billing, or Stripe refusing — in which case the response still answers 201 and carries warnings: [{"code": "checkout_unavailable", "message": "…"}]. The workspace exists and created is still true: a payment link that could not be produced must not cost you the workspace you just made. Read warnings, then retry the mint alone with POST /api/v1/workspaces/{workspaceId}/checkout-session.

Two shapes to parse correctly: warnings is omitted, not an empty array, when nothing degraded — and an idempotent replay never mints a second checkout, so the created: false response carries checkout: null even for a growth request. Capture checkout from the call that actually created the workspace. checkout is always null on the app-credential branch.

Create a profile
POST /api/v1/profiles

POST /api/v1/profiles has two branches. The app-credential branch provisions a dealer end to end (see Partners & OAuth apps); the session branch is what a person or their agent uses for their own next client. A profile creation is refused with plan_limit_reached once the workspace's active_profiles allowance is spent — that limit is enforced on every creation path, so an agent that plans to create ten profiles should read the subscription first.

Retiring a workspace

Archive a workspace
DELETE /api/v1/workspaces/{workspaceId}

Owner only, and terminal — there is no un-archive. A workspace created by mistake, or a throwaway one an agent made while exploring, is retired with this call.

"Delete" means ARCHIVE, and the response says so. A workspace that has ever exported holds conversion_exports rows, and a database trigger refuses to let any path erase them — they are the record of what Atribu transmitted on your customers' behalf. So the call stamps archived_at, removes every membership, revokes pending invitations, archives every profile and purges its tracking, attribution and spend data, revokes the workspace's API keys and pauses its webhook subscriptions. What survived is in counts.retained_*.

200 OK
{
  "data": {
    "workspace_id": "873efefe-5fe0-44d5-8f67-0d3967855ff6",
    "archived": true,
    "archived_at": "2026-09-06T14:42:11.547Z",
    "counts": {
      "profiles_archived": 1,
      "memberships_removed": 1,
      "invitations_revoked": 0,
      "api_keys_revoked": 0,
      "webhook_subscriptions_paused": 0,
      "retained_conversion_exports": 1,
      "retained_signal_audit_rows": 3
    },
    "profiles_purged": 1
  },
  "meta": { "workspace_id": "873efefe-5fe0-44d5-8f67-0d3967855ff6" }
}

Safe to retry — idempotent, and both answers are 200

The first call returns archived: true. Every later call returns archived: false with the original archived_at and changes nothing. A DELETE that 404s an already-archived workspace would make a retry look like a failure.

A session bearer, or an atb_user_… token whose grant covers workspaces:write — a default mcp:read token is refused. An atb_live_ API key cannot call it: a key is minted for exactly one profile and belongs to no workspace. A member who is not an owner gets 403; a non-member gets 404, the same answer an unknown id gets, so the status code never confirms that a workspace exists.

After archiving, every workspace-scoped route answers 404 for it, it is absent from GET /api/v1/workspaces and from MCP whoami, and a pending invitation to it can no longer be accepted.

Reading what you can reach

GET /api/v1/workspaces is the right first call for a user credential: it needs no profile_id, and it tells you which workspaces the person behind the token belongs to. GET /api/v1/workspaces/{workspaceId}/profiles then lists the profiles inside one.

A user token must name a profile

An API key is one profile, so profile-scoped routes need no parameter. An atb_user_… token may reach several, so ?profile_id=<uuid> is required there — its absence is a 400, never a guess. See Authentication.

Everything under /workspaces

The workspace is also the grain for cross-profile analytics (Top Performers, creative patterns, experiments, pacing), for agency reporting, and for the admin surfaces a console needs. Those routes live under /workspaces/{id}/… because they are workspace-scoped, and they are explained where the feature is: Top Performers and creative reads, reports, credentials.

MethodPathWhat it does
POST/api/v1/invitations/acceptAccept a workspace or profile invitation
GET/api/v1/profilesList the profiles the signed-in user can reach in this workspace
POST/api/v1/profilesProvision a dealer (app-authenticated)
DELETE/api/v1/profiles/{profileId}Archive a profile you provisioned (app-authenticated)
POST/api/v1/profiles/{profileId}/adoptAdopt an existing profile (app-authenticated)
PUT/api/v1/profiles/{profileId}/entitlements/{feature}Set a profile's Atribu entitlement (app-authenticated)
POST/api/v1/profiles/demoCreate and seed this workspace's demo profile
DELETE/api/v1/profiles/demoDelete this workspace's demo profile
GET/api/v1/workspacesList the workspaces the signed-in user belongs to
POST/api/v1/workspacesCreate a workspace
DELETE/api/v1/workspaces/{workspaceId}Archive a workspace
GET/api/v1/workspaces/{workspaceId}/api-keysA profile's API keys
POST/api/v1/workspaces/{workspaceId}/api-keysMint a new API key for a profile
POST/api/v1/workspaces/{workspaceId}/api-keys/{id}/revokeRevoke one API key
POST/api/v1/workspaces/{workspaceId}/api-keys/{id}/rotateRotate one API key
GET/api/v1/workspaces/{workspaceId}/api-usagePer-key API usage for a workspace
GET/api/v1/workspaces/{workspaceId}/auditList recorded changes to a workspace's classification settings
POST/api/v1/workspaces/{workspaceId}/billing-portal-sessionOpen Stripe's Customer Portal for a workspace
GET/api/v1/workspaces/{workspaceId}/brandingThe workspace's report/email branding
PUT/api/v1/workspaces/{workspaceId}/brandingUpdate the workspace's branding (non-logo fields)
POST/api/v1/workspaces/{workspaceId}/branding/logoUpload the workspace's logo
DELETE/api/v1/workspaces/{workspaceId}/branding/logoRemove the workspace's logo
POST/api/v1/workspaces/{workspaceId}/checkout-sessionMint a Stripe Checkout hand-off for a plan upgrade
GET/api/v1/workspaces/{workspaceId}/compliance-overviewPer-profile privacy/HIPAA compliance posture
PATCH/api/v1/workspaces/{workspaceId}/compliance-overviewSet whether this workspace is a healthcare agency
GET/api/v1/workspaces/{workspaceId}/connected-appsList OAuth-app authorizations across the workspace's profiles
DELETE/api/v1/workspaces/{workspaceId}/connected-apps/{id}Revoke an OAuth-app authorization
GET/api/v1/workspaces/{workspaceId}/creative-archetypesThe workspace's creative archetypes and how often each one wins
GET/api/v1/workspaces/{workspaceId}/creative-patternsCross-profile creative patterns, and who is not running them
GET/api/v1/workspaces/{workspaceId}/creative-patterns/dimensionsWhich single creative-dimension values win in this workspace
POST/api/v1/workspaces/{workspaceId}/creative-tests/decisionsDismiss or draft one testing-roadmap gap
POST/api/v1/workspaces/{workspaceId}/customer-erasuresErase a customer's personal data
POST/api/v1/workspaces/{workspaceId}/experiment-promotionsRecord an ad's promotion to a Meta experiment
GET/api/v1/workspaces/{workspaceId}/experimentsMeta lift and split studies across the workspace's profiles
GET/api/v1/workspaces/{workspaceId}/invitationsList pending workspace invitations
POST/api/v1/workspaces/{workspaceId}/invitationsInvite someone to the workspace
DELETE/api/v1/workspaces/{workspaceId}/invitations/{invitationId}Revoke a pending workspace invitation
GET/api/v1/workspaces/{workspaceId}/mcp-settingsGet the workspace's MCP data-plane settings
PUT/api/v1/workspaces/{workspaceId}/mcp-settingsUpdate the workspace's MCP data-plane settings
GET/api/v1/workspaces/{workspaceId}/mcp-writeback-auditsList the workspace's MCP write-back audit log
GET/api/v1/workspaces/{workspaceId}/membersList a provisioned workspace's members (app-authenticated)
PUT/api/v1/workspaces/{workspaceId}/membersAdd or update a workspace member (app-authenticated)
DELETE/api/v1/workspaces/{workspaceId}/members/{userId}Remove a workspace member (app-authenticated)
GET/api/v1/workspaces/{workspaceId}/oauth-appsOAuth apps this workspace administers, with their DPA state
POST/api/v1/workspaces/{workspaceId}/oauth-apps/{appId}/dpa/acceptAccept the DPA for every profile an OAuth app provisions
POST/api/v1/workspaces/{workspaceId}/oauth-apps/{appId}/dpa/withdrawWithdraw an OAuth app's DPA acceptance
GET/api/v1/workspaces/{workspaceId}/pacingMonth-to-date spend and outcomes against budget, per profile
GET/api/v1/workspaces/{workspaceId}/pii-access-logAudit access to this workspace's customer/visitor PII
GET/api/v1/workspaces/{workspaceId}/profilesList the profiles the signed-in user can open in a workspace
GET/api/v1/workspaces/{workspaceId}/profiles/{profileId}/invitationsPending invitations to one profile
POST/api/v1/workspaces/{workspaceId}/profiles/{profileId}/invitationsInvite someone to one profile
DELETE/api/v1/workspaces/{workspaceId}/profiles/{profileId}/invitations/{invitationId}Revoke a pending profile invitation
PATCH/api/v1/workspaces/{workspaceId}/profiles/{profileId}/members/{membershipId}Change a profile member's role or permissions
DELETE/api/v1/workspaces/{workspaceId}/profiles/{profileId}/members/{membershipId}Remove someone from a profile
GET/api/v1/workspaces/{workspaceId}/recommendationsOpen recommendations across every profile in the workspace
GET/api/v1/workspaces/{workspaceId}/replicate-runs/{runId}One Replicate run — a winning ad adapted for another profile
POST/api/v1/workspaces/{workspaceId}/replicate-runs/{runId}/handoffBind a finished Replicate run to the creative session it was handed to
GET/api/v1/workspaces/{workspaceId}/reporting-currencyThe currency this workspace's cross-profile totals are reported in
PATCH/api/v1/workspaces/{workspaceId}/reporting-currencySet the currency this workspace's cross-profile totals are reported in
POST/api/v1/workspaces/{workspaceId}/reports/bulk-generateGenerate (and optionally send) a report across many profiles
GET/api/v1/workspaces/{workspaceId}/reports/hubThe workspace Reports hub
POST/api/v1/workspaces/{workspaceId}/reports/schedules/bulkApply a schedule patch across many profiles
GET/api/v1/workspaces/{workspaceId}/sender-domainThe workspace's verified sending domain, if any
POST/api/v1/workspaces/{workspaceId}/sender-domainRegister a sending domain for this workspace
DELETE/api/v1/workspaces/{workspaceId}/sender-domainRemove the workspace's sending domain
POST/api/v1/workspaces/{workspaceId}/sender-domain/verifyRe-check DNS verification for the workspace's sending domain
POST/api/v1/workspaces/{workspaceId}/shopify-plan-selectionChoose a plan on a Shopify App Store workspace
GET/api/v1/workspaces/{workspaceId}/snapshotsList shared Top Performers snapshot links
POST/api/v1/workspaces/{workspaceId}/snapshotsCapture a shareable Top Performers snapshot
DELETE/api/v1/workspaces/{workspaceId}/snapshots/{snapshotId}Revoke a shared snapshot link early
GET/api/v1/workspaces/{workspaceId}/subscriptionThe workspace's current subscription — plan, status, period bounds
GET/api/v1/workspaces/{workspaceId}/tab-countsHow much is new on each console tab since you last opened it
GET/api/v1/workspaces/{workspaceId}/test-roadmapWhat each profile should test next, and how much creative it has to judge on
GET/api/v1/workspaces/{workspaceId}/top-performersThe workspace's top-performing ads, across every profile
GET/api/v1/workspaces/{workspaceId}/top-performers/briefThe six counters that summarise a workspace's leaderboard
POST/api/v1/workspaces/{workspaceId}/top-performers/chatAsk the Top Performers Copilot (streaming)

Generated from openapi.json. The full request and response schema for every operation is in the OpenAPI document.

Next steps

On this page