> ## Documentation Index
> Fetch the complete documentation index at: https://openapidocs.flexforwardship.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> HTTP status codes, error response formats, and troubleshooting guidance

# 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 three error response shapes depending on the type of failure. Understanding which shape to expect helps you write correct error-parsing logic.

| Shape            | When                                     | Status Codes                             |
| ---------------- | ---------------------------------------- | ---------------------------------------- |
| Standard error   | Authentication, not-found, server errors | 401, 403, 404, 405, 500                  |
| Validation error | Request body failed schema validation    | 400                                      |
| Label failure    | Courier rejected the label request       | 502 (also 201/200 with `status: failed`) |

### Standard error

Returned for authentication failures, not-found errors, and server errors:

```json theme={null}
{
  "error": "Unauthorized"
}
```

### Validation error

Returned for request validation failures (HTTP 400). Includes a `details` array with field-level error information:

```json theme={null}
{
  "error": "Validation failed",
  "details": [
    {
      "field": "shipment.shipTo.address.countryCode",
      "message": "must be a valid ISO 3166-1 alpha-2 country code"
    },
    {
      "field": "shipment.parcels[0].weight",
      "message": "must be greater than 0"
    }
  ]
}
```

Each entry in `details` contains:

| Field     | Description                                                                  |
| --------- | ---------------------------------------------------------------------------- |
| `field`   | Dot-delimited path to the invalid field (array indices use bracket notation) |
| `message` | Human-readable description of the validation failure                         |

## HTTP status codes

| Status | Meaning                | When                                                                    | Retryable                                      |
| ------ | ---------------------- | ----------------------------------------------------------------------- | ---------------------------------------------- |
| 200    | OK / Idempotent replay | Successful GET request, or POST with a previously used `idempotencyKey` | N/A                                            |
| 201    | Created                | Label created successfully                                              | N/A                                            |
| 400    | Bad Request            | Request body failed validation                                          | No — fix the request                           |
| 401    | Unauthorized           | Missing or invalid Bearer token                                         | No — obtain valid token from Flex Forward team |
| 403    | Forbidden              | Valid token but no access to the requested resource                     | No — verify account permissions                |
| 404    | Not Found              | Label ID or shipping account does not exist                             | No — verify the ID                             |
| 405    | Method Not Allowed     | HTTP method is not supported for this endpoint                          | No — check the method                          |
| 500    | Internal Server Error  | Unexpected server failure                                               | Yes — retry with backoff                       |
| 502    | Bad Gateway            | Courier service returned an error                                       | Yes — retry with backoff                       |

## Validation errors (400)

Validation errors indicate that the request body does not meet the API schema requirements. The response always includes a `details` array with specific field paths.

Common causes:

* Missing required fields (`shipment.shipTo`, `courier`, `idempotencyKey`)
* Invalid field formats (country code, email, phone number)
* Invalid numeric values (weight must be greater than 0)

<Note>
  Fix all validation errors listed in the `details` array before retrying. The same `idempotencyKey` can be reused after a 400 response because no label was created.
</Note>

## Authentication errors (401 / 403)

### 401 Unauthorized

The Bearer token is missing, malformed, or expired:

```json theme={null}
{
  "error": "Unauthorized"
}
```

Verify that the `Authorization` header is present and correctly formatted: `Bearer YOUR_API_TOKEN`.

### 403 Forbidden

The token is valid but the caller does not have access to the requested resource. This occurs when attempting to retrieve a label or tracking information that belongs to a different account:

```json theme={null}
{
  "error": "Forbidden"
}
```

## Downstream courier errors (502)

When the courier service returns an error, the API responds with HTTP 502. The label is persisted in the database with `status: failed` and includes the courier error details:

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "failed",
  "courier": "yunexpress",
  "courierOrderNumber": null,
  "courierTrackingNumber": null,
  "error": {
    "code": "COURIER_ERROR",
    "message": "Address validation failed at courier"
  }
}
```

The `error` object contains:

| Field     | Description                                       |
| --------- | ------------------------------------------------- |
| `code`    | Machine-readable error code                       |
| `message` | Human-readable error description from the courier |

<Warning>
  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.
</Warning>

## Retryable vs non-retryable errors

| Error Type        | Retryable | Action                                                                          |
| ----------------- | --------- | ------------------------------------------------------------------------------- |
| 400 Validation    | No        | Fix the request body based on `details`                                         |
| 401 Unauthorized  | No        | Obtain valid token from the Flex Forward team                                   |
| 403 Forbidden     | No        | Verify account access to the resource                                           |
| 404 Not Found     | No        | Verify the label ID or shipping account                                         |
| 500 Server Error  | Yes       | Retry with the same `idempotencyKey` and exponential backoff                    |
| 502 Courier Error | Depends   | Check error message — transient issues are retryable, validation issues are not |

See [Idempotency and Retries](/idempotency-and-retries) for the recommended retry strategy.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Missing Content-Type header">
    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.
  </Accordion>

  <Accordion title="Wrong base URL or HTTP instead of HTTPS">
    All requests must use HTTPS. Verify you are using the correct environment URL: `https://api.flexforward.com` (production) or `https://sandbox.flexforward.com` (development).
  </Accordion>

  <Accordion title="Invalid UUID format for label ID">
    The `id` parameter in `GET /labels/{id}` and `GET /tracking/{id}` must be a valid UUID. Passing a tracking number or other identifier format will return a 404 error.
  </Accordion>

  <Accordion title="Label created but status is failed">
    A `status: failed` response with HTTP 201 or 200 means the label was persisted but the courier rejected the request. Check the `error` object for the courier's error message. Common causes: invalid address, unsupported destination, or courier account configuration issues.
  </Accordion>
</AccordionGroup>
