/uploads/capabilityScope documents:intakeReturns a short-lived browser/agent-direct R2 PUT URL only when this workspace is approved for source processing. A closed workspace receives 403 CUSTOMER_DATA_NOT_ENABLED_FOR_WORKSPACE before any URL or compute reservation is issued. Document bytes never pass through the application server. `requestedBytes` is checked against the deployment's per-source ceiling here, before any byte is stored: above it the answer is 413 SOURCE_EXCEEDS_PROCESSING_CEILING carrying `maxBytes`, `maxPages` and a sentence you can show a customer. Send `x-tavonel-source-idempotency-key` (a sha256 hex digest of the source event) to make the document id deterministic, so a retried intake converges on one document rather than two.
curl -sS -X POST https://tavonel.com/api/v1/uploads/capability \
-H "Authorization: Bearer $TAVONEL_API_KEY" \
-H "content-type: application/json" \
-d '{ "originalFilename": "<originalFilename>", "declaredMimeType": "application/pdf", "requestedBytes": 1, "estimatedPages": 1 }'import os
import requests
body = {
"originalFilename": "<originalFilename>",
"declaredMimeType": "application/pdf",
"requestedBytes": 1,
"estimatedPages": 1
}
response = requests.request(
"POST",
"https://tavonel.com/api/v1/uploads/capability",
headers={"Authorization": "Bearer " + os.environ["TAVONEL_API_KEY"]},
json=body,
timeout=30,
)
response.raise_for_status()
print(response.json())const response = await fetch("https://tavonel.com/api/v1/uploads/capability", {
method: "POST",
headers: { authorization: `Bearer ${process.env.TAVONEL_API_KEY}`, "content-type": "application/json" },
body: JSON.stringify({ "originalFilename": "<originalFilename>", "declaredMimeType": "application/pdf", "requestedBytes": 1, "estimatedPages": 1 }),
});
if (!response.ok) throw new Error(`${response.status} ${(await response.json()).code}`);
console.log(await response.json());{
"originalFilename": "<originalFilename>",
"declaredMimeType": "application/pdf",
"requestedBytes": 1,
"estimatedPages": 1
}| Status | Response |
|---|---|
200 | A qualified direct upload capability and the immutable document id the bytes will be registered under. PUT the bytes to uploadUrl with content-type declaredMimeType and content-length contentLength, within expiresInSeconds; the URL is the credential and it is short-lived. Then confirm with documentId. |
400 | UNQUALIFIED_INPUT — A required field was missing or was not of the declared type. UNQUALIFIED_MIME — The declared MIME type is not in the capability manifest. FILENAME_MIME_MISMATCH — The extension and the declared MIME type disagree. INVALID_FILENAME — Same refusal from the intake validator. SOURCE_IDEMPOTENCY_KEY_INVALID — x-tavonel-source-idempotency-key was present and was not 64 hex characters. |
401 | AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns. API_KEY_INVALID — The bearer token was well-formed but did not match a stored key. API_KEY_EXPIRED — The key matched and its expiry has passed. API_KEY_REVOKED — The key matched and was revoked. A rotation revokes the key it replaces. |
402 | STUDIO_SUBSCRIPTION_REQUIRED — The operation needs the higher plan tier — activation, rollback and retrieval-index rebuild are the three. TRIAL_ARCHIVE_NOT_INCLUDED — ZIP upload is not included in the free evaluation. TRIAL_FILE_LIMIT_EXCEEDED — The free evaluation's file count is spent. GPU_CREDITS_REQUIRED — The workspace has no processing balance left to reserve against. TRIAL_PAGE_LIMIT_EXCEEDED — The free evaluation's page allowance is spent. TRIAL_NOT_ACTIVE — No free evaluation is active for this workspace. TRIAL_DISABLED — Free evaluation is closed today. |
403 | API_SCOPE_REQUIRED — The key authenticated and does not carry the scope this operation requires. The request was refused rather than answered with less. CUSTOMER_DATA_NOT_ENABLED_FOR_WORKSPACE — This workspace has no current approval to process its sources. |
409 | INTAKE_IDEMPOTENCY_CONFLICT — The same source idempotency key was already used for different bytes. COMPUTE_IDEMPOTENCY_CONFLICT — The processing reservation ledger already holds a different reservation under this request's idempotency key. SOURCE_DELETED — The uploaded source has a deletion tombstone, so its bytes cannot be admitted or served again. |
413 | SOURCE_EXCEEDS_PROCESSING_CEILING — requestedBytes is above what every processor in the chain can read. The body carries maxBytes, maxPages and a limit sentence. This is the refusal the 5 MB per-source ceiling produces. TRIAL_FILE_TOO_LARGE — Above the free-evaluation per-file bound, which is lower than the deployment ceiling. |
415 | METADATA_ONLY_ENDPOINT — Document bytes were POSTed to a route that accepts only metadata. Bytes go direct to storage, never through the application server. |
429 | API_RATE_LIMITED — The key has used its per-minute allowance for this scope. The window is a fixed clock minute per key and scope; the allowances are on /docs/billing-and-limits. INTAKE_RATE_LIMITED — Too many upload capabilities were requested in the window. INTAKE_DAILY_QUOTA_EXCEEDED — The workspace's daily intake quota is spent. TRIAL_CAPACITY_REACHED — The deployment's concurrent free evaluations are full. |
503 | SIGNER_NOT_CONFIGURED — The upload URL signer is not configured, so no capability can be issued. INTAKE_DISABLED — Intake is closed today. API_RATE_LIMIT_UNAVAILABLE — The allowance could not be read, so the request was refused rather than run unbounded. |