# API error contract Application-owned HTTP APIs use Problem Details per RFC 7807 / RFC 9457, matching `game-ingest-server`. Every error response has media type `application/problem+json` and the shape: ```json { "type": "urn:error:invalid-velocity-access-request", "title": "Invalid Velocity access request", "status": 400, "detail": "The request body does not match the required Velocity access contract.", "instance": "/api/velocity/access", "extensions": { "issues": [ { "path": "minecraftUuid", "message": "Expected a compact Java Edition UUID", "code": "invalid_format" } ] } } ``` `type`, `title`, and `status` are required. `detail`, `instance`, and `extensions` are included when relevant. ## Problem catalog | Type | Status | Meaning | | --- | ---: | --- | | `urn:error:invalid-velocity-access-request` | 400 | Access request JSON does not satisfy the shared Velocity contract | | `urn:error:invalid-velocity-connection-request` | 400 | Confirmed-connection JSON does not satisfy the shared Velocity contract | | `urn:error:unauthorized` | 401 | Velocity bearer credential is missing, invalid, or revoked | | `urn:error:expired-velocity-access-request` | 401 | Access timestamp is outside the accepted clock-skew window | | `urn:error:expired-velocity-connection-request` | 401 | Connection timestamp is outside the accepted clock-skew window | | `urn:error:not-found` | 404 | Unknown application-owned API route | | `urn:error:unknown-minecraft-account` | 404 | Connection telemetry references an inactive or unknown account | | `urn:error:method-not-allowed` | 405 | The endpoint does not support the requested HTTP method | | `urn:error:replayed-velocity-access-request` | 409 | Admission request ID was already processed | | `urn:error:replayed-velocity-connection-request` | 409 | Confirmed-connection request ID was already processed | | `urn:error:unsupported-media-type` | 415 | The request does not use `application/json` | | `urn:error:service-unavailable` | 503 | A safe access decision could not be completed | A whitelist denial remains an HTTP `200` response containing `{ "allowed": false, "message": "..." }`. That response is a successfully evaluated authorization decision, not an HTTP error. Browser server actions continue to use redirects and accessible HTML messages. OAuth protocol responses under `/api/auth/*` are owned by NextAuth and follow that protocol's response behavior.