Error Handling
Learn how to handle errors from the Flow Myna API. All errors follow a consistent format and use standard HTTP status codes.
HTTP Status Codes
| Code | Meaning | When It Occurs |
|---|---|---|
| 200 | Success | Request completed successfully |
| 401 | Unauthorized | Missing, invalid, revoked, or expired API key |
| 422 | Validation Error | Invalid request body (missing fields, wrong types) |
| 429 | Rate Limited | Too many requests (future implementation) |
| 500 | Server Error | Something went wrong on our end |
404 is rare — The API auto-creates objects, object types, and event types, so you won't get 404 errors for missing resources.
Error Response Format
All error responses follow this consistent format:
Error Response Format
{
"detail": "Human-readable error message"
}Authentication Errors (401)
Missing API Key
{
"detail": "Missing API key. Use 'Authorization: Bearer fm_live_...' or 'X-FlowMyna-Api-Key: fm_live_...'"
}Fix: Include the Authorization header in your request.
Invalid API Key Format
{
"detail": "Invalid API key format. Keys must start with 'fm_live_'"
}Fix: Ensure your key starts with fm_live_ and is 40 characters.
Invalid API Key
{
"detail": "Invalid API key"
}Fix: Check that you're using the correct key from your dashboard.
Revoked Key
{
"detail": "API key has been revoked"
}Fix: Create a new API key in your dashboard.
Expired Key
{
"detail": "API key has expired"
}Fix: Create a new API key or one without an expiration date.
Validation Errors (422)
Validation errors occur when your request body doesn't match the expected schema:
| Field | Constraint |
|---|---|
event | Required, 1-200 characters |
objects | Required, at least 1 item |
objects[].type | Required, 1-100 characters |
objects[].id | Required, 1-500 characters |
timestamp | Optional, valid ISO 8601 format |
Validation Error Example
{
"detail": [
{
"loc": ["body", "event"],
"msg": "field required",
"type": "value_error.missing"
},
{
"loc": ["body", "objects"],
"msg": "ensure this value has at least 1 items",
"type": "value_error.list.min_items"
}
]
}Retry Logic
Implement exponential backoff for transient errors:
Retry Implementation
import time
import random
import requests
def record_with_retry(event_data, max_retries=3):
"""Record event with exponential backoff retry"""
for attempt in range(max_retries):
try:
response = requests.post(
f"{BASE_URL}/event",
json=event_data,
headers=headers,
timeout=30
)
# Success
if response.status_code == 200:
return response.json()
# Don't retry client errors (except rate limits)
if response.status_code in [401, 422]:
raise ValueError(f"Client error: {response.json()}")
# Retry server errors and rate limits
if response.status_code in [429, 500, 502, 503, 504]:
if attempt == max_retries - 1:
raise Exception(f"Max retries exceeded: {response.text}")
except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
# Exponential backoff with jitter
wait_time = (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait_time)
raise Exception("Unexpected retry exit")Our SDKs handle retries automatically. The Python and Node.js SDKs include built-in retry logic with exponential backoff.