Forlena CRM API
Error Handling
Use error codes for machine branching, and retry only when it is safe.
| HTTP | Code | Meaning | Action |
|---|---|---|---|
| 400 | VALIDATION_ERROR | Request shape or field values are invalid. | Fix payload and retry. |
| 401 | INVALID_KEY | API key is missing, malformed, or unknown. | Use valid Authorization header. |
| 401 | KEY_REVOKED | API key was revoked by admin. | Generate a new key. |
| 401 | SUBSCRIPTION_INACTIVE | Organization subscription/trial is inactive. | Reactivate plan, then retry. |
| 404 | NOT_FOUND | Resource does not exist in your org scope. | Verify ID and org ownership. |
| 429 | RATE_LIMITED | Per-endpoint per-minute limit exceeded. | Use exponential backoff + jitter. |
| 429 | ORG_RATE_LIMITED | Organization minute rate limit exceeded. | Reduce parallel fan-out and retry with backoff. |
| 429 | API_QUOTA_EXCEEDED | Monthly total API quota reached for your org. | Wait until reset or increase monthly quota. |
| 429 | QUOTA_EXCEEDED | Monthly AI quota reached for your org. | Wait until reset or increase quota. |
| 500 | INTERNAL_ERROR | Unexpected server-side failure. | Retry idempotent requests with limits. |
429 Rate Limit Example
json
{
"error": "Rate limit exceeded",
"code": "RATE_LIMITED",
"retry_after_seconds": 60
}429 Total API Quota Example
json
{
"error": "Monthly API quota exceeded",
"code": "API_QUOTA_EXCEEDED",
"limit": 50000,
"used": 50000,
"remaining": 0,
"reset_at": "2026-04-01T00:00:00.000Z"
}429 AI Quota Example
json
{
"error": "Monthly AI API quota exceeded",
"code": "QUOTA_EXCEEDED",
"limit": 5000,
"used": 5000,
"remaining": 0,
"reset_at": "2026-04-01T00:00:00.000Z"
}Retry Strategy (JavaScript)
Retry only for 429 or 5xx. Do not retry 400/401/404 until request or credentials are corrected.
javascript
async function fetchWithRetry(url, options, maxRetries = 4) {
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
const res = await fetch(url, options);
if (res.status !== 429 && res.status < 500) return res;
if (attempt === maxRetries) return res;
const jitter = Math.floor(Math.random() * 250);
const delayMs = Math.min(1000 * 2 ** attempt + jitter, 15000);
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}