API reference

Uploads

Every path is under https://impartire.com/api/v1. Generated from the API’s own contract, openapi.json (OpenAPI 3.1), which you can load into any OpenAPI tool. Errors are Problems — see Conventions.

POST/api/v1/uploads

Presign a single PUT, or start a multipart upload, for a file (step 1 of creating an asset with a file)

PUT the file's bytes to upload_url with headers, then create the asset with file.upload_id (or attach it to an existing asset with POST /assets/{id}/files). A single PUT carries up to 5 GiB. With multipart: true (required above 5 GiB, allowed from 5 MiB, up to 5 TiB) the answer has method: MULTIPART, no upload_url or headers, and multipart: the server-chosen part_size_bytes and part_count. Sign the parts' URLs with POST /uploads/{id}/parts, PUT each part, then POST /uploads/{id}/complete.

Scopes: assets:write

Parameters
  • Idempotency-Keyheader · string

    Makes a retry safe: the same key and request within 24 hours replays the first response. 1–255 characters.

Request bodyCreateUploadRequest
  • filenamestringrequired

    The file's name; its extension is what slots match on.

  • content_typestringrequired

    The MIME type the PUT will send.

  • size_bytesintegerrequired

    The exact size of the file. Required: a single PUT's URL is bound to it, and a multipart upload is checked against it when completed. At most 5 GiB for a single PUT, 5 TiB with multipart.

  • multipartboolean

    Upload in parts (required above 5 GiB, allowed from 5 MiB). The response's multipart gives the part size and count; sign the parts' URLs with POST /api/v1/uploads/{id}/parts, PUT each part, then POST /api/v1/uploads/{id}/complete. Default false: one PUT.

