Skip to main content

Errors

SpeyBooks uses conventional HTTP status codes and returns structured, machine-readable error information in JSON.

Error responses are stable and designed to be handled programmatically.

HTTP status codes

CodeMeaning
200Success
201Resource created
204No content (successful deletion)
400Bad request — invalid parameters
401Unauthorized — missing or invalid API key
403Forbidden — valid key, insufficient permissions
404Not found — resource does not exist
409Conflict — resource already exists
422Unprocessable entity — validation failed
429Too many requests — rate limit exceeded
500Server error — internal failure

HTTP status codes indicate request outcome, not business meaning. Use the error payload for precise handling.

Error response format

All errors follow the same structure.

{
"success": false,
"error": {
"code": "validation_error",
"message": "The 'email' field is required",
"field": "email"
}
}

Error fields

FieldDescription
codeStable, machine-readable error code
messageHuman-readable description
fieldField that caused the error (when applicable)

The field property is included only for validation errors.

Error codes

Authentication errors

CodeDescription
unauthorizedMissing or invalid API key
forbiddenAPI key valid but lacks permission

Validation errors

CodeDescription
validation_errorRequest data failed validation
required_fieldRequired field is missing
invalid_formatField has an invalid format
invalid_valueField value is not permitted
invalid_idMalformed resource ID

Validation errors always return HTTP 422.

Resource errors

CodeDescription
not_foundResource does not exist
already_existsResource with the same identifier exists
conflictResource state prevents the operation
unprocessable_entityBusiness rule prevents the operation

Rate limiting

CodeDescription
rate_limit_exceededToo many requests

When rate limited, the response includes a Retry-After header.

HTTP/1.1 429 Too Many Requests
Retry-After: 30
{
"success": false,
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry after 30 seconds."
}
}

Clients should respect the Retry-After value before retrying.

Server errors

CodeDescription
internal_errorInternal server error
service_unavailableTemporary outage

Server errors indicate failures on the SpeyBooks side. They are safe to retry with appropriate backoff.

Handling errors

Clients should handle errors by inspecting both the HTTP status code and the error payload.

Example (JavaScript)

try {
const response = await fetch('https://api.speybooks.com/v1/invoices', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(invoiceData)
});

const result = await response.json();

if (!result.success) {
const { error } = result;

switch (error.code) {
case 'validation_error':
console.error(
`Validation failed: ${error.message}` +
(error.field ? ` (${error.field})` : '')
);
break;

case 'unauthorized':
console.error('Invalid or missing API key');
break;

case 'rate_limit_exceeded':
const retryAfter = response.headers.get('Retry-After');
console.error(`Rate limited. Retry after ${retryAfter}s`);
break;

default:
console.error(`API error: ${error.message}`);
}
}
} catch (err) {
console.error('Network error:', err);
}

Key principles

  • Errors are explicit and structured
  • Error codes are stable and machine-readable
  • Validation failures are precise and field-level
  • Rate limits communicate retry timing
  • Server errors do not leak internal details

Error handling in SpeyBooks is designed to be predictable, composable, and safe to automate.