Error Handling

Structured error responses with machine-readable codes for reliable integration.

Error envelope

All errors return a consistent JSON structure:

1{
2 "error": {
3 "code": "not_found",
4 "message": "Load not found",
5 "param": "id"
6 }
7}
FieldTypeDescription
codestringMachine-readable error code. Use this for programmatic handling.
messagestringHuman-readable description of the error.
paramstring or nullThe request parameter that caused the error, if applicable.

Error codes

Handle errors by switching on the error.code field, not the HTTP status code.

CodeHTTP StatusDescription
validation_error400, 422Invalid request parameters or body. Check param for the specific field.
not_authenticated401Missing or invalid credentials.
insufficient_permissions403Valid credentials but not authorized for this resource or action.
not_found404The requested resource does not exist.
already_exists409A resource with the same identifying fields already exists.
rate_limit_exceeded429Too many requests. See the Retry-After header.
internal_error500An unexpected server error. Contact support if it persists.

Example error responses

Validation error (422):

1{
2 "error": {
3 "code": "validation_error",
4 "message": "field required",
5 "param": "stops[0].address.city"
6 }
7}

Authentication error (401):

1{
2 "error": {
3 "code": "not_authenticated",
4 "message": "Missing or invalid authentication credentials.",
5 "param": null
6 }
7}

Rate limit error (429):

1{
2 "error": {
3 "code": "rate_limit_exceeded",
4 "message": "Rate limit exceeded. Retry after 30 seconds.",
5 "param": null
6 }
7}

Handling errors in code

Switch on error.code rather than HTTP status for precise handling.

Python

1import time
2import requests
3
4response = requests.post(
5 "https://tryenvoy.ai/api/v1/loads/load_.../offers",
6 headers={"X-API-Key": "<your-api-key>"},
7 json={"carrier_id": "car_...", "amount": 2500.00},
8)
9
10if response.status_code >= 400:
11 error = response.json()["error"]
12
13 match error["code"]:
14 case "not_found":
15 print(f"Resource not found: {error['message']}")
16 case "already_exists":
17 print("This resource already exists.")
18 case "validation_error":
19 print(f"Invalid field {error['param']}: {error['message']}")
20 case "not_authenticated":
21 print("Check your API key -authentication failed.")
22 case "rate_limit_exceeded":
23 retry_after = int(response.headers.get("Retry-After", 60))
24 time.sleep(retry_after)
25 case _:
26 print(f"Unexpected error: {error['code']} -{error['message']}")

TypeScript

1const response = await fetch("https://tryenvoy.ai/api/v1/loads/load_.../offers", {
2 method: "POST",
3 headers: {
4 "X-API-Key": "<your-api-key>",
5 "Content-Type": "application/json",
6 },
7 body: JSON.stringify({ carrier_id: "car_...", amount: 2500.0 }),
8});
9
10if (!response.ok) {
11 const { error } = await response.json();
12
13 switch (error.code) {
14 case "not_found":
15 console.error(`Resource not found: ${error.message}`);
16 break;
17 case "already_exists":
18 console.error("This resource already exists.");
19 break;
20 case "validation_error":
21 console.error(`Invalid field ${error.param}: ${error.message}`);
22 break;
23 case "not_authenticated":
24 console.error("Check your API key -authentication failed.");
25 break;
26 case "rate_limit_exceeded":
27 const retryAfter = parseInt(response.headers.get("Retry-After") ?? "60", 10);
28 await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
29 break;
30 default:
31 console.error(`Unexpected error: ${error.code} -${error.message}`);
32 }
33}

Validation errors

For 422 responses, the param field uses dot notation for nested fields (e.g., stops[0].address.city). Validate your payload structure against the API Reference before sending requests.