Errors
ZetPin uses OAuth-style error objects across both the OAuth and API surfaces. Each error carries a machine-readable code and a human-readable description.
Error format
Errors are returned as a JSON object with an error code and an error_description. Branch on error in code; show or log error_description for humans.
json
{
"error": "invalid_grant",
"error_description": "The authorization code is expired or has already been used."
}Common error codes
| Code | HTTP | Meaning |
|---|---|---|
invalid_grant | 400 | The authorization code or refresh token is bad, expired, already used, or (for refresh tokens) reused after rotation. |
invalid_client | 401 | Client authentication failed — wrong client_id or client_secret. |
invalid_token | 401 | The access token is malformed, expired, or revoked. Returned with a WWW-Authenticate header. Refresh or re-authorize. |
insufficient_scope | 403 | The token is valid but wasn't granted the scope this endpoint requires. |
access_denied | — | The user declined consent on the authorize page. Returned on the redirect, not the API. |
quota_exceeded | 429 | The app's monthly post quota is used up. See Rate limits & quotas. |
401 and WWW-Authenticate
When an access token is rejected, the API returns 401 with a WWW-Authenticate header describing the failure, per the OAuth 2.0 Bearer token spec. Use it to decide whether to refresh the token or restart the authorization flow.
http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token",
error_description="The access token expired"
{
"error": "invalid_token",
"error_description": "The access token expired"
}Handling errors
Oninvalid_token, refresh and retry (see Refreshing & revoking). On insufficient_scope, re-run the authorize flow requesting the missing scope (see Scopes). On invalid_grant for a refresh token, assume the grant is gone and prompt the user to reconnect.