Error Handling
Error codes, rate limits, and how to handle API errors.
This page covers the error responses returned by the Adopture API, rate limiting behavior, and best practices for handling failures.
HTTP Status Codes
| Status | Error Code | Description |
|---|---|---|
202 | -- | Events accepted successfully |
400 | validation_failed | Request body does not match the expected schema |
400 | invalid_json | Request body is not valid JSON |
401 | invalid_app_key | App key not found or has an invalid format |
402 | subscription_inactive | Subscription is canceled, unpaid, or paused |
402 | trial_expired | Free trial has ended |
405 | method_not_allowed | Only POST requests are accepted |
413 | payload_too_large | Request body exceeds 512 KB |
415 | unsupported_media_type | Content-Type must be application/json |
429 | rate_limit_exceeded | Per-minute rate limit exceeded |
429 | monthly_limit_exceeded | Monthly event limit exceeded |
429 | daily_limit_exceeded | Daily event limit exceeded |
503 | service_overloaded | Server is temporarily overloaded |
Error Response Format
Error responses include a JSON body with the error code and a human-readable message:
{
"error": "validation_failed",
"message": "events[0].name is required"
}Rate Limits
Limits by Plan
| Plan | Events/Month | Events/Minute |
|---|---|---|
| Trial | 10,000 | 200 |
| 10K | 10,000 | 200 |
| 100K | 100,000 | 500 |
| 500K | 500,000 | 2,000 |
| 1M | 1,000,000 | 5,000 |
| 2M | 2,000,000 | 8,000 |
| 5M | 5,000,000 | 15,000 |
Rate Limit Headers
Every response includes these headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per minute |
X-RateLimit-Remaining | Remaining requests in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Handling Rate Limits
When you receive a 429 response, check the Retry-After header for the number of seconds to wait before retrying:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312800Monthly Limit Behavior
- Paid plans have a 10% grace buffer above the stated monthly limit. For example, the 100K plan will accept up to 110,000 events before enforcement.
- Trial plans are enforced at the exact limit with no grace buffer.
Once the monthly limit is reached, the API returns 429 with the monthly_limit_exceeded error code until the next billing cycle.
Idempotency
Include an Idempotency-Key header with a UUID to safely retry failed requests without creating duplicate events:
POST /api/v1/events HTTP/1.1
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000The server remembers idempotency keys for 300 seconds (5 minutes). If a duplicate request is received within that window, the server returns the original response with an additional field:
{
"status": "accepted",
"events": 1,
"deduplicated": true
}Best Practices
- Batch events — Send multiple events per request (up to 100) to reduce the number of API calls
- Use idempotency keys — Always include an
Idempotency-Keywhen retrying requests to avoid duplicate events - Respect Retry-After — When rate-limited, wait the indicated number of seconds before retrying
- Handle 503 gracefully — Queue events locally and retry with exponential backoff when the service is temporarily overloaded