Docs

Type a word or a question. Esc closes the search.

Sign in Start free
Developers/Basics

Errors

Every failed request returns one JSON shape and a stable code. Branch on the code, retry only what is worth retrying, and keep the request id.

The error envelope

A 4xx or 5xx response from a /v1 operation has this body, with one exception noted below:

{
  "error": {
    "code": "import_rows_out_of_range",
    "message": "Choose between 1 and 500 rows per import.",
    "request_id": "req_…",
    "details": { "min_rows": 1, "max_rows": 500 }
  }
}
FieldMeaning
codeA stable snake_case identifier. Branch on this, not on the message.
messageA sentence for people. Its wording can change; do not match on it. The message of a 5xx is replaced by Internal server error, except for 503 and a few provider failures; the cause stays in our log.
request_idThe id of this request. Quote it when you contact support; it finds the request in our logs.
detailsOptional. Extra data some codes define, such as max_bytes or retry_at. Absent when a code has none.

A code that no handler names comes from its HTTP status: bad_request for 400, unauthorized for 401, payment_required for 402, permission_denied for 403, not_found for 404, conflict for 409, rate_limit_exceeded for 429, service_unavailable for 503, internal_error for other 5xx and request_failed for any other status.

The incident AI operations are an exception: a 402 for a used-up AI quota still has the older flat body {"error": "…", "quota": {…}}, where error is a string. Read the HTTP status there.

Handling errors

  • Branch on error.code. The message and the details text are for people.
  • Retry only 429 and 5xx. Any other 4xx fails the same way until you change the request.
  • Wait for the Retry-After header when there is one. It gives seconds and comes with rate_limit_exceeded, confirmation_rate_limited and the 429 form of quota_limit_reached. Without it, back off exponentially and add jitter.
  • Send an Idempotency-Key on every POST and PATCH you may retry. When the first request finished with a status from 200 to 499, a retry after a timeout gets that stored answer and creates nothing a second time. A 5xx is not stored: a retry with the same key runs the request again, so after a 5xx look at the resource before you assume nothing was created. See idempotency.
  • Log request_id with the code, and send it to support for any 5xx that persists.

Errors on every operation

Middleware, not a handler, answers these before a request reaches its operation, so they are listed here once and not on each operation. Each applies only under the condition shown.

CodeStatusWhen
api_key_scopes_required 403 The request uses an API key created before scopes existed.
bad_request 400 A POST or PATCH carries an Idempotency-Key header and its body cannot be read.
forbidden 403 A POST or PATCH carries an Idempotency-Key header and the request has no verifiable current authorization.
idempotency_key_conflict 409 A POST or PATCH carries an Idempotency-Key header that was stored with a different body.
idempotency_replay_unavailable 409 A POST or PATCH carries an Idempotency-Key header whose stored response cannot be replayed to this caller.
insufficient_scope 403 The request uses an API key that lacks the scope the operation requires.
internal_error 500 · 502 A POST or PATCH carries an Idempotency-Key header and the key store fails.
not_found 404 A client-portal session requests a route the portal does not expose.
permission_denied 403 A browser session sends a request from another origin; Bearer keys are not affected.
rate_limit_exceeded 429 The request exceeds the per-client rate limit, or the per-credential limit once authenticated; Retry-After gives the wait in seconds.
read_only_api_key 403 A read-only API key calls an operation that writes.
session_required 403 An API key calls a route that is limited to browser sessions.
unauthorized 401 The credentials are missing, malformed, unknown, revoked or expired.

Error codes by status

67 codes can come back from a public operation. Each is listed under its first HTTP status; a code that can carry another status shows it next to the code. “Operations” are the ones whose handler can answer with the code, found by reading the source; the page of an operation in the reference is authoritative for what it returns.

200

request_failed 200 · 410 · 413 · 422

The request failed with a status that has no code of its own.

Typical trigger
A 410 for an expired invite, a 413 for a body over its size limit, or a 422 for a request that parses but that the rules reject.
Fix
Use the HTTP status and message; these are not retryable until the request changes.
Operations

400 Bad request

bad_request

The request is malformed or fails validation.

Typical trigger
A body that is not valid JSON, a missing or invalid field, or a path or query value that does not parse; the message names the problem.
Fix
Read message and details, correct the request and send it again; an unchanged retry fails the same way.
Operations

