Docs

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

DE
Sign in Start free
Developers/Basics

Two shapes, always the same.

A successful call returns data. A failed call returns error. You can tell them apart by the status code and by the one key at the top.

Success

A 2xx response with a JSON body wraps its payload as { "data": … }. A list puts an array in data and adds pagination; what that object means depends on the endpoint, see pagination.

curl -s https://app.upfour.io/v1/monitors/$MONITOR_ID \
  -H "Authorization: Bearer $UP4_API_KEY"
{ "data": { "id": "…", "name": "Example", … } }

{
  "data": [ … ],
  "pagination": {
    "cursor": null,
    "next_cursor": null,
    "prev_cursor": null,
    "limit": 50,
    "has_more": false
  }
}
  • The envelope applies to every call made with an API key. A response that already carries a top-level data or error is passed through unchanged.
  • 204 No Content has no body. File downloads such as report exports are not JSON and are not wrapped.
  • New fields can appear in a response; the changelog lists them as added. Ignore fields you do not know.

Errors

Every 4xx and 5xx response uses one object, with Content-Type: application/json. Errors are not wrapped in data.

{
  "error": {
    "code": "insufficient_scope",
    "message": "API token does not have the required scope",
    "request_id": "req_…",
    "details": { "required_scope": "monitor.write" }
  }
}
FieldMeaning
error.codeA stable identifier in snake_case. Branch on this.
error.messageA sentence for people. It can change; do not match on it.
error.request_idThe id of this request, the same as the X-Request-Id response header.
error.detailsOnly present when there is more to say: field names the invalid field, required_scope the missing scope, original_request_at the first use of an idempotency key.

Every code, with its status and cause, is in the error catalogue.

Status codes

A status without a more specific code gets the default code below. Many errors carry a specific code instead, such as cursor_expired or idempotency_key_conflict.

StatusDefault error.codeUsually means
400bad_requestThe request is malformed or a field is invalid. A field error adds details.field.
401unauthorizedNo valid key. See API keys and scopes.
402payment_requiredThe Company’s plan or billing state does not allow the action.
403permission_deniedRefused. Scope errors use their own codes, see API keys and scopes.
404not_foundThe resource does not exist, or your key cannot see it.
409conflictThe request conflicts with the current state. Idempotency conflicts use their own codes.
429rate_limit_exceededToo many requests. Wait for Retry-After.
503service_unavailableA deliberate notice, for example a feature that is not available right now. The message is meant to be read.
other 5xxinternal_errorOur fault. The message is always “Internal server error”; send us the request_id.

Any other status falls back to request_failed.

Request ids

Every response, success or failure, carries X-Request-Id. If you send the header, up4 uses your value; otherwise it generates req_ followed by a UUID. Log it, and quote it when you contact support.

curl -si https://app.upfour.io/v1/me \
  -H "Authorization: Bearer $UP4_API_KEY" \
  -H "X-Request-Id: nightly-sync-2026-10-27" | grep -i '^x-request-id'

Common mistakes

  • Matching on error.message. Match on error.code and the status.
  • Reading data on an error response. There is none.
  • Expecting a body on 204.
  • Treating every 403 as “not allowed for good”. A missing scope or a read-only key can be fixed with a new key.
  • Retrying a 5xx or timed-out POST without an Idempotency-Key. With one, a retry returns the stored answer when the first request finished below 500; a 5xx itself is not stored. See idempotency.