API Overview & Authentication
Base URLs, request format, and the three ways to authenticate with the Intempt API: JWT bearer tokens, API keys, and SCIM bearer tokens.
API Overview & Authentication
The Intempt Platform API is versioned under /v1 and served from a single origin per environment. There's no separate auth.intempt.com host: that string only appears as the iss claim inside issued JWTs.
Base URLs
| Environment | Base URL |
|---|---|
| Production | https://api.intempt.com |
| Staging | https://api.staging.intempt.com |
| Local development (auth service) | http://localhost:8090 |
Authentication schemes
| Scheme | Header | Used for |
|---|---|---|
| JWT bearer | Authorization: Bearer <jwt> | Console and CLI sessions. Required on nearly every /v1/** endpoint. |
| API key | Authorization: Bearer <api_key> | Server-to-server integrations calling the platform API. Issued and managed via /v1/{orgName}/api-keys. |
| SCIM bearer token | Authorization: Bearer <scim_token> | SCIM 2.0 provisioning at /scim/v2/{slug}/*, called by an identity provider, not by application code. |
| None (public) | None | OAuth/OIDC endpoints, .well-known discovery, OTP send/verify, passkey authentication, SSO callbacks (/sso/**), and public invite/share links. |
📘 Good to know
/v1/auth/otp/*, /v1/auth/mfa/challenge/verify, and /v1/auth/passkeys/authenticate/* are public endpoints. The OTP code, challenge token, or WebAuthn assertion in the request body is the proof of identity, so no bearer token is sent.
JWT bearer tokens
JWTs are issued by the token endpoint, POST /oauth/token, using one of three grant types:
| Grant type | Used for |
|---|---|
authorization_code | Exchanging a code from a completed login (OTP, social, or passkey) for tokens. Requires a PKCE code_verifier. |
refresh_token | Getting a new access token without a full login. |
urn:ietf:params:oauth:grant-type:device_code | CLI or headless devices completing the device code flow. |
The token response:
| Field | Type | Description |
|---|---|---|
access_token | string | RS256 JWT, signed by the auth service. |
refresh_token | string | Opaque token used to get a new access token. Valid for 12 hours. |
token_type | string | Always Bearer. |
expires_in | integer | Access token lifetime in seconds (900). |
📘 Good to know
Refresh tokens are single-use: exchanging one issues a new one and invalidates the old one. If a used-up refresh token is presented again, the auth service treats it as a replay and revokes the whole session.
Verify a JWT's signature against the public key set at GET /.well-known/jwks.json.
API keys
API keys are managed at the organization level.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/{orgName}/api-keys | List API keys |
| POST | /v1/{orgName}/api-keys | Create an API key |
| PATCH | /v1/{orgName}/api-keys/{keyId} | Update an API key's name or project assignments |
| PATCH | /v1/{orgName}/api-keys/{keyId}/active | Enable or disable an API key |
| POST | /v1/{orgName}/api-keys/{keyId}/regenerate | Rotate an API key's secret |
| DELETE | /v1/{orgName}/api-keys/{keyId} | Delete an API key |
Creating a key requires a name and a level (admin, public, or private), and accepts an optional projectIds array to scope the key to specific projects.
Each key in a list response has these fields:
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Key identifier |
name | string | Label you gave the key |
level | string | One of admin, public, private |
projectIds | array of integer | Projects the key is scoped to |
prefix | string | Non-secret identifier used to tell keys apart in a list |
createdAt | string (date-time) | Creation timestamp |
lastUsedAt | string (date-time) | Last time the key authenticated a request |
active | boolean | Whether the key currently authenticates requests |
The full key value is only ever returned once: in the response to POST /v1/{orgName}/api-keys (as fullKey) and again if you regenerate it (as newFullKey from POST /v1/{orgName}/api-keys/{keyId}/regenerate). Store it when you create or regenerate it. Regenerating replaces the secret but keeps the key's name, level, and project assignments.
SCIM bearer tokens
SCIM 2.0 endpoints at /scim/v2/{slug}/* authenticate with a static bearer token, not a JWT, because identity providers like Okta and Azure AD only support static bearer tokens for SCIM outbound connections. SCIM tokens are SHA-256 hashed at rest.
Use cases
- A frontend app tracking events in the browser. Use a public API key. It's designed to be visible in client-side code.
- A backend job syncing data on a schedule. Use a private API key, kept out of any client-side code.
- A script that manages keys or projects across your whole org. Use an admin API key.
- The Intempt console or CLI. Use a JWT obtained through a real login (OTP, social, or passkey), not an API key. A JWT represents a signed-in person.
- A CLI or device with no browser available. Use the device code grant to get a JWT without a redirect-based login.
- A long-running session that shouldn't force a re-login. Exchange the refresh token at
/oauth/tokeninstead of starting the login flow over. - Connecting an identity provider, like Okta or Azure AD, for user provisioning. Use a SCIM bearer token, generated separately from any API key or JWT.
- A key you suspect is compromised. Regenerate it rather than deleting and recreating it, so existing project assignments and the key's name stay intact.
Error responses
Failed requests return a JSON body:
| Field | Type | Description |
|---|---|---|
error | string | Machine-readable error code |
message | string | Human-readable description |
details | object | Additional context (optional) |
Some endpoints apply their own limits on top of standard auth checks. For example, POST /v1/auth/otp/send returns 429 if you request more than 3 codes per minute for the same email.
Where to go next
- API keys for creating, revealing, and rotating keys from Org Settings.
- How Intempt works for how authenticated requests fit into the wider tracking model.
- JavaScript SDK for the client-side reference that uses a public API key under the hood.
- Track Data API for the first endpoint most server-side integrations call after authenticating.
Asset Draft/Publish System
How saving works for content items in the Asset library: there's no separate draft state for most asset types, images land on the CDN as soon as they're generated or edited, and Brand Ads are the one type with an explicit publish step.
JavaScript SDK
Full API reference for IntemptJS — event tracking, user identification, consent, and product tracking in the browser.
