The Skills Fest

Errors

Every error is an RFC 9457 problem document with Content-Type: application/problem+json:

{
  "type": "https://www.theskillsfest.com/developers/errors/insufficient_data_class",
  "title": "Insufficient data class",
  "status": 403,
  "detail": "This key cannot write background_check. Grant the data:safeguarding scope.",
  "instance": "/api/v1/members/external/acme-membership/U-1042",
  "request_id": "req_01K3XQ7YB4N2M",
  "errors": [{ "field": "background_check", "message": "requires data:safeguarding" }]
}

Branch on type, not on the wording of detail. The type URIs are part of the v1 contract and will not change.

Every error type

unauthorized — 401

The key is missing, malformed, revoked, expired, or belongs to a workspace that is no longer active. The response is deliberately identical for all of these, so it cannot be used to work out which keys exist.

api_disabled — 403

The key is valid but the API is off for this workspace — either it was never enabled, or an Owner switched it off in Settings → API. Takes effect on the very next request.

ip_not_allowed — 403

This key has an IP allowlist and the request did not come from one of them.

insufficient_scope — 403

The key lacks a resource scope this endpoint needs. The missing scopes are named in errors[].

insufficient_data_class — 403

The request touched a field outside the key’s data classes. The field is named. We refuse rather than accepting the write and dropping that field silently.

workspace_paused — 403

The workspace is paused for billing and is read-only. Reads and exports keep working; writes resume when billing does.

addon_required — 403

The endpoint needs an add-on this workspace does not have — lodging, today. Separate from scopes: holding lodging:read is not enough on its own.

not_found — 404

No such resource in this workspace. A resource that exists in a different workspace also answers 404 — a 403 would confirm it exists.

method_not_allowed — 405

The path exists but not with this HTTP method.

conflict — 409

The request conflicts with the current state of the resource.

idempotency_in_progress — 409

A request with this Idempotency-Key is still running. Wait and retry with the same key.

idempotency_key_reuse — 422

This Idempotency-Key was already used for a different request body. We refuse rather than returning the earlier result, which would answer a question you did not ask.

unprocessable_entity — 422

The request was understood but cannot be processed: a missing or unknown field, a malformed cursor, or a batch over the limit. Details are in errors[].

payload_too_large — 413

The request or the requested export is too big — a CSV over the row cap, for instance. Use the paginated JSON endpoint.

rate_limited — 429

Too many requests for this key. Retry-After says how long to wait; the RateLimit-* headers on every response let you slow down before this happens.

internal_error — 500

Something went wrong on our side. Quote the request_id if you contact us — it identifies the exact call.

service_unavailable — 503

The API is temporarily unable to serve requests. This is deliberately not a 401: when we cannot verify a key we refuse rather than guessing.