Skip to main content

Errors

The Navigo API uses standard HTTP status codes. The table below is derived from the real behavior of the frontend interceptor.

HTTP status codes

StatusMeaningReason / note
400Bad RequestValidation error; the body has the shape { field: ["message"] }
401UnauthorizedKey/token is invalid or expired ("Session expired")
403ForbiddenInsufficient permission (not an admin / a resource you don't own)
404Not FoundResource not found
429Too Many RequestsRate limit exceeded (60/min, 2000/day)
5xxServer ErrorAn error on Navigo's side — retry with backoff

Error body format (validation, 400)

For validation errors, messages are returned per field as an array:

{
"external_id": ["lead with this external_id already exists."],
"email": ["Enter a valid email address."]
}

The frontend typically shows the first message of the first field to the user.

Handling errors correctly

const res = await fetch(url, options);

if (!res.ok) {
if (res.status === 429) {
// Rate limit — respect Retry-After, retry with backoff
const retryAfter = Number(res.headers.get("Retry-After") ?? 1);
await new Promise((r) => setTimeout(r, retryAfter * 1000));
// ... retry
} else if (res.status >= 500) {
// Server error — retry with exponential backoff
} else {
const errors = await res.json(); // { field: ["message"] }
throw new Error(Object.values(errors)[0]?.[0] ?? `HTTP ${res.status}`);
}
}

:::tip Retry policy For 429 and 5xx errors, retry with exponential backoff (1s, 2s, 4s, 8s…). For 4xx errors (other than 429), do not retry — fix the request instead. :::