Skip to main content

events

POST /event-exports​

Export the committed event history

WP-D6. Starts an asynchronous export of every committed canonical event the store retains for the resolved project and environment, beyond the feed's retention, optionally filtered. Returns 202 with the EventExport record. Entities with an accepted deletion are never exported. A part holding an entity whose deletion is accepted later stops getting URLs at once and is rewritten without it. The record's deletions object lists every accepted deletion, so a copy rebuilt from the export can be erased by entity_hash. resume_cursor is a readEventFeed cursor: the export plus the feed read after it lose nothing. Rows committed while the export starts may appear in both; deduplicate on item_identity. At most 2 active exports per (project, environment); more is 429 resource_exhausted. Once the project's destructive purge has started, the request is 400 failed_precondition with EventExportRefusedDetail. Requires the read scope (or member for sessions) and, for purpose-restricted principals, the event-feed purpose. Honors Idempotency-Key.

Operation ID: createEventExport · Service: serving-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
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.

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​

EventExportRequest

Responses​

StatusSchemaDescription
202EventExportThe queued export.
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 /event-exports/{export_id}​

Get an event export

WP-D6. One event export. Each available part, and the deletions object, carries a V4-signed URL scoped to that single object, TTL 15 minutes, minted on every GET and never stored; re-read the record when it expires. A part holding an entity whose deletion was accepted reads rewriting, with no URL, until its next revision is available. Same authorization as readEventFeed.

Operation ID: getEventExport · Service: serving-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
export_idpathyesstringEvent export id (evx_ ULID).

Responses​

StatusSchemaDescription
200EventExportThe export record.
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 /event-feed​

Read the committed event feed

WP-D6. The resolved project's and environment's committed canonical events (every intake path) and data-subject deletion items, in feed order. Positions are dense within a feed_epoch. An item is appended only after its event is committed to the canonical store, and once a position is readable, every lower retained position is readable. Items never move. An event item only ever turns into event_redacted, when its entity's deletion is accepted. Read from after (an opaque cursor), or from start (oldest | now) when after is absent; giving both is 400 invalid_argument. limit is 1-500, and a page also stops at 4 MiB. When the read position is at the high watermark (always so for start=now), wait_seconds (0-20) long-polls for the next append. A forged or foreign cursor is 400 invalid_argument. An authentic cursor below the retention floor is 400 failed_precondition with EventFeedCursorExpiredDetail. One from an earlier epoch, or ahead of the head, is 400 failed_precondition with EventFeedResetDetail. From the start of the project's destructive purge until it completes, every page holds exactly one terminal project_purged item; after completion the read is 404. API keys are revoked at the deletion request, so a key-based reader gets 401 instead and must treat it as the loss of its binding. Tenancy comes only from the credential. Requires the read scope (or viewer for sessions) and, for purpose-restricted principals, the event-feed purpose. Metered as state_reads with quantity = items returned (002 §11).

Operation ID: readEventFeed · Service: serving-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
afterquerynostringOpaque cursor from next_cursor, high_watermark_cursor or retention_floor_cursor of an earlier page of this feed; the read returns positions strictly after it.
limitquerynointegerMaximum items returned (1-500).
startquerynostringWhere to begin when after is absent: oldest (the oldest retained item) or now (only items appended after the read). Defaults to oldest.
wait_secondsquerynointegerLong-poll bound. When the read position is at the high watermark, wait up to this many seconds for the next append before answering (0 = answer at once). Past the per-principal wait cap the read answers at once with Retry-After: 1.

Responses​

StatusSchemaDescription
200EventFeedPageOne page of feed items in position order.
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 /event-feed/heads:watch​

Watch the heads of every event feed an application may read

