Contents
When a request fails, the API returns a consistent JSON error object regardless of the endpoint. The HTTP status code indicates the category of failure; the body provides specifics.
{
"statusCode": 400,
"error": "validation_error",
"message": "Model validation failed.",
"details": {
"itemID": ["The itemID field is required."],
"units": ["The field units must be greater than 0."]
}
}| Field | Type | Description |
|---|---|---|
statusCode | integer | HTTP status code (mirrors the response status) |
error | string | Machine-readable error code (see table below) |
message | string | Human-readable description of what went wrong |
details | object or null | Field-level validation errors (only present for validation failures) |
The details object maps field names to arrays of error messages. It is only present when the error code is validation_error.
| Code | HTTP Status | Meaning |
|---|---|---|
bad_request | 400 | Request is malformed or missing required data |
validation_error | 400 | One or more fields failed validation (see details) |
unauthorized | 401 | Authentication is missing or the token is expired |
forbidden | 403 | Authenticated but lacking permission for this action |
not_found | 404 | The requested resource does not exist |
conflict | 409 | Request conflicts with current state (e.g., duplicate ShortID) |
rate_limited | 429 | Too many requests — slow down and retry |
not_implemented | 501 | Endpoint exists but the operation is not available |
internal_error | 500 | Unexpected server error |
| Status | When You’ll See It |
|---|---|
| 200 OK | Successful read or update |
| 201 Created | Resource successfully created |
| 400 Bad Request | Invalid input, missing fields, malformed JSON |
| 401 Unauthorized | No token, expired token, or invalid token |
| 403 Forbidden | Token valid but action not allowed for this client |
| 404 Not Found | Resource ID doesn’t exist |
| 409 Conflict | Duplicate or state conflict |
| 429 Too Many Requests | Rate limit exceeded |
| 500 Internal Server Error | Server-side failure (report to your administrator) |
When you submit invalid data, the API returns a 400 with field-level detail:
curl -X POST https://your-host/api/v1/Item \
-H "Authorization: Bearer ..." \
-H "Content-Type: application/json" \
-d '{}'{
"statusCode": 400,
"error": "validation_error",
"message": "Model validation failed.",
"details": {
"itemID": ["The itemID field is required."]
}
}Fix the flagged fields and retry.
If your credentials don’t include the required permission:
{
"statusCode": 403,
"error": "forbidden",
"message": "Insufficient permissions."
}Other 403 variants:
| Message | Cause |
|---|---|
| ”Account is read-only.” | Integration user is marked read-only — no write operations allowed |
| ”Warehouse is outside the client’s authorized scope.” | The warehouse ID in your request isn’t assigned to your integration user |
| ”Insufficient permissions.” | Your group doesn’t grant the security permission for this endpoint |
| ”Report access denied.” | Your group doesn’t have access to the requested report |
{
"message": "Rate Limit Exceeded. 100 per Minute"
}Note: The rate limit response uses a simpler format than the standard error envelope. Back off and retry after a reasonable interval (30–60 seconds).
var response = await client.PostAsync(url, content);
if (!response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
var error = JsonConvert.DeserializeObject<ApiError>(body);
switch (error.Error)
{
case "validation_error":
// Fix the fields listed in error.Details
break;
case "rate_limited":
// Wait and retry
break;
case "unauthorized":
// Token expired — refresh and retry
break;
default:
// Log and alert
break;
}
}$response = Invoke-WebRequest -Uri $url -Method Post -Body $json `
-Headers @{ Authorization = "Bearer $token" } `
-ContentType "application/json" -ErrorAction SilentlyContinue
if ($response.StatusCode -ge 400) {
$error = $response.Content | ConvertFrom-Json
Write-Warning "$($error.error): $($error.message)"
}On this page