Error handling
Every error response follows RFC 7807 (application/problem+json). This page lists every status code the API emits, whether the client should retry, and what action is appropriate.
Response shape
HTTP/2 404
content-type: application/problem+json
{
"type": "https://developer.messpunkt.io/errors/#resource-not-found",
"title": "Resource not found",
"status": 404,
"detail": "Property d490d09c-46cc-498e-a9ac-e031dd2402d2 not found in this Tenant's scope",
"trace_id": "e9048b1072c8443b"
}
type is a stable identifier you can branch on in code: https://developer.messpunkt.io/errors/#<code> in sandbox and production, pointing at the row for that code below — branch on the fragment after #; title is human-readable but may be localised in the future; trace_id is the single best thing to include when you open a support ticket.
Status-code matrix
Applies to all /v1/* data endpoints. OAuth endpoints (/oauth/*) use the OAuth 2.0 error format (RFC 6749 §5.2) — see the OAuth table below.
| Status | type fragment |
Retryable? | Recommended client action |
|---|---|---|---|
400 |
invalid-request |
No | Malformed or invalid request — missing required query parameter, bad date format, to before from, a range that lies entirely after the last completed month, unknown metric value (named in detail), limit outside 1–200, a page_cursor not issued by the API, a property_id that is not a UUID. detail says which. Fix the request, do not retry. |
401 |
invalid-token |
After refresh | Access token missing, expired, malformed, issued for another audience, a refresh token sent as access token, or the landlord's API access has ended (also on /whoami — never 404). Refresh the token via grant_type=refresh_token and retry once. If refresh also fails, restart the authorization flow. For tokens bound to a DPoP key, a failed proof (wrong htu/htm, clock skew, reused jti, key not matching cnf.jkt) also returns 401, with WWW-Authenticate: DPoP error="invalid_dpop_proof" — fix the proof generation instead of refreshing, see the DPoP guide. |
403 |
insufficient-scope |
No | Token is valid but lacks a scope required for this endpoint (e.g. calling a read:readings endpoint with only read:units). Re-authorize requesting the missing scope. |
404 |
resource-not-found |
No | Either the resource doesn't exist, or it exists but is outside your Property scope; an ID in the path that is not a UUID gets the same answer. The API deliberately does not distinguish these — see Property scope in the Reference. Treat 404 on a previously-known ID as "access revoked"; refresh your Property list via /whoami and re-fetch /properties. |
429 |
too-many-requests |
Yes | Rate limit exceeded, on /v1/* and on the OAuth endpoints alike (both answer with this type). Honour the Retry-After header (seconds). Use exponential backoff for bursty loads — see Retry strategy below. |
500 |
internal-error |
Yes | Unexpected server error. No detail, no stack trace. Retry with exponential backoff. Include trace_id if you escalate. |
503 |
service-unavailable |
Yes | A dependency needed to check the token or the connection is temporarily unavailable. The request was refused, not served — the API never answers with data it could not authorize. No detail. Retry with exponential backoff. |
502 / 503 / 504 |
(platform-level, may not be problem+json) |
Yes | Gateway or cold-start transient. Retry with exponential backoff. Usually resolves within a few seconds. |
OAuth endpoint errors
The /oauth/authorize and /oauth/token endpoints follow RFC 6749 §5.2 — a flat {"error": "...", "error_description": "..."} body:
error |
Meaning | Action |
|---|---|---|
invalid_request |
Missing or malformed parameter on the request. | Fix and retry. |
invalid_client |
Unknown client_id, or client_id mismatch between the authorization code and the token request. |
Fix client config. Do not retry the same request. |
invalid_grant |
Authorization code is expired, wrong redirect_uri, PKCE verifier doesn't match, refresh token is replayed or the session was revoked. |
Restart the authorization flow — do not retry. If this happened on refresh, the refresh-token family was revoked: the user must re-consent. |
invalid_scope |
Requested a scope that's not in the original grant (refresh-time scope narrowing only). | Request a subset of the original scopes, or re-authorize to widen. |
invalid_target |
The resource parameter (RFC 8707) names a resource this server does not issue tokens for. |
Use https://api.messpunkt.io for this REST API (the MCP server has its own resource). |
unsupported_grant_type |
Only authorization_code and refresh_token are supported. |
Fix the request. |
invalid_redirect_uri |
The redirect_uri is not on the allow-list for this client_id. |
Use a registered redirect URI, or contact us to register a new one. |
Retry strategy
For 429 and 5xx responses, use exponential backoff with jitter:
- Attempt 1: wait max(
Retry-After, 1 s) - Attempt 2: wait 2 s ± 500 ms random jitter
- Attempt 3: 4 s ± 1 s
- Attempt 4: 8 s ± 2 s
- Attempt 5: 16 s ± 4 s
- Stop at 5 retries. Log
trace_id, surface a user-facing message, and continue.
GET and safe to retry. Write endpoints do not exist yet; how they will handle retries (a mandatory Idempotency-Key) is described on the roadmap.
Getting help
When you open a support ticket, always include:
- The
trace_idfrom the response body - The UTC timestamp of the request
- Your
client_id - The HTTP method + path (without secrets)
Email: kontakt@messpunkt.io — we respond within 3 business days during the pilot phase.