WP-D6 TG-08 (applications only). One parked request per application answers when ANY event feed the application may read moves, with positions only; the application then reads each feed that moved with readEventFeed from its own cursor. Coverage is exactly readEventFeed's admission of the creating application: every project the application and its organization created, in the environments of its registration, while the project is active, suspended or deleting until its purge completes. Entries of known outside the coverage are ignored. data holds the covered feeds whose feed_epoch or high_watermark_position differs from known, and covered feeds known lacks (feeds without items are not listed), ordered by project and environment, at most 500 per page; follow next_page_token until it is absent, merging each page into known. A changed head a page does not return stays due. A purge-fenced feed reports the position of its terminal project_purged item. When nothing differs, wait_seconds (0-20) long-polls for the next move. Each application may park 2 watches per serving replica; past that, or the replica's limit, the watch answers at once with Retry-After: 1. A watch covers at most 1,000 feeds; partition a larger coverage with shard (400 failed_precondition heads_scope_too_large otherwise, naming a sufficient shard_count). A next_page_token is good for 60 seconds. The request body is at most 128 KiB. A read with a body: safe to repeat, never stored in the Idempotency-Key response cache, answered Cache-Control: no-store. Not metered (the readEventFeed reads it leads to are). Requires, for purpose-restricted principals, the event-feed purpose.

Operation ID: watchEventFeedHeads · Service: serving-api

Authentication​

  • applicationToken (http (bearer)) — A registered partner application's Google-signed OIDC ID token (WP-A9): minted by the application's own workload identity with the environment's exact audience, and pinned on the service account's email and unique id. Only registered applications are accepted.

Idempotency​

This operation never replays a stored response (003 §1): a retry carrying the same Idempotency-Key runs again, against current data.

Request body​

EventFeedHeadsWatchRequest

Responses​

StatusSchemaDescription
200EventFeedHeadsPageThe covered feeds that moved (positions only).
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 /event-feed/stats​

Read per-source hourly event-feed counts

WP-D6. Exact counts of items appended to the resolved feed as event, per source_id and UTC hour of appended_at, with how many of them are now stored redacted, for reconciliation against items read. Hours ending at or before sealed_through are final. since is inclusive and until exclusive. Both are truncated to whole hours and at most 744 hours apart; the default is the 24 hours before the read. Rows are paginated per 003 §1 (limit ≤ 200). A cursor carries the resolved since, until and source_id of its first page; repeating them is optional, and differing values are 400 invalid_argument. Same authorization as readEventFeed. Metered as state_reads with quantity = rows returned.

Operation ID: getEventFeedStats · Service: serving-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
cursorquerynostringOpaque pagination cursor from a previous response's next_cursor.
limitquerynointegerPage size (cursor pagination, 003 §1). Maximum 200.
sincequerynostringInclusive lower bound (RFC 3339, truncated to the hour).
source_idquerynostringKeep only this source's rows.
untilquerynostringExclusive upper bound (RFC 3339, truncated to the hour).

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
200EventFeedStatsPer-source hourly counts, ordered by hour then source.
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 /events​

Ingest a batch of events

Ingests up to 500 canonical events (002 §2) in one batch (≤ 5 MiB; one event ≤ 64 KiB serialized). Per-item 207-style results (003 §5): every item is validated against https://spec.tessera.dev/schemas/event.json by THE tessera-core validator; invalid items are rejected individually with a field-precise message while valid items in the same batch are still accepted. Acceptance means a durable Pub/Sub publish acknowledgment on events.ingest — not contract validation (that happens in the stream router; violations park in the dead-letter store). The server sets the envelope (project_id, environment, source_id, received_at, ingest_id, canonical_entity_key); client-supplied values for these fields are rejected as invalid_argument. When event_id is absent it is derived as sha256(project_id, entity, event_type, timestamp, attributes_fingerprint) (002 §2) so retries are no-ops downstream. Requires an API key with the ingest scope (secret or publishable). Sustained per-key event-rate limits apply (resource_exhausted + retry_after_seconds + X-RateLimit-* headers, 003 §1). Event identity (002 §8): the ledger keys each event by its entity, its microsecond timestamp and the first 16 characters of event_id. Events for the same entity with the same microsecond timestamp must therefore differ in the first 16 characters of event_id; otherwise the later one is treated as a duplicate and is not stored as a new event. Choose ids that lead with high entropy (a UUIDv4, or a ULID with its random part first), not a shared fixed prefix such as order-2026-10- followed by the part that tells events apart. Platform-derived ids (when event_id is absent) are hash digests and already satisfy this. The first 16 characters of event_id must not contain #: such an item is rejected with invalid_argument ("event_id: must not contain '#' in its first 16 characters"); # later in the id is accepted. Entity ids must not contain # anywhere (it separates the segments of the storage keys): an item whose entity.id or a secondary_entities[].id contains # is rejected with invalid_argument ("entity.id: must not contain '#'", or "secondary_entities.{i}.id: must not contain '#'"). Entities stored before this rule keep reading, scoring and erasing. Publishable-key (tpk_) calls are origin-checked against the key's allowed_origins (WP-S6; see the events tag description for the full CORS contract): requests without an Origin header or from a non-allowlisted origin are rejected with permission_denied, and allowed origins are echoed back via Access-Control-Allow-Origin + Vary: Origin. Secret (tsk_) keys are unaffected by origin checks.