Under the condition in Errors on every operation, and from handlers on 267 of 271 operations.

cursor_expired

The list cursor has expired.

Typical trigger
Paging a monitor list with a cursor that is too old.
Fix
Start again without a cursor.
Operations

cursor_invalid

The list cursor is not valid.

Typical trigger
Paging a monitor list with a cursor that was not issued by the API or was altered.
Fix
Use the cursor from the previous response unchanged, or start without one.
Operations

cursor_parameters_changed

The filters changed since the cursor was issued.

Typical trigger
Paging a monitor list with a cursor while sort or filter parameters differ from the first request.
Fix
Keep the parameters the same for all pages, or start again without a cursor.
Operations

401 Unauthorized

unauthorized

The request carries no valid credentials.

Typical trigger
The Authorization header is missing or malformed, the API key is unknown or revoked, or a browser session has expired.
Fix
Send a valid key as Authorization: Bearer pls_..., and create a new key if the old one was revoked.
Operations

Every operation, under the condition in Errors on every operation. Handlers also return it on:

402 Payment required

billing_action_unavailable

The Company's billing state does not allow this action.

Typical trigger
A metered or limited action while the billing state, such as paused or without credit, blocks it; details holds the action and billing_state.
Fix
Top up the credit or change the plan, then retry.
Operations
21 operations

payment_required

The Company's billing state does not allow the action.

Typical trigger
Creating a monitor, scheduled job or alert channel when the credit is used up or the plan does not cover it; the message names the reason.
Fix
Top up the credit or change the plan in billing, then retry.
Operations
9 operations

403 Forbidden

api_key_scopes_required

The API key predates scopes and has none.

Typical trigger
Only for API keys created before scopes existed, on any public operation.
Fix
Rotate the key in the app to get one with explicit scopes.
Operations

Every operation, under the condition in Errors on every operation.

check_capacity_exceeded

The change would push the subscription's projected monthly check load over its included budget.

Typical trigger
Creating a monitor, directly or through a client template, or changing one, when the projected cost including the change exceeds the budget; running monitors are not affected, and details carries projected_cents, included_cents and change_cents.
Fix
Use a longer interval, fewer regions or fewer monitors, or raise the included budget.
Operations
7 operations

forbidden

The idempotency layer has no current authorization to bind the key to.

Typical trigger
Only on POST and PATCH requests that send an Idempotency-Key header and whose authorization cannot be verified.
Fix
Authenticate the request with a valid key before sending Idempotency-Key.
Operations

Every operation, under the condition in Errors on every operation.

insufficient_scope

The API key lacks the scope this operation needs.

Typical trigger
Only for API keys, when the key's scopes do not include the one the operation requires; details.required_scope names it.
Fix
Create a key with the needed scope; a missing scope never resolves by retrying.
Operations

Every operation, under the condition in Errors on every operation.

permission_denied

The credentials are valid but may not do this.

Typical trigger
The key's role or client scope does not allow the action, for example a write on a client the key cannot write to.
Fix
Use a key with the needed role and client scope, or ask a Company admin to grant it.
Operations

Under the condition in Errors on every operation, and from handlers on 182 of 271 operations.

quota_limit_reached 403 · 429

A usage or inventory limit of the Company was reached.

Typical trigger
Counters and concurrency limits answer 429 with Retry-After, inventory and capacity limits answer 403; details holds purpose, limit and window.
Fix
On 429 wait Retry-After seconds; on 403 free something up, request a higher limit where details.raise_request is true, or buy an extension.
Operations
21 operations

read_only_api_key

A read-only API key tried to write.

Typical trigger
Only for read-only API keys, on any POST, PUT, PATCH or DELETE operation.
Fix
Use a key with write permission for this call.
Operations

Every operation, under the condition in Errors on every operation.

session_required

The operation is available only to a signed-in browser session, not to an API key.

Typical trigger
Only for API keys, on routes that manage keys or are limited to the web app.
Fix
Do this in the app while signed in; API keys cannot call it.
Operations

Every operation, under the condition in Errors on every operation.

404 Not found

design_template_not_found

The design template does not exist or is not visible to the caller.

Typical trigger
A design template id in the path or body that is unknown or not visible to the caller.
Fix
List design templates and use an id from the list.
Operations
12 operations

not_found

