Authentication
Every Upload API request identifies the project with the public key, sent as the UPLOADCARE_PUB_KEY parameter or pub_key where the endpoint says so.
Signed access
A project with Signed Uploads turned on additionally requires a credential generated on your backend with the project secret key. You create secret keys yourself in the API keys section of your Dashboard. A project can have more than one.
There are two credential schemes:
- Token, a JSON Web Token in the
Authorizationheader. It can restrict which endpoints the client may call and how many operations it may spend. - Signature (legacy), the
signatureandexpirerequest parameters. It allows every upload endpoint until it expires. AI image endpoints accept tokens only. The scheme stays supported, but use tokens for new integrations.
signature and an Authorization header, the signature is checked and the header is ignored. AI image endpoints read only the header.Credentials are checked only when the project has Signed Uploads or Signed AI image generation turned on. The signed uploads guide explains how to enable them and which credential to choose.
Token
A token is a JSON Web Token (RFC 7519) sent in the Authorization header with the Bearer scheme:
Signing
The token MUST be signed with HS256. The signing key is the SHA-256 digest of the project secret key, as raw 32 bytes rather than their hex representation. Any of the project’s secret keys works.
Hash the secret key as the characters you copied from the dashboard, not as the bytes that hex string decodes to. Both that and signing with the digest’s hex form produce Invalid token. Reason: signature does not match, which is the most common way a hand-rolled token fails.
Claims
Standard claims sit at the root of the payload. Everything Uploadcare interprets sits under the uc claim.
nbf, if present, is enforced: a token used before that time is rejected with AccessTokenInvalidError. Other standard claims are ignored. Keys under uc other than the ones in that table are not allowed: such a token is rejected.
Payload example:
Scope and limits
Each signed endpoint has a scope path. A scope item matches a path exactly, or as a prefix when it ends with /*. A bare /* matches every endpoint. The list holds from 1 to 16 items, each up to 64 characters and starting with /.
/multipart/start/ for files over multipartMinFileSize (25 MB by default), /from_url/ for URL and social sources, and /group/ when groupOutput is on. The AI Image Editor plugin sends the same token, so add its paths too. A path that’s missing fails with ScopeForbiddenError.The AI image endpoints are checked only when Signed AI image generation is on, and they accept auth tokens only, not signatures. Polling a generation’s status is not checked.
The operations counter lives as long as the token. A request that would exceed the limit is refused. A request refused before any file is saved or any job is started consumes nothing. Once a direct upload saves its first file, the whole request’s operations are spent, even if a later file in the same request fails. A multipart upload that is started but never completed still consumes its operation.
One counter per token
Uploadcare keys the counter by the token itself, not by its claims. Two tokens minted in the same second with the same claims are byte-identical, so they share one counter, and one user can spend another’s limit. If you set operations, add a sub (for example, the user ID) or a jti (a random ID) so every token is unique. Uploadcare doesn’t read either claim.
Generate a token
Use the Uploadcare Node SDK, or any JWT library that supports HS256. The samples set operations, so they also set sub to give each token its own counter:
NodeJS (SDK)
NodeJS
Python
Ruby
@uploadcare/signed-uploads mints the token for you, and validates the claims before signing rather than letting the API reject them:
Pass expire (a millisecond timestamp or a Date) in place of lifetime for an absolute expiry. subject sets sub and tokenId sets jti. When you pass operations, set at least one of them so each token gets its own count. Signed uploads covers handing the token to File Uploader, Upload Client or the AI Image Editor.
Upload example
Errors
With Accept: application/json (exactly) or the jsonerrors=1 query parameter, errors come back as HTTP 200 with the real status in status_code. The one exception is DerivativeQuotaExceededError, which keeps its 429. Upload Client sends jsonerrors=1 and reads it. Otherwise, the HTTP status is the real one. Either way, branch on error_code.
On uploads, the JavaScript libraries handle two of these for you: given a way
to fetch a token, they answer AccessTokenExpiredError and
OperationsLimitExceededError by dropping the refused token and retrying the
request once. The AI image endpoints are not retried. See when a credential is
refused.
Signature
The signature and expire parameters are sent together with the request, either in the query string or as form fields.
Any of the project’s secret keys works.
Generate a signature
@uploadcare/signed-uploads package accepts milliseconds and converts to seconds internally. If you implement signing without this package, expire must be in seconds, not milliseconds.JavaScript
NodeJS
Python
Ruby
Elixir
Upload example
Errors
For the complete list of Upload API errors, see Errors.