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
POST /api/v1/workspacesTwo 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 ownPOST /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:
{
"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.
POST /api/v1/profilesPOST /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.
| Method | Path | What it does |
|---|---|---|
POST | /api/v1/invitations/accept | Accept a workspace or profile invitation |
GET | /api/v1/profiles | List the profiles the signed-in user can reach in this workspace |
POST | /api/v1/profiles | Provision a dealer (app-authenticated) |
POST | /api/v1/profiles/demo | Create and seed this workspace's demo profile |
DELETE | /api/v1/profiles/demo | Delete this workspace's demo profile |
GET | /api/v1/workspaces | List the workspaces the signed-in user belongs to |
POST | /api/v1/workspaces | Create a workspace |
GET | /api/v1/workspaces/{workspaceId}/api-keys | A profile's API keys |
POST | /api/v1/workspaces/{workspaceId}/api-keys | Mint a new API key for a profile |
POST | /api/v1/workspaces/{workspaceId}/api-keys/{id}/revoke | Revoke one API key |
POST | /api/v1/workspaces/{workspaceId}/api-keys/{id}/rotate | Rotate one API key |
GET | /api/v1/workspaces/{workspaceId}/audit | List recorded changes to a workspace's classification settings |
GET | /api/v1/workspaces/{workspaceId}/branding | The workspace's report/email branding |
PUT | /api/v1/workspaces/{workspaceId}/branding | Update the workspace's branding (non-logo fields) |
POST | /api/v1/workspaces/{workspaceId}/branding/logo | Upload the workspace's logo |
DELETE | /api/v1/workspaces/{workspaceId}/branding/logo | Remove the workspace's logo |
POST | /api/v1/workspaces/{workspaceId}/checkout-session | Mint a Stripe Checkout hand-off for a plan upgrade |
GET | /api/v1/workspaces/{workspaceId}/compliance-overview | Per-profile privacy/HIPAA compliance posture |
PATCH | /api/v1/workspaces/{workspaceId}/compliance-overview | Set whether this workspace is a healthcare agency |
GET | /api/v1/workspaces/{workspaceId}/connected-apps | List 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-archetypes | The workspace's creative archetypes and how often each one wins |
GET | /api/v1/workspaces/{workspaceId}/creative-patterns | Cross-profile creative patterns, and who is not running them |
GET | /api/v1/workspaces/{workspaceId}/creative-patterns/dimensions | Which single creative-dimension values win in this workspace |
POST | /api/v1/workspaces/{workspaceId}/creative-tests/decisions | Dismiss or draft one testing-roadmap gap |
POST | /api/v1/workspaces/{workspaceId}/experiment-promotions | Record an ad's promotion to a Meta experiment |
GET | /api/v1/workspaces/{workspaceId}/experiments | Meta lift and split studies across the workspace's profiles |
GET | /api/v1/workspaces/{workspaceId}/invitations | List pending workspace invitations |
POST | /api/v1/workspaces/{workspaceId}/invitations | Invite someone to the workspace |
DELETE | /api/v1/workspaces/{workspaceId}/invitations/{invitationId} | Revoke a pending workspace invitation |
GET | /api/v1/workspaces/{workspaceId}/mcp-settings | Get the workspace's MCP data-plane settings |
PUT | /api/v1/workspaces/{workspaceId}/mcp-settings | Update the workspace's MCP data-plane settings |
GET | /api/v1/workspaces/{workspaceId}/mcp-writeback-audits | List the workspace's MCP write-back audit log |
GET | /api/v1/workspaces/{workspaceId}/pacing | Month-to-date spend and outcomes against budget, per profile |
GET | /api/v1/workspaces/{workspaceId}/pii-access-log | Audit access to this workspace's customer/visitor PII |
GET | /api/v1/workspaces/{workspaceId}/profiles | List the profiles the signed-in user can open in a workspace |
GET | /api/v1/workspaces/{workspaceId}/recommendations | Open 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-generate | Generate (and optionally send) a report across many profiles |
GET | /api/v1/workspaces/{workspaceId}/reports/hub | The workspace Reports hub |
POST | /api/v1/workspaces/{workspaceId}/reports/schedules/bulk | Apply a schedule patch across many profiles |
GET | /api/v1/workspaces/{workspaceId}/sender-domain | The workspace's verified sending domain, if any |
POST | /api/v1/workspaces/{workspaceId}/sender-domain | Register a sending domain for this workspace |
DELETE | /api/v1/workspaces/{workspaceId}/sender-domain | Remove the workspace's sending domain |
POST | /api/v1/workspaces/{workspaceId}/sender-domain/verify | Re-check DNS verification for the workspace's sending domain |
GET | /api/v1/workspaces/{workspaceId}/snapshots | List shared Top Performers snapshot links |
POST | /api/v1/workspaces/{workspaceId}/snapshots | Capture a shareable Top Performers snapshot |
DELETE | /api/v1/workspaces/{workspaceId}/snapshots/{snapshotId} | Revoke a shared snapshot link early |
GET | /api/v1/workspaces/{workspaceId}/subscription | The workspace's current subscription — plan, status, period bounds |
GET | /api/v1/workspaces/{workspaceId}/tab-counts | How much is new on each console tab since you last opened it |
GET | /api/v1/workspaces/{workspaceId}/test-roadmap | What each profile should test next, and how much creative it has to judge on |
GET | /api/v1/workspaces/{workspaceId}/top-performers | The workspace's top-performing ads, across every profile |
GET | /api/v1/workspaces/{workspaceId}/top-performers/brief | The 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.