Skip to main content

Error Handling

All SendSeven API errors follow a consistent JSON structure. This guide covers error codes, handling strategies, and retry logic.

Error response format

{
"detail": "Human-readable error message",
"error_code": "MACHINE_READABLE_CODE"
}

Validation errors include field-level details:

{
"detail": "Validation error",
"error_code": "VALIDATION_ERROR",
"errors": [
{ "field": "email", "message": "Invalid email format" },
{ "field": "phone", "message": "Phone number must include country code" }
]
}

HTTP Status Codes

Success codes

CodeNameWhen Used
200OKGET, PUT, PATCH, DELETE
201CreatedPOST that creates a resource
204No ContentDELETE with no response body

Client errors

CodeNameAction
400Bad RequestCheck request format
401UnauthorizedVerify API token
403ForbiddenCheck token scopes
404Not FoundVerify resource ID and tenant
409ConflictDuplicate resource exists
422Unprocessable EntityCheck field validation rules
429Too Many RequestsWait and retry (see Rate Limits)

Server errors

CodeNameAction
500Internal Server ErrorRetry after delay; contact support if persistent
503Service UnavailableRetry with exponential backoff

Error Codes Reference

INVALID_TOKEN

HTTP 401 - Token is missing, malformed, or expired.

{
"detail": "Invalid or expired authentication token",
"error_code": "INVALID_TOKEN"
}

Fix: Verify the Authorization header format (Bearer s7_api_<32hex>), check expiration, or create a new token.

INSUFFICIENT_SCOPE

HTTP 403 - Token lacks the required permission.

{
"detail": "Missing required scope: campaigns:create",
"error_code": "INSUFFICIENT_SCOPE"
}

Fix: The detail message tells you exactly which scope is missing. Create a token with that scope.

RESOURCE_NOT_FOUND

HTTP 404 - Resource doesn't exist or belongs to a different tenant.

{
"detail": "Conversation not found",
"error_code": "RESOURCE_NOT_FOUND"
}

Fix: Verify the resource ID and that your API token is associated with the correct account.

VALIDATION_ERROR

HTTP 422 - Request body failed validation.

{
"detail": "Validation error",
"error_code": "VALIDATION_ERROR",
"errors": [
{ "field": "email", "message": "Invalid email format" },
{ "field": "phone", "message": "Phone number must include country code (e.g., +1)" }
]
}

Fix: Check the errors array for specific field-level issues.

RATE_LIMITED

HTTP 429 - Too many requests.

{
"detail": "Rate limit exceeded. Retry after 45 seconds.",
"error_code": "RATE_LIMITED"
}

Fix: Read the Retry-After header and wait before retrying. See Rate Limits.

INSUFFICIENT_BALANCE

HTTP 402 - Account has exceeded trial limits or payment failed.

{
"detail": "Insufficient balance to send message.",
"error_code": "INSUFFICIENT_BALANCE"
}

Fix: Check billing status in Settings > Billing, update payment method, or upgrade plan.

DUPLICATE_RESOURCE

HTTP 409 - A resource with the same unique identifier already exists.

{
"detail": "A tag with this name already exists",
"error_code": "DUPLICATE_RESOURCE"
}

Fix: Use a different name or update the existing resource.

Implementing Error Handling

Python

import time
import requests

def api_request_with_retry(method, url, max_retries=5, **kwargs):
headers = {
"Authorization": "Bearer s7_api_your_token",
"Content-Type": "application/json",
}
kwargs.setdefault("headers", headers)

for attempt in range(max_retries):
response = requests.request(method, url, **kwargs)

if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
time.sleep(retry_after)
continue

if response.status_code >= 500:
time.sleep(2 ** attempt)
continue

return response

raise Exception(f"Failed after {max_retries} retries")

JavaScript

async function apiRequest(method, path, body = null) {
const url = `https://api.sendseven.com/api/v1${path}`;
const options = {
method,
headers: {
'Authorization': 'Bearer s7_api_your_token',
'Content-Type': 'application/json',
},
};
if (body) options.body = JSON.stringify(body);

const response = await fetch(url, options);

if (response.ok) return response.json();

const error = await response.json();

switch (error.error_code) {
case 'INVALID_TOKEN':
throw new Error('Authentication failed - check your API token');
case 'INSUFFICIENT_SCOPE':
throw new Error(`Missing permission: ${error.detail}`);
case 'RATE_LIMITED':
const retryAfter = response.headers.get('Retry-After') || 60;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return apiRequest(method, path, body); // retry
case 'VALIDATION_ERROR':
throw new Error(`Validation: ${error.errors?.map(e => `${e.field}: ${e.message}`).join(', ')}`);
default:
throw new Error(error.detail || 'Unknown error');
}
}

Retry guidelines

StatusRetry?Reason
400NoFix the request
401NoFix authentication
403NoFix permissions
404NoResource doesn't exist
409NoResolve conflict
422NoFix validation errors
429YesWait for rate limit reset
500YesTransient server error
503YesService temporarily unavailable
tip

Only retry on 429 and 5xx errors. Client errors (4xx) indicate a problem with the request itself.