Skip to content

Authentication and API keys ​

Every API route authenticates with an API key. The key carries your account and its permissions (scopes); you never have to say which client you are, and you cannot point at another one.

Getting a key ​

You create your keys yourself in the app, under Settings → Settings → API keys. Only the account owner and its administrators can create or revoke a key; other members see the list. Paid tiers only: on the Discovery plan, creation is refused (plan_free_no_api).

  1. Name the key (for example "Looker Studio" or "warehouse sync"), tick the scopes the integration needs, and pick an expiry: never, 90 days or 1 year.
  2. The key is shown exactly once. Only its SHA-256 hash is stored: DURUM cannot show it to you again. Keep it in a secrets manager.
  3. To revoke a key, use the Revoke button on the same page. A revoked or expired key answers 401 immediately.

A key only sees the account it was created on. No API parameter can point at another account, and every response is checked before it leaves: a row that did not belong to your account blocks the whole response (500 tenant_barrier).

Key format ​

A key always starts with durum_sk_live_, followed by 32 random characters (base64url alphabet). Example shape: durum_sk_live_Ab3dEf…. The first eight characters after the prefix act as a readable identifier (the "prefix") in exchanges with your account manager: they let you name a key without ever writing it out in full.

Using the key ​

Pass the key in the Authorization header with the Bearer scheme:

bash
curl "https://app.durum.ai/api/v1/dashboard/kpis" \
  -H "Authorization: Bearer durum_sk_live_YOUR_KEY"

The x-api-key: durum_sk_live_YOUR_KEY header is also accepted. When both are present, Authorization is read first.

Never expose the key in a browser

The API accepts requests from any origin (open CORS): the key is the only protection. Call the API from a server, a script or a BI tool, never from code your visitors can see.

Scopes ​

A key only reaches the scopes it carries. Each route requires exactly one scope; without it, the response is 403.

Read scopes ​

ScopeGrants access to
read:dashboardaggregated KPIs, daily series, breakdowns
read:adsspend per ad and per campaign, ad rules and run history
read:attributionmulti-touch attribution, capture health, attribution report
read:eventsCRM events (leads, bookings, sales, payments, cancellations) and their summary
read:salessales summary, per-rep performance, sales cycle
read:financeP&L and revenue (margins stripped)
read:funnelfunnel and conversion
read:contactscontacts, customers, purchases
read:callsa contact's calls, call list, transcript, recording
read:journeyscustomer journeys, one contact's journey, touchpoint feed
read:creativespending creative needs
read:icpICP criteria
read:capiconnected Meta pixels (without tokens)

Write scopes ​

They are never granted by default: request them explicitly.

ScopeAllows
write:goalsreplace your KPI goals
write:settingsset your sale counting rule
write:icpset your ICP criteria
write:adsenable, disable, switch to dry-run or delete an ad rule
write:creativesget an upload authorization for a visual, import a creative into the reserve, acknowledge creative needs

Global scope ​

The * scope grants all scopes, read and write. It is only issued on a justified request.

Rate limit ​

  • 600 requests per minute per key, counted in fixed 60-second windows.
  • Every response carries the X-RateLimit-Limit (600) and X-RateLimit-Remaining (requests left in the current window) headers.
  • Beyond that, the response is 429 with retry_after_seconds: 60.
  • Failed authentications are also throttled per IP address: past 20 401 responses in one minute, the answer is 429 with too_many_failed_attempts for the rest of the minute.

Access log ​

Every authenticated request is logged by DURUM: key identifier, method, path, required scope, response code, IP address and timestamp. Each key's last-used date is updated as well. The log serves security audits; it is not readable through the API.

Authentication and access errors ​

CodeJSON bodyCause
401{ "error": "invalid_or_missing_api_key" }header missing, key malformed, unknown, revoked or expired
403{ "error": "insufficient_scope", "required": "read:calls" }the key lacks the required scope (required says which one)
403{ "error": "plan_free_no_api" }the workspace is on the Discovery plan: the REST API and the MCP server require a paid tier
403{ "error": "forbidden" }the requested resource (for example a call) does not belong to your account
429{ "error": "rate_limited", "retry_after_seconds": 60 }rate limit exceeded
429{ "error": "too_many_failed_attempts", "retry_after_seconds": 60 }too many failed authentications from your IP address
500{ "error": "tenant_barrier" }the response was blocked by the account check; contact DURUM

The other codes (400, 404, 405, 502) are described in the API reference.

Powered by DURUM.ai: ad attribution and operational intelligence