Storage

Store a file against a quote (step 2 of the upload flow)

Requires scope files:write; this is a funded mutation (503 MAINTENANCE while paused). Send the raw file bytes with the X-Kepto-Quote-Id of a current quote and a caller-chosen Idempotency-Key. The gateway reserves admission budgets, escrows KEP, creates the on-chain deal, and returns the activated deal on success. Replaying the same Idempotency-Key with identical input returns the existing job (200 when Active, 202 otherwise); replaying it with different input fails with 409 IDEMPOTENCY_CONFLICT. Poll GET /api/v1/jobs/{jobId} when the response is not terminal. Price, provider, duration, and replicas are server-controlled query fields and are rejected with 400 UNSAFE_HOSTED_FIELD.

POST/api/v1/filesTry it
iNote
Requires a key with the files:write scope, sent as Authorization: Bearer <api-key>. Keys missing the scope are rejected with 403 — see Authentication.
!Heads up
Executes a real on-chain transaction on Robinhood testnet, funded by the gateway wallet. Returns 503 while funded mutations are paused for maintenance.
iNote
Part of the three-step upload flow: quote the upload with POST /api/v1/files/quote, store the bytes against the quote with POST /api/v1/files, then poll GET /api/v1/jobs/{jobId} until the job completes.

Headers

NameInTypeDescription
X-Kepto-Quote-IdrequiredheaderstringQuote id from POST /api/v1/files/quote; must still be current.
Idempotency-KeyrequiredheaderstringCaller-chosen key that makes the upload safely retryable.
X-FilenameheaderstringDisplay name recorded for this file. Default untitled.
X-PrivacyheaderstringVisibility recorded with the file. public expects plaintext bytes; password and link expect a Kepto encrypted envelope.
X-FolderheaderstringFolder name recorded for this file.

Body

application/octet-stream binaryrequired

Errors

CodeMeaning
400Empty body; UNSAFE_HOSTED_FIELD when price, provider, duration, or replicas query parameters are supplied; MISSING_UPLOAD_GUARD when X-Kepto-Quote-Id or Idempotency-Key is absent.
401Invalid or missing API key.
403The API key lacks the required scope for this operation.
409REQUOTE_REQUIRED when the quote is missing, expired, mismatched, or provider/market policy drifted (request a fresh quote); IDEMPOTENCY_CONFLICT when the Idempotency-Key is already bound to different input.
413Request body exceeds the maximum encrypted envelope size (52428851 bytes).
415Multipart uploads are not supported; send raw file bytes.
429LIMIT_EXCEEDED family — an admission budget was exhausted: CONCURRENCY_EXCEEDED, CUMULATIVE_BYTES_EXCEEDED, DAILY_DEALS_EXCEEDED, KEP_JOB_EXCEEDED, KEP_ACCOUNT_EXCEEDED, KEP_GLOBAL_EXCEEDED, NATIVE_ACCOUNT_EXCEEDED, NATIVE_GLOBAL_EXCEEDED, or PHYSICAL_CAPACITY_EXCEEDED.
503MAINTENANCE while funded mutations are paused (with Retry-After); otherwise the upload failed after admission — UPLOAD_FAILED when it failed before broadcast, NEEDS_RECONCILIATION when the outcome of a broadcast transaction is unknown. The failing job record is attached when available.
cURL
curl -X POST https://gateway.kepto.xyz/api/v1/files \
  -H "Authorization: Bearer <api-key>" \
  -H "X-Kepto-Quote-Id: <X-Kepto-Quote-Id>" \
  -H "Idempotency-Key: <Idempotency-Key>" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @<file>
200 · application/json
{
  "jobId": "string",
  "accountId": "string",
  "idempotencyKey": "string",
  "inputDigest": "string",
  "envelopeBytes": 0,
  "physicalBytes": 0,
  "dealCount": 0,
  "kepWei": "string",
  "budgetClass": "customer",
  "watchtowerBondWei": "string",
  "nativeWei": "string",
  "utcDay": "2026-08-07",
  "state": "Reserved",
  "transactionHashes": [
    "string"
  ]
}