The resource does not exist or is outside the caller's scope.

Typical trigger
An id in the path that is unknown, belongs to another Company, or lies outside the key's client scope, and a client-portal session asking for a route the portal does not expose.
Fix
Check the id and that the key's client scope covers it; do not retry an unchanged request.
Operations

Under the condition in Errors on every operation, and from handlers on 196 of 271 operations.

409 Conflict

channel_in_use

The alert channel is still used by monitors or alert plans, so it was not deleted.

Typical trigger
Deleting an alert channel that a monitor notifies or an alert plan step targets. `details` carries the counts `monitors` and `alert_plans`.
Fix
Remove the channel from those monitors and alert plan steps first, then delete it.
Operations

conflict

The request conflicts with the current state of the resource.

Typical trigger
Creating something that already exists, or acting on a resource whose state no longer allows it, such as a postmortem for an incident that is not resolved.
Fix
Fetch the current state, resolve the difference and send the request again.
Operations
11 operations

design_template_conflict

The design template was changed after the caller read it.

Typical trigger
Updating or applying a design template that was changed after the caller read it.
Fix
Reload the template and apply the change again.
Operations
10 operations

domain_claimed

The domain is in use by another Company.

Typical trigger
Setting a custom domain on a status page when another Company already holds it; details.domain names it.
Fix
Prove control of the domain with the TXT record shown for the page, or use a different domain.
Operations

domain_move_stale

The page named as the domain's current holder is not the holder any more.

Typical trigger
Moving a domain with move_from_page_id set to a page that does not hold it; details.page names the real holder.
Fix
Read the domain's current holder and send the move again with that page.
Operations

domain_on_other_page

The domain is used by another status page in the same Company.

Typical trigger
Setting a custom domain that another page of the Company already holds; details.page names that page.
Fix
Move the domain on purpose by sending the holder's page id as the page to move from, or choose another domain.
Operations

domain_used_in_company

The domain is used by a status page in the Company that the caller cannot see.

Typical trigger
Setting a custom domain held by a page outside the caller's client scope; the page is not named.
Fix
Ask someone with access to that page to move or remove the domain, or choose another domain.
Operations

idempotency_key_conflict

The Idempotency-Key was already used with a different request body.

Typical trigger
Only on POST and PATCH requests with an Idempotency-Key header that repeat a stored key with a changed body; details.original_request_at gives the first request's time.
Fix
Send the same body to replay the first answer, or use a new key for a new request.
Operations

Every operation, under the condition in Errors on every operation.

idempotency_replay_unavailable

The request was already processed, but its stored answer cannot be replayed.

Typical trigger
Only on POST and PATCH requests with an Idempotency-Key header whose stored response was made with a different API key, or under different scopes, access level or client access, or is no longer visible to the caller.
Fix
Read the resource's current state instead of replaying, and use a new key for any new attempt.
Operations

Every operation, under the condition in Errors on every operation.

oncall_schedule_in_use

The on-call rotation is still a target of an alert plan step, so it was not deleted.

Typical trigger
Deleting an on-call rotation that an alert plan step targets as `oncall:<id>`. `details.alert_plans` lists those plans.
Fix
Remove the rotation from the steps of those alert plans first, then delete it.
Operations

413 Content too large

422 Unprocessable content

429 Too many requests

rate_limit_exceeded

Too many requests in a short time.

Typical trigger
The per-client or per-credential request limit was reached, or an endpoint with its own limit, such as test checks or AI calls, refused the call; Retry-After carries the wait in seconds where the code sets it.
Fix
Wait for Retry-After seconds, then retry with backoff and spread bursts over time.
Operations

Every operation, under the condition in Errors on every operation. Handlers also return it on:

500 Internal server error

internal_error 500 · 502

The server failed while handling the request.

Typical trigger
An unexpected failure or a failed upstream call; the message of a 5xx is replaced by "Internal server error" except for 503 and a few provider failures, and the cause stays in the server log.
Fix
Retry with backoff, and send request_id to support if it keeps failing.
Operations

Under the condition in Errors on every operation, and from handlers on 118 of 271 operations.

502 Bad gateway

503 Service unavailable

notification_setup_incomplete

The Company's setup is incomplete, so the channel cannot be created.

Typical trigger
Creating an alert channel in a Company that has no default team.
Fix
Contact support with the request_id so the setup can be completed.
Operations

