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.

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)
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
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}/auditList recorded changes to a workspace's classification settings
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}/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}/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}/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}/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
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

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

Next steps

On this page