Operation ID: createEvents · Service: ingest-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.
  • publishableKey (http (bearer)) — Publishable key (003 §2): tpk_… in Authorization: Bearer. Client-side SDK event ingestion only (ingest scope, single project).

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.
keyquerynostringPublishable-key (tpk_…) authentication via query parameter — for the browser SDK's navigator.sendBeacon flush path only, because beacons cannot set an Authorization header (WP-S6). Accepted for publishable keys exclusively: a secret (tsk_…) key in a URL is refused with invalid_argument (secrets must never appear in URLs or access logs). Ignored when an Authorization header is present.

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​

EventBatchRequest

Responses​

StatusSchemaDescription
200EventBatchResultPer-item ingestion results (003 §5).
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 /events/deadletter​

List dead-letter items

Dead-letter items of the resolved project + environment (WP-S1), cursor-paginated (003 §1) and filterable by reason, event_type, entity_type and entity_id. Tenancy comes exclusively from the resolved credential — the store never returns another project's items. Requires the read scope (publishable keys are refused); sessions scope tenancy via X-Tessera-Project + X-Tessera-Environment. Purpose-restricted principals also need the event-feed purpose, named in their allow-list and registered in the project (403 permission_denied, reason purpose_not_allowed).

Operation ID: listDeadletterItems · Service: ingest-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
cursorquerynostringOpaque pagination cursor from a previous response's next_cursor.
entity_idquerynostringFilter by the embedded event's entity.id.
entity_typequerynostringFilter by the embedded event's entity.type.
event_typequerynostringFilter by the embedded event's event_type.
limitquerynointegerPage size (cursor pagination, 003 §1). Maximum 200.
reasonquerynostringFilter by dead-letter reason.

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
200DeadletterItemPagePage of dead-letter items, newest first.
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 /events/deadletter:discard​

Discard dead-letter items

Marks the selected items discarded (terminal: a discarded item can never be replayed). Selector: exactly one of dlt_ids | filter (both or neither fail 400 invalid_argument); explicitly listed items that are already discarded are refused with 400 failed_precondition, filter selection matches only parked items. Requires the admin scope (or an admin-role session).

Operation ID: discardDeadletterItems · Service: ingest-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
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.

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​

DeadletterSelector

Responses​

StatusSchemaDescription
200DeadletterDiscardResultDiscard result.
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 /events/deadletter:replay​

Replay dead-letter items

Republishes the selected items' original ingest messages to events.ingest, unchanged except envelope.replay_of = \{dlt_id\}; each replayed item's status becomes replayed and its replay_count increments (WP-S1 req 12). Selector: exactly one of dlt_ids | filter (both or neither fail 400 invalid_argument). Explicitly listed items that are discarded or have replay_count \>= 10 are refused with 400 failed_precondition; filter selection matches only replay-eligible parked items. Items with reason: schema_invalid are not replay-eligible (the producer resends a corrected event) unless their stored event carries a router_forwarded member: an accepted event the stream router did not finish within its delivery attempts (detail starts subscription_max_delivery_attempts:), republished with its original ordering key and attributes. Requires the admin scope (or an admin-role session).

Operation ID: replayDeadletterItems · Service: ingest-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
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.

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​

DeadletterSelector

Responses​

StatusSchemaDescription
202DeadletterReplayResultReplay accepted; matched items republished.
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.