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.
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
| Name | In | Type | Description |
|---|---|---|---|
| X-Kepto-Quote-Idrequired | header | string | Quote id from POST /api/v1/files/quote; must still be current. |
| Idempotency-Keyrequired | header | string | Caller-chosen key that makes the upload safely retryable. |
| X-Filename | header | string | Display name recorded for this file. Default untitled. |
| X-Privacy | header | string | Visibility recorded with the file. public expects plaintext bytes; password and link expect a Kepto encrypted envelope. |
| X-Folder | header | string | Folder name recorded for this file. |
Body
application/octet-stream binaryrequired
Errors
| Code | Meaning |
|---|---|
| 400 | Empty 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. |
| 401 | Invalid or missing API key. |
| 403 | The API key lacks the required scope for this operation. |
| 409 | REQUOTE_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. |
| 413 | Request body exceeds the maximum encrypted envelope size (52428851 bytes). |
| 415 | Multipart uploads are not supported; send raw file bytes. |
| 429 | LIMIT_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. |
| 503 | MAINTENANCE 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"
]
}