Response 201Upload
  • upload_idstring (uuid)required
  • upload_urlstring or nullrequired

    PUT the file's bytes here, with headers. Null for a multipart upload: its parts' URLs come from multipart.parts_url.

  • method"PUT" | "MULTIPART"required

    PUT: one PUT to upload_url. MULTIPART: parts, see multipart.

  • headersmap of string or nullrequired

    Headers the PUT must send. Null for a multipart upload (a part's PUT needs none).

  • url_expires_atstring (date-time) or nullrequired

    When upload_url stops accepting a new PUT (15 minutes). Null for a multipart upload: each part URL carries its own expiry.

  • expires_atstring (date-time)required

    When the upload must be used by (24 hours).

  • max_bytesintegerrequired
  • status"pending"required
  • multipartUploadMultipart or nullrequired

    Set for a multipart upload; null for a single PUT.

    • part_size_bytesintegerrequired

      Every part is exactly this size except the last, which is the remainder. Chosen by the server: at least 8 MiB, a whole number of MiB, at most 10 000 parts.

    • part_countintegerrequired

      How many parts: ceil(size_bytes / part_size_bytes). Part numbers run 1..part_count; part n is bytes (n-1)·part_size_bytes onward.

    • parts_urlstringrequired

      Where to sign the parts' upload URLs (POST, { part_numbers }).

Other responses
  • 401 unauthenticated — no key, or an unknown, revoked or expired one.
  • 403 insufficient-scope — the key lacks a required scope.
  • 404 not-found.
  • 409 idempotency-in-flight.
  • 422 validation (e.g. size_bytes over 5 GiB without multipart, multipart under 5 MiB), or idempotency-mismatch.
  • 429 rate-limited — the key's request budget is spent; wait Retry-After seconds.
  • 500 internal.
  • 503 storage-unavailable.

GET/api/v1/uploads/{id}

Get an upload's status: pending, landed, consumed or expired

Scopes: assets:write

Parameters
  • idpath · string (uuid)required

    upload_id from POST /uploads.

Response 200UploadStatus
  • upload_idstring (uuid)required
  • status"pending" | "landed" | "consumed" | "expired"required

    pending: no bytes yet (for a multipart upload: not completed yet). landed: the bytes are in storage, ready for POST /api/v1/assets or POST /api/v1/assets/{id}/files. consumed: an asset was created from it, or it was attached to one (asset_id). expired: past expires_at, or aborted.

  • size_bytesinteger or nullrequired
  • asset_idstring (uuid) or nullrequired

    Set when consumed.

  • expires_atstring (date-time)required
  • multipartUploadMultipart or nullrequired

    Set for a multipart upload; null for a single PUT.

    • part_size_bytesintegerrequired

      Every part is exactly this size except the last, which is the remainder. Chosen by the server: at least 8 MiB, a whole number of MiB, at most 10 000 parts.

    • part_countintegerrequired

      How many parts: ceil(size_bytes / part_size_bytes). Part numbers run 1..part_count; part n is bytes (n-1)·part_size_bytes onward.

    • parts_urlstringrequired

      Where to sign the parts' upload URLs (POST, { part_numbers }).

Other responses
  • 401 unauthenticated — no key, or an unknown, revoked or expired one.
  • 403 insufficient-scope — the key lacks a required scope.
  • 404 not-found.
  • 429 rate-limited — the key's request budget is spent; wait Retry-After seconds.
  • 500 internal.
  • 503 storage-unavailable.

POST/api/v1/uploads/{id}/parts

Sign upload URLs for parts of a multipart upload

Up to 100 distinct part numbers per request, each from 1 to multipart.part_count. PUT part n's bytes (offset (n-1)·part_size_bytes, part_size_bytes long, the last part the rest) to its URL within 15 minutes and keep the PUT's ETag header for …/complete. Signing writes nothing, so asking again just signs fresh URLs: no Idempotency-Key.

Scopes: assets:write

Parameters
  • idpath · string (uuid)required

    upload_id from POST /uploads with multipart: true.

Request bodySignPartsRequest
  • part_numbersarray of integerrequired

    The parts to sign: 1 to 100 distinct part numbers, each from 1 to the upload's multipart.part_count. Sign in batches for more.

Response 200UploadPartUrlList
  • dataarray of UploadPartUrlrequired

    One per requested part number, in the order asked.

    • part_numberintegerrequired
    • urlstringrequired

      PUT exactly this part's bytes here, with no extra headers; keep the response's ETag header for POST …/complete.

    • expires_atstring (date-time)required

      When url stops accepting a new PUT (15 minutes). Sign the part again for a fresh one.

Other responses
  • 401 unauthenticated — no key, or an unknown, revoked or expired one.
  • 403 insufficient-scope — the key lacks a required scope.
  • 404 not-found — not this credential's upload, or no longer in progress (completed, aborted, used or expired).
  • 422 validation (part_numbers), or not-multipart — the upload is a single PUT.
  • 429 rate-limited — the key's request budget is spent; wait Retry-After seconds.
  • 500 internal.
  • 503 storage-unavailable.

POST/api/v1/uploads/{id}/complete

Complete a multipart upload from its parts

Every part once, in any order, each with the ETag its PUT answered. The assembled file must be size_bytes long: otherwise it is discarded, the upload fails, and the answer is 422 size-mismatch. On success the upload is landed, ready for POST /assets or POST /assets/{id}/files. Completing an upload already completed answers its status again.

Scopes: assets:write

Parameters
  • idpath · string (uuid)required

    upload_id from POST /uploads with multipart: true.

  • Idempotency-Keyheader · string

    Makes a retry safe: the same key and request within 24 hours replays the first response. 1–255 characters.

Request bodyCompleteUploadRequest
  • partsarray of objectrequired

    Every part, once each: all multipart.part_count of them, in any order.

    • part_numberintegerrequired
    • etagstringrequired

      The ETag header the part's PUT answered with, quotes included or not.

Response 200UploadStatus
  • upload_idstring (uuid)required
  • status"pending" | "landed" | "consumed" | "expired"required

    pending: no bytes yet (for a multipart upload: not completed yet). landed: the bytes are in storage, ready for POST /api/v1/assets or POST /api/v1/assets/{id}/files. consumed: an asset was created from it, or it was attached to one (asset_id). expired: past expires_at, or aborted.

  • size_bytesinteger or nullrequired
  • asset_idstring (uuid) or nullrequired

    Set when consumed.

  • expires_atstring (date-time)required
  • multipartUploadMultipart or nullrequired

    Set for a multipart upload; null for a single PUT.

    • part_size_bytesintegerrequired

      Every part is exactly this size except the last, which is the remainder. Chosen by the server: at least 8 MiB, a whole number of MiB, at most 10 000 parts.

    • part_countintegerrequired

      How many parts: ceil(size_bytes / part_size_bytes). Part numbers run 1..part_count; part n is bytes (n-1)·part_size_bytes onward.

    • parts_urlstringrequired

      Where to sign the parts' upload URLs (POST, { part_numbers }).

Other responses
  • 401 unauthenticated — no key, or an unknown, revoked or expired one.
  • 403 insufficient-scope — the key lacks a required scope.
  • 404 not-found — not this credential's upload, or aborted, failed or expired.
  • 409 idempotency-in-flight.
  • 422 validation (parts — missing, repeated, or refused by storage), not-multipart, size-mismatch, or idempotency-mismatch.
  • 429 rate-limited — the key's request budget is spent; wait Retry-After seconds.
  • 500 internal.
  • 503 storage-unavailable.

POST/api/v1/uploads/{id}/abort

Abort a multipart upload in progress

Frees the parts stored so far; the upload reads expired. Aborting again, or after completing, is 404.

Scopes: assets:write

Parameters
  • idpath · string (uuid)required

    upload_id from POST /uploads with multipart: true.

Other responses
  • 204 Aborted.
  • 401 unauthenticated — no key, or an unknown, revoked or expired one.
  • 403 insufficient-scope — the key lacks a required scope.
  • 404 not-found — not this credential's upload, or not in progress (completed, aborted, used).
  • 422 not-multipart — the upload is a single PUT.
  • 429 rate-limited — the key's request budget is spent; wait Retry-After seconds.
  • 500 internal.
  • 503 storage-unavailable.