Error Handling
The Flow API uses a consistent error response format to help you handle errors gracefully in your application.
Error Response Format
All errors follow this structure:
{
"error": {
"type": "error_type",
"message": "Human-readable error message",
"code": "ERROR_CODE",
"details": [
{
"field": "field_name",
"message": "Field-specific error message"
}
]
},
"meta": {
"request_id": "req_abc123",
"timestamp": 1703123456000
}
}
Error Types
authentication_error (401)
Returned when authentication fails or is missing.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "INVALID_API_KEY"
}
}
Common causes:
- Missing
Authorizationheader - Invalid API key format
- Revoked or expired API key
authorization_error (403)
Returned when the authenticated user doesn't have permission to perform the action.
{
"error": {
"type": "authorization_error",
"message": "You don't have permission to access this resource",
"code": "FORBIDDEN"
}
}
not_found (404)
Returned when a requested resource doesn't exist.
{
"error": {
"type": "not_found",
"message": "Post not found",
"code": "RESOURCE_NOT_FOUND"
}
}
validation_error (400)
Returned when request validation fails.
{
"error": {
"type": "validation_error",
"message": "Validation failed",
"code": "VALIDATION_ERROR",
"details": [
{
"field": "content",
"message": "Content is required"
},
{
"field": "channelId",
"message": "Channel ID must be a valid UUID"
}
]
}
}
rate_limit_error (429)
Returned when the rate limit is exceeded.
{
"error": {
"type": "rate_limit_error",
"message": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"details": [
{
"message": "Retry after 45 seconds"
}
]
},
"meta": {
"request_id": "req_abc123",
"timestamp": 1703123456000
}
}
Response headers:
X-RateLimit-Limit: Maximum requests per window (100)X-RateLimit-Remaining: Remaining requests in current windowX-RateLimit-Reset: Unix timestamp when the limit resets
server_error (500)
Returned when an internal server error occurs.
{
"error": {
"type": "server_error",
"message": "Internal server error",
"code": "INTERNAL_ERROR"
}
}
Handling Errors
TypeScript (with SDK)
import { Flow, FlowError } from '@flowdev/sdk';
const flow = new Flow('flow_sk_live_...');
try {
const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Hello, world!',
});
} catch (error) {
if (error instanceof FlowError) {
switch (error.type) {
case 'validation_error':
console.error('Validation failed:', error.details);
break;
case 'rate_limit_error':
console.error('Rate limit exceeded, retry after:', error.retryAfter);
// Wait and retry
await new Promise(resolve => setTimeout(resolve, error.retryAfter * 1000));
break;
case 'authentication_error':
console.error('Invalid API key');
break;
default:
console.error('API error:', error.message);
}
}
}
JavaScript (fetch)
async function createPost(apiKey, data) {
const response = await fetch('https://api.flowsocial.app/v1/posts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
const error = await response.json();
if (response.status === 429) {
// Rate limit exceeded
const retryAfter = parseInt(response.headers.get('X-RateLimit-Reset')) - Date.now() / 1000;
console.error('Rate limit exceeded, retry after:', retryAfter, 'seconds');
return;
}
if (response.status === 400) {
// Validation error
console.error('Validation errors:', error.error.details);
return;
}
console.error('API error:', error.error.message);
return;
}
return await response.json();
}
Python
import requests
import time
def create_post(api_key, data):
response = requests.post(
'https://api.flowsocial.app/v1/posts',
headers={
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json',
},
json=data,
)
if response.status_code == 429:
# Rate limit exceeded
retry_after = int(response.headers.get('X-RateLimit-Reset', 0)) - int(time.time())
print(f'Rate limit exceeded, retry after {retry_after} seconds')
return None
if response.status_code == 400:
# Validation error
error = response.json()
print('Validation errors:', error['error']['details'])
return None
if not response.ok:
error = response.json()
print('API error:', error['error']['message'])
return None
return response.json()
Retry Logic
Exponential Backoff
For rate limit errors and server errors, implement exponential backoff:
async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error instanceof FlowError && error.type === 'rate_limit_error') {
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
Best Practices
- Always check response status before processing data
- Handle rate limits gracefully with exponential backoff
- Log request IDs for debugging (included in error responses)
- Validate input before sending requests to avoid validation errors
- Implement retry logic for transient errors (5xx, rate limits)
- Don't retry on client errors (4xx) except rate limits
Request IDs
Every API response (including errors) includes a request_id in the meta field. Use this when contacting support:
Request ID: req_abc123def456
This helps us quickly locate and debug issues.