API
API: Authentication & errors
Authenticate to the Bumpkit API, read its errors, and handle rate limits, credits, idempotency, pagination and versioning.
What every request shares.
Authentication
Send your API key in the x-api-key header on every request:
curl https://bumpkit.dev/v1/me -H "x-api-key: bk_live_..."Authorization: Bearer is not accepted on /v1 endpoints. The SCIM API is the one exception: it takes a separate SCIM token as a bearer token (see SSO & SCIM).
| Item | Detail |
|---|---|
| Key prefix | bk_live_. A key without it fails with INVALID_API_KEY. |
| Display prefix | The first 16 characters, shown as prefix in key listings. |
| Storage | Bumpkit stores a hash. The full key is shown once, when you create it. |
| Expiry | Optional expires_at. An expired key fails with REVOKED_API_KEY. |
| Getting a key | Create one in the dashboard, run bumpkit login, or call POST /v1/keys. |
Every key belongs to one workspace. There are no per-key scopes. What a key can do depends on two things:
- Workspace endpoints (keys, team, settings, integrations, billing, audit, override reviews, rules and similar) need a key created by a person. They act as that person, with that person's role. A key that isn't tied to a person gets
403 FORBIDDEN. - Person-only actions (gate overrides, agent command decisions, and approving and cutting a release batch) need a person signed in to the dashboard. Any key gets
403 HUMAN_APPROVAL_REQUIRED, whatever its creator's role. - Owner-only actions need the key's creator to be a workspace owner or admin. With roles on, some actions also accept another role that holds the permission they name.
Endpoints without either requirement work with any key in the workspace.
Errors
Every error uses the same shape:
{
"status": "error",
"error": {
"code": "MISSING_COMMITS",
"message": "commits array must contain at least one entry",
"field": "commits",
"suggestion": "Provide an array of commit objects with at least one entry.",
"explanation": "The request has no commits, or commits isn't an array with at least one commit.",
"next_step": "Send commits as an array with at least one commit object.",
"docs_url": "https://bumpkit.dev/docs/explanations#missing-commits"
}
}field appears only on errors from the changelog endpoints: the validation codes below and 422 INSUFFICIENT_SIGNAL. suggestion appears only for codes that have one. Errors also carry explanation, next_step and docs_url, which link to its entry in Why am I seeing this?. Successful responses have no envelope: they are the resource itself.
Common codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR |
The body doesn't match the endpoint's shape, or a field is invalid. The message says which. |
| 400 | INVALID_JSON |
The body isn't valid JSON, or isn't a JSON object or array. |
| 400 | INVALID_POLICY |
The bumpkit.yml sent to the gate doesn't parse. The gate fails closed. |
| 401 | MISSING_API_KEY |
No x-api-key header. |
| 401 | INVALID_API_KEY |
The key is malformed or doesn't exist. |
| 401 | REVOKED_API_KEY |
The key was revoked or has expired. |
| 401 | INVALID_SIGNATURE |
An inbound webhook's signature doesn't match. |
| 403 | FORBIDDEN |
Your role can't do this, or the key isn't tied to a person. |
| 403 | ROLE_REQUIRED |
Evidence exports and the audit stream need a key created by an owner, admin or auditor. Publishing release docs needs a key created by an owner, admin, policy admin, approver or member. |
| 403 | FEATURE_EARLY_ACCESS |
The endpoint belongs to a Beta feature your workspace doesn't have access to yet. The message links to the page where you request it. |
| 404 | NOT_FOUND |
Unknown route, a feature that isn't available, or a resource that doesn't exist. For an unknown route the message is Route not found. |
| 404 | CHECK_NOT_FOUND, FINDING_NOT_FOUND, LESSON_NOT_FOUND, MEMORY_NOT_FOUND, DEPLOYMENT_NOT_FOUND, REPOSITORY_NOT_FOUND |
The resource doesn't exist in your workspace. |
| 409 | CONFLICT |
The change conflicts with current state, for example a duplicate. |
| 413 | PAYLOAD_TOO_LARGE |
The body is over the endpoint's size limit. |
| 422 | INSUFFICIENT_SIGNAL |
The changelog endpoints found no usable commits. |
| 429 | RATE_LIMIT_EXCEEDED |
A per-minute or per-endpoint limit was hit. Every 429 carries Retry-After in seconds. |
| 500 | INTERNAL_ERROR |
Server error. |
| 502 | UPSTREAM_ERROR |
A provider such as GitHub, Stripe or an integration failed. |
| 503 | SERVICE_UNAVAILABLE |
Temporary outage. |
| 503 | POLICY_UNAVAILABLE |
The gate reads bumpkit.yml through the GitHub App or a GitHub Enterprise Server connection, and the host didn't return it or couldn't say whether the App is installed. The gate fails closed. |
| 503 | LLM_NOT_CONFIGURED |
This feature isn't available for your workspace right now. |
Every code, with what to do about it, is listed in Why am I seeing this?.
Body size limits
| Endpoint | Limit |
|---|---|
POST /v1/checks, POST /v1/deployments |
10 MB |
POST /v1/rollbacks/{id}/open |
8 MB |
| Everything else | 1 MB |
A body over the limit fails with 413 PAYLOAD_TOO_LARGE, and a body that isn't valid JSON with 400 INVALID_JSON, before authentication runs.
Rate limits
Per-minute limits are separate from billing. The workspace limit is 120 requests per minute, shared by all its keys, and some endpoints have their own limits.
Authenticated responses carry these headers, so you can budget calls before you hit a limit:
X-RateLimit-Limit-Minute: 120
X-RateLimit-Remaining-Minute: 43
X-RateLimit-Reset-Minute: 1716249660Reset values are Unix epoch seconds. When the limit is hit the response is 429 with RATE_LIMIT_EXCEEDED, the same headers and Retry-After in seconds.
Credits
1 credit = 1 release check = $0.10. Re-runs of the same commit are free. Every workspace gets 60 free credits each calendar month (UTC), no card needed. No seats, no repository limits. Enterprise is a custom annual contract.
Credit purchases aren't enabled yet. To buy more credits, contact the Bumpkit team at hello@bumpkit.dev. GET /v1/billing/usage shows what each period used.
Every 429 carries Retry-After in seconds. Wait that long, then retry. Endpoints with their own limits say so below.
Idempotency
POST /v1/checks and POST /v1/gate are replay-safe. Send an Idempotency-Key header and retry with the same key: you get the stored result instead of a second run.
curl https://bumpkit.dev/v1/gate \
-H "x-api-key: $BUMPKIT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: deploy-7f3a9c" \
-d '{"repository": "acme/api", "base": "v1.4.2", "head": "main"}'| Rule | Behavior |
|---|---|
| Key format | 1 to 200 characters: letters, digits, ., :, -, _. Anything else is 400 INVALID_IDEMPOTENCY_KEY. |
| Pinned requests | A request with a diff, or with base and head both full 40-character SHAs, is replayed automatically, with or without a header, until something that affects the result changes, such as approvals, CI results, org policy or a freeze. Then the call runs again. |
| Other requests | Replayed only when you send Idempotency-Key. The key covers the request body. For the gate, approvals are not part of it. |
| Replay | 200 with the stored body and "replayed": true. No new check or decision is stored, and the call doesn't use a credit. |
| Same key, different body | 422 IDEMPOTENCY_KEY_REUSED. |
| Same request still running | The server waits up to 2 minutes for the first call, then returns 409 REQUEST_IN_PROGRESS. Retry. |
| Failed runs | Not stored. A retry runs again. |
| Retention | 1 day. |
| Early expiry | A stored result runs again after new finding feedback, an override, or a change freeze that starts, ends or changes. |
| Scope | Per workspace and per endpoint. |
| Data retention | Results are stored for replay only with the standard data retention mode. With findings_only or ephemeral, every call runs again. |
Other endpoints have no idempotency header. POST /v1/claims is idempotent for the same agent and session; the endpoint descriptions note others.
Pagination
There are no cursors. List endpoints take a limit query parameter and return the newest items first. Each endpoint gives its default and maximum. An out-of-range limit falls back to the default, except where the endpoint says it is clamped.
SCIM list endpoints use startIndex and count.
Versioning
The API is versioned in the path. Everything here is /v1. Fields can be added to responses without notice, so ignore fields you don't recognize. Fields marked optional are left out when empty.