Authentication

Overview

Delivr.ai data APIs (events, audiences, taxonomy, identity lookup) authenticate with an API key + secret pair, created from the dashboard. A key is scoped either to your whole organization or to a single project; see Project-scoped API keys.

X-Api-Key: dlvr_...
X-Api-Secret: ...

There is one supported way to create keys: the dashboard at https://app.delivr.ai/{org_id}/settings/api-keys. The dashboard is the only place that displays the secret half. We do not recommend (and are phasing out) JWT-based programmatic key creation.

First time here? Your Delivr contact (sales or support) creates the organization and invites your first user(s). Once you accept the invite and sign in to app.delivr.ai, everything from API keys to project settings to inviting teammates is self-serve.

Base URL: https://api.delivr.ai


Create your API key in the dashboard

The fastest, safest way to get a working key + secret pair is to create one through the UI.

  1. Sign in at app.delivr.ai and switch to the organization you want the key to belong to.

  2. Open Settings > API keys. The direct link is https://app.delivr.ai/{org_id}/settings/api-keys (replace {org_id} with your organization ID).

  3. Click Create key and give it a descriptive name (for example, "Production export job" or "Hubspot sync"). Under Scope, keep Organization (every project), or choose one project to create a project-scoped key.

  4. In the confirmation dialog, copy both values into your secrets manager before closing it:

    ValueFormatWhere to use it
    api_keydlvr_ prefixX-Api-Key header on every request
    api_secrethex stringX-Api-Secret header on every request

The full api_secret is shown once, at creation time. If you close the dialog without saving it, you'll need to delete the key from the same page and create a new one. The list view shows only the key prefix; it cannot reveal the secret again.

An organization key reaches every project in the organization that owns it; a project-scoped key reaches one project. Anyone with both halves can call the API with that scope, so treat the pair like a password: rotate on suspected leak, never commit either value to source control. Use the Revoke action in the same dashboard page to retire a key.


Make your first authenticated request

Once you have the pair, every request to api.delivr.ai carries both headers. The two-header pattern works on every data endpoint (events, audiences, taxonomy, identity lookup).

curl "https://api.delivr.ai/api/v3/events_schema?source=pixel" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Api-Secret: YOUR_API_SECRET"

Response (200 OK)

{
  "fields": [
    { "name": "event_id", "data_type": "Utf8", "nullable": false },
    { "name": "event_type", "data_type": "Utf8", "nullable": false },
    { "name": "ts_millis", "data_type": "Int64", "nullable": false },
    { "name": "resolved", "data_type": "Boolean", "nullable": true }
  ]
}

If you see 401 {"error":"Invalid API key"}, double-check that you copied the full dlvr_-prefixed value. If you see 401 {"error":"Invalid API secret"}, the secret half does not match the key on file. Create a new pair from the dashboard.


Why both halves matter

A leaked api_key on its own is not enough to call the API. The platform compares the supplied api_secret against a stored hash on every request, in constant time, and rejects mismatches with 401. Pair-based auth means:

  • You can rotate the secret without re-issuing the key (less downstream config churn).
  • Keys can be safely surfaced in logs or dashboards; the secret stays out of those code paths.
  • Per-key access logs show exactly which credential made each call.

If your organization has secret_required enabled (default for new keys), a request that omits X-Api-Secret is rejected with 401 {"error":"API secret is required"}. Older keys may still accept secret-less calls during migration, but every new integration should send both headers.


Per-endpoint headers

This table describes an organization key. A project-scoped key reaches fewer of these, and only for its own project; see Project-scoped API keys.

