LLM API

Authentication

The LLM API authenticates with a project-scoped inference key, sent as a bearer token.

Create a key

Inference keys are created in the Console under Inference API → Keys, scoped to a project. The full secret is shown only once at creation, so copy it immediately and store it in a secret manager. See Inference keys for the full lifecycle (rotation, revocation, archiving).

Treat keys like passwords

A key carries the permissions of its project. Never commit one to source control or expose it in client-side code. If a key leaks, revoke it in the Console and issue a new one.

Send the key

Pass the key in the Authorization header as a bearer token. The SDKs do this for you when you set api_key.

Authorization header
Authorization: Bearer $UPGREAT_API_KEY

Keep the key in an environment variable rather than inline:

export UPGREAT_API_KEY="sk-..."

curl https://llm.upgreat.ai/v1/models \
  -H "Authorization: Bearer $UPGREAT_API_KEY"

Errors

A missing, malformed or revoked key returns 401 Unauthorized with an OpenAI-style error envelope:

401 response
{
  "error": {
    "message": "invalid token",
    "type": "authentication_error",
    "code": "invalid_token"
  }
}

A 400 indicates the request body failed validation (for example a missing model or messages field). The error.message names the offending field.

A 403 with code model_not_allowed means the model is not available to this key: either the key's own model list excludes it, or your organization does not have access to it. The Console lists the models your organization can use.

Rate limits and capacity

A 429 Too Many Requests carries a Retry-After header (seconds) and one of these codes:

  • rate_limit_exceeded, token_rate_limit_exceeded — the requests or tokens per minute allowed for the key, or for your organization across all its keys.
  • token_quota_exceeded — the token quota of the key or the organization for the current period is used up.
  • model_overloaded — the model is at capacity. Requests above capacity wait briefly in a queue shared fairly between organizations; this code means no slot became free in time.
429 response
{
  "error": {
    "message": "deepseek-v4.1-flash is at capacity, retry shortly",
    "type": "rate_limit_error",
    "code": "model_overloaded"
  }
}

Retrying

Wait the number of seconds in Retry-After, then retry with exponential backoff and a little jitter. For large batch jobs, cap your own concurrency rather than sending everything at once: requests are served faster and you avoid model_overloaded.