Skip to main content

Errors

Every 4xx and 5xx response carries a JSON body. Three response formats are in use across the API; the format you'll get is fully determined by the kind of error, not by which endpoint you called. They are:

  1. Problem detailsapplication/problem+json, RFC 7807. Used for cross-cutting failures: rate-limit, idempotency, missing or invalid token, missing scope, unknown public route.
  2. Standard errorsapplication/json, { errors: [...], request_id }. Used for resource-level and validation failures from specific endpoints.
  3. OAuth errorsapplication/json, RFC 6749 §5.2 { error, error_description }. Used only by POST /oauth/token and POST /oauth/revoke for compatibility with standard OAuth 2.0 client libraries.

Use the HTTP status code as your primary signal; the body adds context. Always read X-Request-Id from response headers — it identifies the call across our logs regardless of which body format you got back.

1. Problem details (RFC 7807)

HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 42
X-Request-Id: 550e8400-e29b-41d4-a716-446655440000

{
"type": "https://developer.risepeople.com/errors/rate-limit-exceeded",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit exceeded. Try again in 42 seconds.",
"instance": "/v1/employees"
}
FieldAlwaysPurpose
typeyesStable URI identifying the problem class. Use this URI as a programmatic match key — we won't rename it.
titleyesShort human-readable summary.
statusyesHTTP status code (duplicated for clients that lose it).
detailusuallySpecific explanation for this occurrence.
instanceusuallyPath the error refers to, for tracing.

Known problem types — each has its own page describing causes and fixes:

Type URI suffixStatusPage
/errors/rate-limit-exceeded429rate-limit-exceeded
/errors/idempotency-key-reuse409idempotency-key-reuse
/errors/idempotency-key-too-long400idempotency-key-too-long
/errors/insufficient-scope403insufficient-scope
/errors/token-unauthorized401token-unauthorized
/errors/public-api-not-found404public-api-not-found

The type URI in any RFC 7807 response body deep-links to the matching page above.

2. Standard errors

For resource-level and validation failures from specific endpoints:

HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: 550e8400-e29b-41d4-a716-446655440000

{
"errors": [
{ "code": "not_found", "detail": "No employee with id `unknown` in this account." }
],
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
FieldAlwaysPurpose
errorsyesAlways an array — even for a single error. Validation failures populate one entry per offending field.
errors[].codeyesShort machine-readable identifier.
errors[].detailusuallyHuman-readable explanation. Sensitive details are omitted from 5xx bodies in production.
request_idusuallyUUID echoing X-Request-Id from the response headers.

Codes you may see today:

CodeStatusWhen
invalid_params400Bad query string, path parameter, or request body
invalid_token401Token rejected during request handling
token_expired401Token past exp — refresh it
forbidden403Authenticated but not authorized for this resource
not_found404Resource doesn't exist in this account
unsupported_media_type415Wrong Content-Type for this endpoint
validation_error422Business-rule failure — see errors[] for each offending field
internal_server_error500Our bug — safe to retry

For human-readable context on any specific code, see the affected endpoint in the API Reference. Match codes exactly in your error handling, but be defensive: a future code you haven't seen before should fall through to a generic handler rather than crash.

Validation errors (422)

Validation failures populate one entry per offending field. The exact extension fields vary per endpoint; minimum is code and detail.

{
"errors": [
{ "code": "invalid_value", "detail": "birth_date must be before hire_date", "source": { "pointer": "/data/attributes/birth_date" } },
{ "code": "already_taken", "detail": "email is already in use by another employee", "source": { "pointer": "/data/attributes/email" } }
],
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}

source.pointer is a JSON Pointer (RFC 6901) into the request body where applicable.

3. OAuth errors (RFC 6749)

POST /oauth/token and POST /oauth/revoke follow RFC 6749 §5.2 so standard OAuth client libraries parse them out of the box:

{
"error": "invalid_client",
"error_description": "Client authentication failed."
}
errorStatusWhen
invalid_request400Required parameter missing or malformed
invalid_client401Bad client_id / client_secret
invalid_grant400Authorization code or refresh token is invalid or expired
invalid_scope400Requested scope is unknown or not allowed for this client
unauthorized_client400Client isn't allowed to use this grant type
unsupported_grant_type400grant_type value isn't recognized
access_denied403Resource owner refused authorization

When to retry

StatusRetry?
400, 401, 403, 404, 409, 422No — your code is wrong, retrying won't change it
429Yes, after Retry-After seconds
5xxYes, with exponential backoff (see Rate limits)
Network timeout (no response)Yes, with an Idempotency-Key — otherwise you risk double-writes

Reporting a problem

Open a ticket at support.risepeople.com and include:

  1. The full X-Request-Id from the response headers
  2. The request method, path, and (for writes) body
  3. The full error response body and Content-Type
  4. Your client_id (not the secret!)
  5. The time (in ISO 8601 with timezone) you made the request

With those five pieces we can usually pinpoint the cause in a single round-trip.