# Errors

All Platform API endpoints use a consistent error format. When a request fails, the response body contains an `error` object with a human-readable message and a machine-readable code.

## Error Format

```json
{
  "error": {
    "message": "No active outbound flow found for partner ACME. Ensure the flow exists and is set to 'Active'.",
    "code": "configuration_error",
    "reason": "flow_inactive"
  }
}
```

- `message` -- a description of what went wrong, intended for developers. May include specific identifiers to help with debugging.
- `code` -- a short, stable string naming the class of failure. Branch on this.
- `reason` -- a stable string naming the specific condition within that class, on the errors that have one. Branch on this when the class is not specific enough to act on. Omitted when there is nothing more to say than the code already says.

The split exists because the useful question is usually "what do I have to do about this", which the code answers, while "which check failed" is a separate question that would otherwise force the code list to grow a value per condition.

## Can I Just Retry?

The status tells you whether resending the identical request could ever succeed:

- **400** -- no. The request is malformed. Fix the payload.
- **404** -- no. An identifier does not resolve. Fix the partner key or transaction set code, or create the thing it names.
- **422 with `code: configuration_error`** -- yes, once someone finishes the setup in Tediware. The request was valid; configuration is incomplete. This is the only case where waiting and retrying is the right behavior.
- **422 with any other code** -- no. The resend codes and the format codes describe a state that resending cannot change.
- **429** -- yes, after the `Retry-After` interval.

Branch on `code`, not on the status alone: `422` covers both "finish the setup and this works" and "this can never work", and only the code separates them.

## HTTP Status Codes

```
| Status | Meaning                                                                 |
|--------|-------------------------------------------------------------------------|
| 200    | Success. The request was processed and the response contains the result. |
| 202    | Accepted. The work was started in the background and is not finished yet. |
| 400    | Bad request. A required parameter is missing or a value is invalid.      |
| 401    | Unauthorized. The API key is missing or invalid.                         |
| 403    | Forbidden. The key is valid but not permitted on this endpoint.          |
| 404    | Not found. The requested resource does not exist.                        |
| 422    | Unprocessable. The request is valid but cannot be completed due to a configuration issue. |
| 429    | Too many requests. You have exceeded the rate limit; retry after the delay in the Retry-After header. |
```

## Error Codes

```
| Code                | Status | Description                                                          |
|---------------------|--------|----------------------------------------------------------------------|
| unauthorized        | 401    | The API key is missing or does not match any key in the system.       |
| missing_parameter   | 400    | A required field (such as contents) was not provided.                 |
| invalid_filename    | 400    | The filename contains disallowed characters or exceeds 128 characters. |
| invalid_envelope    | 400    | The envelope configuration is incomplete or contains invalid values.   |
| forbidden           | 403    | The key is valid but not allowed here: a sandbox key on an endpoint that requires a standard key, or an account that has been disabled. |
| not_found           | 404    | An identifier does not resolve: a partner key, transaction set code, result, or artifact. |
| configuration_error | 422    | Setup in Tediware is incomplete or ambiguous. The request was valid.   |
| rate_limited        | 429    | Too many requests in the rate-limit window. Retry after the Retry-After interval. |
```

Resending an outbound transaction returns its own `422` codes (`not_outbound`, `content_unavailable`, `delivery_node_missing`, `not_flow_delivered`, `delivery_target_missing`), each naming why that transaction cannot be resent. They are described on the [EDI Transactions](/resources/api-docs/edi-transactions) page.

### Reason Codes

`configuration_error` and `not_found` carry a `reason` naming which check failed. These are the reasons the submission endpoints can return:

```
| Reason                    | Code                | What is missing                                          |
|---------------------------|---------------------|----------------------------------------------------------|
| partner                   | not_found           | No partner in your organization has this key.             |
| transaction_set           | not_found           | The partner has no transaction setting for this code and direction. |
| transaction_set_not_ready | configuration_error | The setting exists but has no implementation or mapping.  |
| flow_inactive             | configuration_error | The partner has no flow for this direction set to Active. |
| missing_endpoint_node     | configuration_error | The flow has no endpoint node to submit to.               |
| ambiguous_endpoint_node   | configuration_error | The flow has more than one matching node.                 |
| missing_external_envelope | configuration_error | The partner has no external envelope assigned.            |
| missing_internal_envelope | configuration_error | The partner has no internal envelope assigned.            |
```

## Rate Limits

Platform API requests are rate-limited per API key:

- **Read endpoints** (fetching results, artifacts, and the feed): 240 requests per minute.
- **Write endpoints** (submitting EDI or JSON): 240 requests per minute.
- **Resending an outbound transaction**: 10 requests per minute, on top of the broad write limit. It is lower because every resend puts another copy of a document on a partner's wire.

When you exceed a limit, the API responds with `429` and a `Retry-After` header giving the number of seconds to wait:

```json
{
  "error": {
    "message": "Rate limit exceeded. Please try again later.",
    "code": "rate_limited"
  }
}
```

Wait for the `Retry-After` interval before retrying, and use exponential backoff if you keep hitting the limit.

If your integration needs higher limits, [contact us](https://tediware.com/contact) and we'll be happy to help.

## Handling Errors

A general approach to error handling:

- **401** -- check that your API key is correct and has not been revoked
- **400** -- review the request body for missing or malformed fields. The `message` will indicate which field is problematic.
- **403** means the key is valid but cannot be used here. Confirm you are using a standard key rather than a sandbox key; retrying or reissuing the key will not help.
- **404** -- verify that the partner key or transaction set code is correct, or create the thing it names. Retrying the same request will not help.
- **422** -- setup in Tediware is incomplete. The `reason` names which check failed; fix it in the app and the identical request then succeeds. Check the flow builder for the affected partner. On a resend, the `code` names the specific reason the transaction cannot be resent, and retrying will not change that one.
- **429** -- you are exceeding the rate limit. Wait for the `Retry-After` interval and back off before retrying.