quota_gate_unavailable

The limit check itself failed, so the action was not carried out.

Typical trigger
The quota service could not decide while the request ran.
Fix
Retry in a moment; nothing was changed.
Operations
21 operations

service_unavailable

The service or a dependency the request needs cannot take it right now.

Typical trigger
A dependency such as the AI provider, the checkout or the report runner is not available; the action was not carried out.
Fix
Retry with backoff; nothing was changed by the failed request.
Operations
10 operations

504 Gateway timeout

Codes of the web app

The routes behind these 40 codes are not part of the public API: sign-in, billing, add-ons, support messages and test checks. API keys do not reach them, and nothing here is promised to stay. They are listed so that a code you find in a log or in the app has an explanation.

account_deletion_invalid_password 400

The password given to confirm the account deletion is wrong.

Typical trigger
Deleting the signed-in account with a current password that does not match.
Fix
Send the account's current password, or reset it first.

account_deletion_owner_transfer_required 409

The account owns a Company and must hand ownership over before it can be deleted.

Typical trigger
Deleting the account of a Company owner.
Fix
Transfer ownership to another member, or ask the up4 team to delete the whole Company.

account_deletion_unavailable 503

Account deletion cannot be carried out right now.

Typical trigger
A server-side failure while processing the deletion.
Fix
Email privacy@upfour.io so the up4 team can process it.

addon_change_open 409

An add-on purchase is still waiting for its payment, so the plan cannot change.

Typical trigger
Changing the plan while an earlier add-on purchase is open.
Fix
Finish or cancel the open add-on purchase, then change the plan.

addons_change_failed 502

Stripe could not be reached for an add-on change; nothing was changed.

Typical trigger
Stripe failed or timed out while the add-on change was applied.
Fix
Retry in a few minutes; the change applies only when a request succeeds.

below_reduction_floor 422

The new pack quantity is lower than current use needs.

Typical trigger
Reducing an add-on to fewer packs than what the Company uses.
Fix
Choose a quantity at or above what is in use, or free up usage first.

billing_portal_failed 502

The billing portal could not be opened.

Typical trigger
Stripe failed or timed out while the portal session was created; the plan and payment details are unchanged.
Fix
Retry in a few minutes, or message the up4 team.

checker_busy 503

The checkers are too busy for a test check.

Typical trigger
A test check while the checker pool or the target address is at its test limit.
Fix
Try again in a few seconds.

checker_unavailable 503

The test check could not be started.

Typical trigger
A test check when the request cannot be sent to a checker.
Fix
Try again later.

checkout_failed 502

The checkout for the plan could not be opened.

Typical trigger
Stripe failed or timed out while the checkout session was created; nothing was charged.
Fix
Retry in a few minutes, or message the up4 team.

custom_domain_slots_retired 410

Custom domain slots are no longer sold.

Typical trigger
Buying or changing a custom domain slot; a connected custom domain is billed per day from the credit.
Fix
Connect the domain to a status page directly.

idempotency_key_required 400

The request needs an Idempotency-Key header.

Typical trigger
An add-on or support request sent without Idempotency-Key.
Fix
Send a unique Idempotency-Key header and keep it for retries.

invalid_code 401

The two-factor code did not match.

Typical trigger
Confirming two-factor setup at sign-in with a wrong or expired code.
Fix
Check the time on the phone and enter the current code.

invalid_quantities 400

The add-on quantities are not valid.

Typical trigger
Changing add-ons with no quantity, an unknown add-on, a quantity outside what can be booked, or a change that alters nothing; details names the reason.
Fix
Send quantities within the allowed range and at least one that differs from the current one.

invalid_signature 401

The heartbeat ping's signature is not valid.

Typical trigger
Pinging a scheduled job that requires signed pings with a missing or wrong X-Up4-Signature header.
Fix
Sign the ping as documented for the job.

invite_organization_conflict 409

The account already belongs to another Company.

Typical trigger
Accepting an invite, signing in through SSO or verifying a magic link with an account that is a member of a different Company.
Fix
Use a different email address, or leave the other Company first.

no_live_region 503

No checker is online in the selected region.

Typical trigger
A test check for a region with no live checker.
Fix
Try again in a minute or select another region.

no_pending 404

No add-on purchase is waiting for its payment.

