Skip to main content

Error Reference

The ECOSIRE API uses conventional HTTP status codes and returns a consistent JSON error body on every failure.


Error Response Format

{
"statusCode": 422,
"message": "email must be a valid email address",
"error": "Unprocessable Entity"
}
FieldTypeDescription
statusCodenumberHTTP status code
messagestring or string[]Human-readable description; may be an array for validation failures
errorstringHTTP status name

Validation errors return an array in message:

{
"statusCode": 422,
"message": [
"name should not be empty",
"email must be a valid email address"
],
"error": "Unprocessable Entity"
}

HTTP Status Codes

2xx — Success

CodeNameWhen
200OKGET, PUT, PATCH successful
201CreatedPOST created a resource
204No ContentDELETE successful (no body)

4xx — Client Errors

CodeNameCommon Causes
400Bad RequestMalformed JSON body; missing required field
401UnauthorizedMissing Authorization header; expired token
403ForbiddenValid token but insufficient role (e.g., non-admin accessing admin route)
404Not FoundResource ID does not exist; wrong URL path
409ConflictDuplicate unique value (e.g., email already registered)
422Unprocessable EntityBody parsed correctly but fails validation rules
429Too Many RequestsRate limit exceeded for this endpoint

5xx — Server Errors

CodeNameWhat to Do
500Internal Server ErrorRetry once; if persistent, contact support
502Bad GatewayUpstream service unavailable; retry with backoff
503Service UnavailableScheduled maintenance or overload; check status.ecosire.com

Common Error Scenarios

401 Unauthorized — Missing or invalid token

{
"statusCode": 401,
"message": "Unauthorized",
"error": "Unauthorized"
}

Solutions:

  • Confirm the Authorization: Bearer <token> header is present.
  • Check the token has not expired. Call POST /auth/refresh with your refresh token.
  • Regenerate your API key from the dashboard if it was rotated.

403 Forbidden — Insufficient permissions

{
"statusCode": 403,
"message": "Forbidden resource",
"error": "Forbidden"
}

Solutions:

  • Admin-only routes (e.g., GET /admin/licenses) require a user with role admin or support.
  • Portal routes (e.g., GET /portal/downloads) require an authenticated customer account.
  • Confirm you are using the correct API key for the environment (live vs. test).

404 Not Found

{
"statusCode": 404,
"message": "Contact not found",
"error": "Not Found"
}

Solutions:

  • Verify the resource ID (UUID) in the URL path.
  • Confirm the resource belongs to your organization (organizationId scoping).
  • IDs are case-sensitive UUIDs in the format 018e1234-abcd-7000-8000-000000000001.

409 Conflict — Duplicate resource

{
"statusCode": 409,
"message": "A contact with this email already exists",
"error": "Conflict"
}

Solutions:

  • Use PATCH /contacts/:id to update the existing resource instead of creating a new one.
  • Search first using GET /[email protected].

422 Unprocessable Entity — Validation failure

{
"statusCode": 422,
"message": [
"price must be a positive number",
"sku should not be empty"
],
"error": "Unprocessable Entity"
}

Solutions:

  • Review the field-level messages and correct each one.
  • Consult the module reference page for the required request body schema.

429 Too Many Requests — Rate limit exceeded

{
"statusCode": 429,
"message": "ThrottlerException: Too Many Requests",
"error": "Too Many Requests"
}

Check the response headers:

X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710000120

Solutions:

  • Wait until the Unix timestamp in X-RateLimit-Reset before retrying.
  • Implement exponential backoff: delay = Math.min(1000 * 2 ** attempt, 30000).
  • Cache responses where possible to reduce call frequency.
  • Contact support to discuss higher limits for high-volume integrations.

License-specific errors

MessageCauseSolution
License not foundKey does not existVerify the license key format: PREFIX-XXXX-XXXX-XXXX-XXXX
License expiredPast expiry dateRenew the license from the dashboard
Activation limit reachedAll slots usedDeactivate an unused domain first
License revokedManually revoked by adminContact ECOSIRE support
Invalid signatureHMAC mismatchRecompute the X-Ecosire-Signature header
License suspendedSubscription payment failedUpdate payment method in the dashboard

Error Handling Best Practices

async function apiCall<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`https://api.ecosire.com/api${path}`, {
...options,
headers: {
Authorization: `Bearer ${process.env.ECOSIRE_API_KEY}`,
'Content-Type': 'application/json',
...options?.headers,
},
});

if (!res.ok) {
const err = await res.json().catch(() => ({
statusCode: res.status,
message: res.statusText,
error: 'Unknown',
}));

// Retry on 429 after the reset window
if (res.status === 429) {
const reset = res.headers.get('X-RateLimit-Reset');
const waitMs = reset ? Number(reset) * 1000 - Date.now() : 60_000;
await new Promise((r) => setTimeout(r, Math.max(waitMs, 0)));
return apiCall(path, options); // single retry
}

throw Object.assign(new Error(Array.isArray(err.message) ? err.message.join('; ') : err.message), {
statusCode: err.statusCode,
});
}

// 204 No Content
if (res.status === 204) return undefined as T;

return res.json();
}