Skip to main content

uploads

POST /uploads​

Create a resumable upload session

Creates an upload session for one CSV or Parquet file (WP-C2 req 1) and returns a signed GCS resumable session URL targeting projects/\{project_id\}/uploads/\{upload_id\}/\{filename\} in the environment's data bucket. The client PUTs bytes directly to that URL (chunked, resumable) without transiting Tessera services; the session URI is bearer-scoped to the single object. upload_url is returned exactly once, here. Sessions expire 24 h after creation (req 2). source_id, when supplied, must reference an existing file_upload source in the resolved project + environment; when absent, a source is created at completion (req 3). The object path and session row are always constructed from the resolved tenancy, never from request-supplied ids (003 §3).

Operation ID: createUpload · 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
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​

UploadCreateRequest

Responses​

StatusSchemaDescription
201UploadSessionThe created upload session, including the one-time upload_url.
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 /uploads/{upload_id}​

Get an upload session

Upload session status. upload_url is never returned again after creation. After completion the payload includes the schema preview (WP-C2 req 6): columns ([\{name, inferred_type\}]) and up to 20 sample rows (values truncated to 256 chars), derived from the landed snapshot's profile.json and sample — enough for the console to configure a mapping without another scan of the uploaded file. A session past its 24 h expiry reads as status: expired. For a purpose-restricted principal without the event-feed purpose (named in its allow-list and registered in the project), columns and sample_rows are null.

Operation ID: getUpload · 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
upload_idpathyesstringUpload session id (upl_ ULID).

Responses​

StatusSchemaDescription
200UploadSessionThe upload session.
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 /uploads/{upload_id}:complete​

Finalize an upload

Finalizes an upload session (WP-C2 req 3): verifies the object exists (else 400 failed_precondition), is ≤ 50 GiB (larger ⇒ 400 invalid_argument with the observed size in details), records the object's size and GCS integrity metadata (it never reads the whole object: the 002 §10 file_fingerprint is computed by the sync that reads it and is reported by GET /uploads/\{upload_id\} once that sync has run), sniffs the CSV dialect + encoding from the first 1 MiB (req 4; explicit config.csv on the source wins), attaches the object to a file_upload source (creating one when the session has no source_id), and enqueues a WP-C1 sync whose extraction reads the uploaded object. Expired or unknown sessions fail with 400 failed_precondition (req 2). Completing an already-completed session is idempotent: it creates nothing and answers the session's current result, whose sync_id names the sync that now ingests the upload (WP-C2 R10: a follow-up sync that took it over, or a user's or a scheduled sync that took it from a follow-up not yet started; a replay under the same Idempotency-Key answers the stored first response); a sync still queued is launched again (one Job per sync). Uploading the identical object again under the same file name (the same size and checksums) attaches nothing and names the sync that ingests the earlier upload, so the content lands once, (a) while that sync is queued or running, or (b) when it took the earlier upload over from the sync enqueued at completion (a follow-up sync, or a user's or a scheduled sync that took it from a follow-up) and succeeded, unless a project purge or an entity erasure in the project completed after it finished; (c) after any other ended sync, the upload is a new file. An erasure never restores erased rows; a mode=full sync of the source re-ingests its files on purpose. Poll the upload (GET /uploads/\{upload_id\}), not only the sync the first answer named. A session claimed by a comparator (POST /comparators, WP-M19) fails with 400 failed_precondition (upload_claimed_by_comparator): comparator files are evaluation inputs only and are never attached to an ingestion source.

Operation ID: completeUpload · 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
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.
upload_idpathyesstringUpload session id (upl_ 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.

Responses​

StatusSchemaDescription
200UploadCompleteResponseThe completed upload with its enqueued sync.
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.