Skip to main content

api_keys

GET /projects/{project_id}/api-keys​

List a project's API keys

Cursor-paginated key list (003 §1). Shows only the lookup prefix — never plaintext or hash. Sessions need org role admin or above; API keys need the admin scope and can list only their own project, and only the keys of their own environment (a key holds exactly one project + environment, 003 §2); sessions list both environments' keys. The default representation omits name even for named keys, preserving strict legacy clients. Explicit include_name=true opts into names; retain this option on subsequent cursor requests.

Operation ID: listApiKeys · Service: gateway-api

Authentication​

  • apiKey (http (bearer)) — Project API key (003 §2): tsk_live_… or tsk_test_… in Authorization: Bearer. Scoped to exactly one project + environment; scopes are a subset of ingest, read, admin. Keys are stored hashed and shown once at creation.
  • consoleSession (http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls add X-Tessera-Project + X-Tessera-Environment headers, validated against org membership.

Parameters​

NameInRequiredTypeDescription
project_idpathyesstringProject id (proj_ ULID).
cursorquerynostringOpaque pagination cursor from a previous response's next_cursor.
include_namequerynobooleanExplicitly opt into stored integration names. Omitted or false preserves the legacy representation without name. Unnamed keys omit name in both representations.
limitquerynointegerPage size (cursor pagination, 003 §1). Maximum 200.

Pagination​

Cursor pagination (003 §1): pass limit (max 200) and cursor; the response is the pagination envelope — data plus next_cursor (null on the last page).

Responses​

StatusSchemaDescription
200ApiKeyPagePage of API keys.
defaultErrorEnvelopeError response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying.

POST /projects/{project_id}/api-keys​

Create an API key

Mints a key for one environment (003 §2): secret keys are tsk_\{env\}_…, publishable keys tpk_\{env\}_…. The plaintext appears exactly once, in this response. Secret keys must declare scopes (subset of ingest, read, admin); publishable keys are forced to exactly ["ingest"] and may carry allowed_origins (enforced by browser ingestion in Phase 2, WP-S6). Requires org role admin or above. Console sessions only.

Operation ID: createApiKey · Service: gateway-api

Authentication​

  • consoleSession (http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls add X-Tessera-Project + X-Tessera-Environment headers, validated against org membership.

Parameters​

NameInRequiredTypeDescription
Idempotency-KeyheadernostringIdempotency key accepted by all POSTs (003 §1): 24 h dedup window, keyed per project. POSTs that are reads (batchSlotScores, scoreSlotEvent, deriveSlotBands, validateSourceRawPreset, sampleSource, watchEventFeedHeads and the preview operations: previewSourceMapping, previewCatalogMapping, previewLabel, previewPatternLabel, previewMarker, previewDatasetEligibility, previewSlotAudience, previewSharedCheckpointImport, previewSlotAtlasInquiry) accept the key but never replay a stored response: a retry with the same key is executed again (and metered again) against current data. A stored response that names an entity is removed when that entity is erased. A key that already answered answers only a retry of the request that stored its response: the same caller, environment, operation, path, query, scoping headers and body (a JSON body by its content, a gzip body by its inflated content). The same key with any other request is 409 already_exists with details[0].reason idempotency_key_reused, and that request is not run. The window holds no in-flight marker: two first requests sent at once can both run. A response stored by a release before this rule cannot be matched to its request and is refused the same way until it expires; send the request again with a new key. A body over 8 MiB (ingest: over its 5 MiB request limit) is run and its response is not stored. The ingest batch (POST /events) is the exception, except for an application's credentials: under a key that answered another batch it runs again, uncached, and its events' ids deduplicate them; so it does when its stored response cannot be checked. The operations that return a one-time secret store their response sealed: the stored copy opens only for the same key and credential, and one that cannot be opened is 409 idempotency_key_reused. While the server cannot check a stored response (it cannot read the key that checks it, for one), the request is 503 unavailable with Retry-After: retry with the same key. An operation whose handler claims the key itself answers the same 503, before it runs, while the key-hash pepper cannot be read; any other request sent with a key runs meanwhile, and its response is not stored.
project_idpathyesstringProject id (proj_ ULID).

Idempotency​

This operation accepts an Idempotency-Key header (003 §1): within 24 hours, keyed per project and caller, a retry of the same request gets the first response, and the same key with another request is 409 already_exists (idempotency_key_reused). See the Idempotency-Key parameter for the exceptions.

Request body​

ApiKeyCreateRequest

Responses​

StatusSchemaDescription
201ApiKeyWithSecretThe created key, including the one-time plaintext.
defaultErrorEnvelopeError response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying.

DELETE /projects/{project_id}/api-keys/{key_id}​

Revoke an API key

Revocation is permanent; authenticated calls with the key fail with 401 unauthenticated within 5 seconds (WP-A2 req 7). Requires org role admin or above. Console sessions only.

Operation ID: revokeApiKey · Service: gateway-api

Authentication​

  • consoleSession (http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls add X-Tessera-Project + X-Tessera-Environment headers, validated against org membership.

Parameters​

NameInRequiredTypeDescription
key_idpathyesstringAPI key id (key_ ULID).
project_idpathyesstringProject id (proj_ ULID).

Responses​

StatusSchemaDescription
204—Key revoked (idempotent).
defaultErrorEnvelopeError response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying.

GET /projects/{project_id}/api-keys/{key_id}/purposes​

Get an API key's purpose allow-list

The key's purpose allow-list (WP-V12 req 8). purposes: null means unrestricted, the default for every key. Additive to the closed ApiKey record, which never carries purposes. A revoked or foreign key is 404 not_found. Requires org role admin or above. Console sessions only.

Operation ID: getApiKeyPurposes · Service: gateway-api

Authentication​

  • consoleSession (http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls add X-Tessera-Project + X-Tessera-Environment headers, validated against org membership.

Parameters​

NameInRequiredTypeDescription
key_idpathyesstringAPI key id (key_ ULID).
project_idpathyesstringProject id (proj_ ULID).

Responses​

StatusSchemaDescription
200PrincipalPurposesThe key's purpose allow-list.
defaultErrorEnvelopeError response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying.

PUT /projects/{project_id}/api-keys/{key_id}/purposes​

Replace an API key's purpose allow-list

Replaces the key's allow-list (WP-V12 req 8): null lifts the restriction; a list names 1–16 unique purposes registered in the key's project (GET /v1/purposes). Unregistered, malformed, reserved or duplicate names and unknown fields are 400 invalid_argument naming the offending purposes. Once restricted, every output path whose effective purpose (destination or export declared purpose, else the slot purpose, else general) is outside the list answers 403 permission_denied with details[0].reason purpose_not_allowed and details[0].purpose. The listed purposes pin the registry (purpose_referenced) while the key is live. The change and its api_key.purposes.update audit record commit in one transaction; an unchanged list writes nothing. Takes effect within 5 seconds. Requires org role admin or above. Console sessions only.

Operation ID: putApiKeyPurposes · Service: gateway-api

Authentication​

  • consoleSession (http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls add X-Tessera-Project + X-Tessera-Environment headers, validated against org membership.

Parameters​

NameInRequiredTypeDescription
key_idpathyesstringAPI key id (key_ ULID).
project_idpathyesstringProject id (proj_ ULID).

Request body​

PrincipalPurposes

Responses​

StatusSchemaDescription
200PrincipalPurposesThe stored allow-list.
defaultErrorEnvelopeError response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying.

Errors​

Every non-2xx response uses the 003 §1 error envelope; error.request_id matches the X-Request-Id response header, and the HTTP status always matches error.code:

{
"error": {
"code": "invalid_argument",
"details": [
{
"type": "field_violation"
}
],
"message": "human-readable",
"request_id": "req_01hxample"
}
}

Closed error-code set (003 §1): invalid_argument, unauthenticated, permission_denied, not_found, already_exists, failed_precondition, resource_exhausted, internal, unavailable.

resource_exhausted responses (HTTP 429) additionally carry retry_after_seconds. See ErrorEnvelope.