Skip to main content

Error handling

The Flex Forward API uses standard HTTP status codes and structured error responses. This page covers the error formats, status code meanings, and guidance for handling failures.

Error response formats

The API returns four error response shapes depending on the type of failure. Understanding which shape to expect helps you write correct error-parsing logic.

Standard error

Returned for failures such as unsupported couriers/products, authentication failures, conflicts, not-found errors, and server errors. The shape is { "error": string, "code"?: string }:
The error text is informational and may change without notice. Branch on the HTTP status code and, where present, code — never on the message text. Some errors include a machine-readable code. The following codes distinguish label-creation conflicts from courier failures: The code field is optional and this list is not exhaustive. Handle errors without a code using their HTTP status, and tolerate unknown codes.

Validation error

Returned for request validation failures (HTTP 400). Includes a details array with field-level error information:
Each entry in details contains: Only the first validation error is returned. Fix it and resend to surface the next one. HTTP 400 can also use the standard error shape, for example when a courier or product is unsupported. Check whether details exists before reading it; do not assume every 400 contains field-level errors.

HTTP status codes

Label creation outcomes

POST /labels returns the same LabelResponse shape on 200, 201, and 502. The HTTP status code tells you whether this call created the label, replayed an earlier attempt, or was rejected by the courier. The status field tells you whether a label exists.
On POST /labels, branch on the status field, not on the HTTP status code. An idempotent replay returns HTTP 200 even when the first attempt failed at the courier, so a 200 response can carry status: failed.

Validation errors (400)

Schema validation errors indicate that the request body does not meet the API requirements and include a details array with specific field paths. Other HTTP 400 errors use the standard error shape without details. Common causes:
  • Missing required fields (shipment.shipTo, courier, idempotencyKey)
  • Wrong field types or lengths (for example countryCode must be exactly 2 characters)
  • Negative numeric values (weight and dimensions must not be negative)
  • An invalid order.customerOrderNumber (maximum 40 characters, using only ASCII letters, digits, -, and _)
  • An unsupported label.format (use PDF or PNG) or item unitPrice.currency (only USD is accepted)
Fix the reported error before retrying. The same idempotencyKey can be reused after a 400 response because no label was created.

Authentication errors (401 / 403)

401 Unauthorized

The x-rr-apikey or x-rr-apitoken header is missing or invalid:
Verify that both headers are present:

403 Forbidden

The credentials are valid but the account is not permitted to call the API (for example, a blocked account):
A label or tracking record that belongs to a different account returns 404, not 403.

Downstream courier errors (502 and 422)

When the courier service returns an error during POST /labels, the API responds with HTTP 502. The label is persisted in the database with status: failed and includes the courier error details:
The error object contains:
A 502 response means the label request reached the courier and was rejected. Before retrying, review the error message — some courier errors (e.g., address validation) are not transient and require request changes.
Later calls to GET /labels/{id} or GET /tracking/{id} for a failed label return HTTP 422 with a LabelFailedResponse body — no document or tracking is available for that label:

Retryable vs non-retryable errors

See Idempotency and Retries for the recommended retry strategy.

Troubleshooting

All POST requests must include Content-Type: application/json. Without it, the request body will not be parsed and the API returns a 400 error.
All requests must use HTTPS. Verify you are using the correct environment URL: https://api.flexforwardship.com (production) or https://sandbox.flexforwardship.com (development).
The id parameter in GET /labels/{id} and GET /tracking/{id} accepts a label UUID or your customerOrderNumber. Any other value, or an identifier from another account, returns a 404 error.
A status: failed response is returned with HTTP 502 from POST /labels (or with HTTP 200 when you replay the same idempotencyKey), and later reads of that label return HTTP 422. Check the error object (or the LabelFailedResponse body on reads) for the courier’s error message. Common causes: invalid address, unsupported destination, or courier account configuration issues.