Errors
The API uses standard HTTP status codes and returns errors in a consistent format.
Error Response Format
There are two error shapes, and which one you get depends on WHY the call failed rather than on which endpoint you called. Handle both.
Request errors use a nested object. error.code is stable and safe to branch on; error.message is for humans and may be reworded.
{
"error": {
"code": "INVALID_DECK_SIZE",
"message": "This Commander deck has 98 cards. ... Add 2 cards and try again.",
"details": { "totalCards": 98, "expected": 100, "delta": 2, "direction": "add" },
"documentation": "https://dev.spellweave.app/docs/errors/"
}
}details is present when there is something actionable to report, and carries the values you need to tell your user what to change.
Authentication, scope and rate-limit errors (401, 403, 429) use the flat OAuth 2.0 shape instead, on every endpoint including the resource endpoints. Here error is a STRING, not an object, so error.code is undefined.
{
"error": "insufficient_scope",
"error_description": "Requires scope: decks:write"
}A parser that assumes error is always an object will read undefined for every auth failure and report it as an unknown error. Check the type, or branch on the HTTP status first.
HTTP Status Codes
| Status | Meaning | When |
|---|---|---|
200 | OK | Request succeeded |
400 | Bad Request | Invalid parameters or malformed request |
401 | Unauthorized | Missing, invalid, or expired access token |
403 | Forbidden | Valid token but insufficient scope for this endpoint |
404 | Not Found | Resource does not exist or is not owned by the authenticated user |
429 | Too Many Requests | Rate limit exceeded. Check the Retry-After header. |
500 | Server Error | Something went wrong on our end. Please retry. |
OAuth Errors
The OAuth endpoints (/authorize, /token, /revoke) return errors in the OAuth 2.0 format, as do 401, 403 and 429 responses from every other endpoint:
{
"error": "invalid_grant",
"error_description": "Authorization code is invalid, expired, or already used"
}| Error | Description |
|---|---|
invalid_request | Missing required parameter or malformed request |
invalid_client | Client authentication failed (wrong secret or unknown client_id) |
invalid_grant | Authorization code or refresh token is invalid, expired, or already used |
invalid_scope | Requested scope is invalid or not authorized for this app |
unsupported_response_type | Only 'code' is supported |
unsupported_grant_type | Only 'authorization_code' and 'refresh_token' are supported |
access_denied | User denied the authorization request |