APIRequired headersNotes
Events (/api/v3/events/{tier})X-Api-Key, X-Api-SecretThe tier route fixes both the billing tier and the identity fields returned. Scope with source plus pixel_id, project_id, or campaign_id. See Events API v3.
Audiences (/api/v1/audiences*)X-Api-Key, X-Api-SecretName the project with the X-Project-Id header or a ?project_id= query param (equivalent); required for create/list/sample.
Taxonomy (/api/v1/taxonomy/*)X-Api-Key, X-Api-SecretRead-only across the org.
Identity (/api/v1/lookup)X-Api-Key, X-Api-SecretHEM/email resolution.
Organization (/api/v1/organization)X-Api-Key, X-Api-SecretGET to read, PUT to update, or DELETE to remove your own organization.
Organization members (/api/v1/organization/user*)X-Api-Key, X-Api-SecretCreate/list/retrieve/update/delete members of the key's organization.
Project management (/api/v1/project*)X-Api-Key, X-Api-SecretCreate/list/retrieve/update/delete projects in the key's org. Create and list need no project id; retrieve is GET /api/v1/project/retrieve/{project_id}; update and delete take project_id in the body. A project outside the key's org is rejected.
Project members (/api/v1/project/user*)X-Api-Key, X-Api-SecretManage members of a project. Name the target project with a project_id field (writes) or ?project_id= (reads); the project must belong to the key's org.
Pixel management (/api/v1/pixel*)X-Api-Key, X-Api-SecretCreate/list/retrieve/update/delete pixels. Name the target project with a project_id field (writes) or a ?project_id= query parameter (reads).

Project-scoped API keys

A project-scoped key is bound to one project when you create it. It uses the same X-Api-Key and X-Api-Secret headers as an organization key, but it reads and writes only its own project's data. Use one to give a client, a team, or a single integration access to one project without exposing the rest of your organization. If you run projects for several clients, issue one key per client.

Create one

In Settings > API keys, click Create key and choose a project under Scope. A project admin creating a key from inside their project gets a key bound to that project; the scope selector is not shown.

The scope is fixed at creation. To change it, revoke the key and create another.

What a project key confines

  • Naming another project, or a pixel, campaign or record that belongs to another project, is refused. The status code depends on the API; see the table below.
  • An endpoint a project key cannot use answers 403, with a message saying the endpoint is not available to a project-scoped API key.
  • Usage on the events API, identity lookup, the intent API and audience downloads is attributed to the key's project.
  • A project key is held to its project's budget as well as your organization's, on every route that bills. When the organization's budget refuses a project key, the 402 omits the organization's spend and budget figures. See Project budgets.

Where a project key works

APIRoutesWith a project key
Events/api/v3/events/{tier}, /api/v3/events/{tier}/visitors and /api/v3/events/{tier}/schema, /api/v3/events_schema, /api/v1/events, /api/v1/event_countsA request scoped to the organization reads only the key's project. Another project's project_id returns 404 (project not found), another project's pixel 404 (pixel not found), and another project's DSP campaign 404 (campaign not found). The visitors route needs project_id or pixel_id, which must be the key's own.
Identity lookup/api/v1/lookup, /api/v1/lookup/batchSame as an organization key: lookup takes no project.
Audiences/api/v1/audiences*Name the project as usual (X-Project-Id or ?project_id=, required). It must be the key's project; any other returns 403 (access denied). Cloning an audience into another project is refused with 403 too. The audience schema and the audience template catalog work as they do for an organization key.
Audience usageGET /api/v1/audiences/linkage-usageThe key's project only; any other returns 403 (project_id does not match API key scope).
Intent/api/v1/intent/*Same as an organization key: intent data belongs to no project. An audience_id on /api/v1/intent/people must belong to your organization.
Intent topic stats/api/v1/stats/tables/intent-daily-stats, /api/v1/stats/tables/intent-daily-per-topic-statsSame as an organization key: topic-level data.
Taxonomy/api/v1/taxonomy/*Same as an organization key: a shared vocabulary.
Field catalog/api/v1/field-catalog*Same as an organization key: a shared catalog.
Lists, exports, integrations, campaigns/api/v1/lists*, /api/v1/exports*, /api/v1/integrations*, /api/v1/campaigns*A request without project_id is answered for the key's project. Another project's project_id returns 403 (project_id does not match API key scope). The campaign_id and audience_id filters return 403. A record in another project, requested by id, returns 404.
Resolution statisticsGET /api/v1/resolution/statisticsThe key's project only.
Billing usageGET /api/v1/billing/usage, /api/v1/billing/usage/by-meter, /api/v1/billing/usage/daily-by-meterUsage for the key's project only.
Contact queryPOST /api/v1/contact/querySame as an organization key.
Who am IGET /api/v1/whoamiLists only the key's project.
Pixels/api/v1/pixel*Pixels in the key's project only. Name the project as usual; another project returns 401.
Your projectGET /api/v1/project/retrieve/{project_id}, PUT /api/v1/project/updateThe key's own project only; another returns 401.

Not available to a project key (403): the organization itself (/api/v1/organization), organization members (/api/v1/organization/user*), creating, listing and deleting projects, and project members (/api/v1/project/user*). Use an organization key for these.


A note on legacy auth methods

If you have older integrations that use a JWT (obtained from POST /auth/v1/login with an email and password) or use only the X-Api-Key header without a secret, those continue to work for now. Both patterns are on the deprecation path. Move them to dashboard-created key + secret pairs at your next maintenance window. We will publish a removal timeline before disabling either path.


Next steps


Did this page help you?