Skip to main content
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

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable summary"
  },
  "meta": {
    "requestId": "trace-abc or req_<uuid>",
    "timestamp": "2026-06-17T12:00:00.000Z"
  }
}
  • details is omitted when empty (not null, not {}).
  • requestId is in meta for Gather compatibility.

Authentication and authorization

CodeHTTPWhen
UNAUTHORIZED401Missing/invalid API key or organization context
FORBIDDEN403Valid key, wrong scope or access denied

Validation

CodeHTTPWhen
VALIDATION_ERROR400Invalid body, config, or unresolved teamId
details contains field-level keys (e.g. { "apiKey": "apiKey is required" }).

Integration lifecycle

CodeHTTPWhen
INTEGRATION_NOT_FOUND404No active integration for org + team + vendor
INTEGRATION_EXISTS409Duplicate on POST /connect/{vendor}/integrations
HEALTH_PROBE_FAILED502Unexpected probe error (not auth/timeout simulation)
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.

Vendor passthrough

Mapped from outbound vendor HTTP failures:
CodeHTTPVendor situation
VENDOR_AUTH_FAILED502Vendor 401/403 or stored credential rejected
VENDOR_RATE_LIMITED429Vendor 429
VENDOR_UNAVAILABLE502Vendor 5xx
VENDOR_TIMEOUT504Timeout / ECONNABORTED
VENDOR_BAD_REQUEST400Other vendor 4xx
details may include vendorStatus, vendorStatusLabel, or vendorMessage (never raw vendor secrets).

Internal and order errors

CodeHTTPWhen
INTERNAL_ERROR500Unhandled exception or internal-router 5xx
NOT_FOUND404Internal-router resource missing
CONFLICT409Account provisioning name conflict
ORDER_FAILED400Order 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.