Typical trigger
Cancelling a pending purchase when none is open.
Fix
Refresh the add-on state; there is nothing to cancel.

not_purchasable 409

The add-on cannot be bought or changed in the current state.

Typical trigger
A purchase or plan change when an add-on has no price, the Company is read-only or another condition applies; details.reason names it.
Fix
Act on details.reason, or message the up4 team.

nothing_scheduled 404

No reduction is scheduled for the add-on.

Typical trigger
Withdrawing a scheduled reduction when none exists for that add-on.
Fix
Refresh the add-on state; there is nothing to withdraw.

password_required 409

The account has no password yet.

Typical trigger
Starting two-factor setup at sign-in for an account without a password.
Fix
Use Forgot password to set one, sign in again and then set up two-factor.

payment_pending 409

A change to the subscription is still waiting for its payment.

Typical trigger
Changing the plan while the subscription has an unpaid pending update.
Fix
Finish the pending payment, then change the plan.

pending_lapses 409

The pending purchase cannot be cancelled and lapses on its own.

Typical trigger
Cancelling a purchase that is not paid yet.
Fix
Wait for it to lapse if it is not paid.

pending_open 409

An add-on purchase is still waiting for its payment.

Typical trigger
Starting, confirming or changing an add-on purchase while an earlier one is open.
Fix
Finish or let the open purchase lapse before starting another.

price_unavailable 503

The price for the monitor is currently unavailable.

Typical trigger
Reading a monitor's month-to-date cost while a meter price is missing; the API never answers 0 for a missing price.
Fix
Try again later.

probe_timeout 504

No checker answered the test check in time.

Typical trigger
A test check that got no reply before its deadline.
Fix
Try again; if it keeps failing, check the target and region.

quote_expired 409

The add-on price is no longer valid.

Typical trigger
Confirming a quote after its price expired.
Fix
Review the change again to get a new quote.

quote_not_found 404

The add-on quote does not exist.

Typical trigger
Confirming a quote id that is unknown.
Fix
Request a new quote and confirm that one.

subscription_change_failed 502

Stripe could not be reached for the subscription change; nothing was applied.

Typical trigger
Stripe failed or timed out while the plan change was applied.
Fix
Retry in a few minutes, or message the up4 team.

subscriptions_unavailable 409

New status page subscriptions are not possible right now.

Typical trigger
A visitor signing up or confirming while the Company's subscriber pool is full.
Fix
Try again later.

support_category_not_available 403

The message category is not available to this user.

Typical trigger
A client-portal user sending a message other than a problem report.
Fix
Choose the problem report category.

support_delivery_failed 503

The support message could not be delivered.

Typical trigger
The mail send failed after the request was accepted.
Fix
Email the support address named in the message directly.

support_messages_disabled 503

In-app support messages are switched off.

Typical trigger
Sending a support message while the feature is disabled.
Fix
Email the support address named in the message directly.

support_scope_invalid 400

The message scope is not valid.

Typical trigger
Sending a support message that refers to a scope the sender cannot use.
Fix
Pick a scope the sender can access, or send the message without one.

terms_not_accepted 400

The request does not accept the current terms of service.

Typical trigger
Signing up, starting a plan checkout or topping up the wallet without `accept_terms: true` and a `terms_version`.
Fix
Show the terms to the person, then send `accept_terms: true` with the current `terms_version`.

terms_notice_not_due 409

The current terms version cannot be announced any more.

Typical trigger
An operator sends the change notice for a version whose effective date is today or in the past.
Fix
Publish a new version with a future effective date first (docs/ops/terms-versions.md).

terms_version_outdated 409

The terms version the request accepts is not the current one.

Typical trigger
A `terms_version` from a page loaded before a new version of the terms of service was published.
Fix
Reload the page, show the current terms and send their version.

topup_failed 502

The payment page for the top-up could not be opened.

Typical trigger
Stripe failed or timed out while the top-up was prepared; nothing was charged.
Fix
Retry in a few minutes, or message the up4 team.

two_factor_already_enabled 409

Two-factor authentication is already on for the account.

Typical trigger
Starting two-factor setup for an account that already has it.
Fix
Sign in again.

two_factor_setup_expired 401

The two-factor setup step has expired.

Typical trigger
Continuing two-factor setup after its short window ended.
Fix
Sign in again to restart the setup.