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

# Error envelope

> Standard error response format and codes for Humanly Connect

Every **`/connect/*`** route returns errors in a consistent JSON envelope. Gather (`/qsi/gather/*`) and legacy vendor routes (`/qsi/{vendor}/*`) keep their existing shapes.

## Envelope shape

<CodeGroup>
  ```json Error response theme={null}
  {
    "error": {
      "code": "ERROR_CODE",
      "message": "Human-readable summary"
    },
    "meta": {
      "requestId": "trace-abc or req_<uuid>",
      "timestamp": "2026-06-17T12:00:00.000Z"
    }
  }
  ```
</CodeGroup>

* `details` is **omitted** when empty (not `null`, not `{}`).
* `requestId` is in `meta` for Gather compatibility.

## Authentication and authorization

| Code           | HTTP | When                                            |
| -------------- | ---- | ----------------------------------------------- |
| `UNAUTHORIZED` | 401  | Missing/invalid API key or organization context |
| `FORBIDDEN`    | 403  | Valid key, wrong scope or access denied         |

## Validation

| Code               | HTTP | When                                         |
| ------------------ | ---- | -------------------------------------------- |
| `VALIDATION_ERROR` | 400  | Invalid body, config, or unresolved `teamId` |

`details` contains field-level keys (e.g. `{ "apiKey": "apiKey is required" }`).

## Integration lifecycle

| Code                    | HTTP | When                                                 |
| ----------------------- | ---- | ---------------------------------------------------- |
| `INTEGRATION_NOT_FOUND` | 404  | No active integration for org + team + vendor        |
| `INTEGRATION_EXISTS`    | 409  | Duplicate on POST `/connect/{vendor}/integrations`   |
| `HEALTH_PROBE_FAILED`   | 502  | Unexpected probe error (not auth/timeout simulation) |

<Note>
  **Health checks:** General unhealthy vendor state may return **502/504** with `data.healthy: false` in a **success** envelope. **Credential rejection** (MS6+) returns **502** with error code **`VENDOR_AUTH_FAILED`** instead.
</Note>

## Vendor passthrough

Mapped from outbound vendor HTTP failures:

| Code                  | HTTP | Vendor situation                             |
| --------------------- | ---- | -------------------------------------------- |
| `VENDOR_AUTH_FAILED`  | 502  | Vendor 401/403 or stored credential rejected |
| `VENDOR_RATE_LIMITED` | 429  | Vendor 429                                   |
| `VENDOR_UNAVAILABLE`  | 502  | Vendor 5xx                                   |
| `VENDOR_TIMEOUT`      | 504  | Timeout / `ECONNABORTED`                     |
| `VENDOR_BAD_REQUEST`  | 400  | Other vendor 4xx                             |

`details` may include `vendorStatus`, `vendorStatusLabel`, or `vendorMessage` (never raw vendor secrets).

## Internal and order errors

| Code             | HTTP | When                                       |
| ---------------- | ---- | ------------------------------------------ |
| `INTERNAL_ERROR` | 500  | Unhandled exception or internal-router 5xx |
| `NOT_FOUND`      | 404  | Internal-router resource missing           |
| `CONFLICT`       | 409  | Account provisioning name conflict         |
| `ORDER_FAILED`   | 400  | Order path: no invite token generated      |

## Gather errors

Gather uses the same `error` + `meta` shape on `/qsi/gather/*` but with Gather-specific codes. See [Gather error handling](/guides/error-handling).

## Related

* [Request tracing](/platform/request-tracing) — include `x-request-id` when reporting errors to support
* [Standardized vendor endpoints](/connect/standardized-vendor-endpoints)
