Troubleshooting: Integration action and sync error codes
An API-key integration on your dashboard — PostHog, Mixpanel, Freshdesk, Resend, ElevenLabs, Google Gemini, or People Data Labs — flips its card to errored, paused, or stopped, or an action or sync call against it returns a 4xx/5xx. This lane (the credential lane, connected by pasting a provider-issued key into the hosted form) speaks a distinct code family from the Salesforce / HubSpot OAuth lane, which its sibling page CRM integration sync error codes decodes. Readerror.code on the failed response first; the code tells you which leg failed and who owns the fix.
Symptom
On Settings → Integrations the provider card reads errored, or one of its sync rows reads paused or stopped; an action call (POST /api/v1/integrations/{id}/actions/{name}) returns a 404, 401, 400, or 502 carrying one of the codes above; or a sync trigger (POST /api/v1/integrations/{id}/sync) or synced-records read (GET /api/v1/integrations/{id}/data?model=...) returns a 502 or 503. The flipped card and the failed call are two surfaces of the same failure: the card reflects the latest sync state, the call reports the leg that failed on this attempt.
An empty sync list on a connected card is not a failure. Resend, People Data Labs, and WorkOS act on demand or send only, so their drawers can legitimately show zero scheduled sync rows — see Settings → Integrations console.
Connection and action codes: the three-way split
INTEGRATION_CONNECTION_MISSING (404)
There is no stored connection for this provider key in your organization, so the action has nothing to run against. The fix is to connect, not to retry:
- Open Settings → Integrations and find the provider card. The connectable credential-lane keys are
posthog,mixpanel,freshdesk,resend,elevenlabs,google-gemini, andpeopledatalabs; the per-provider prerequisites live in Connect API-key providers. - Click Connect, create the prerequisite at the provider if you have not (a personal API key, a service account, a verified domain), and submit it through the hosted form. The form validates the value before anything is stored.
- Re-run the action once the card reads Connected.
INTEGRATION_AUTH_EXPIRED (401)
A connection exists but the credential it holds was revoked, rotated, or expired at the provider. API keys die quietly — someone rotated the key, the project it scoped moved, or its permissions were narrowed.
- At the provider, confirm the key still exists and still carries the scopes the integration needs (project read access for PostHog, sending access plus a verified domain for Resend).
- Rotate or re-create the key at the provider, then reconnect the card from Settings → Integrations with the fresh value. One reconnect replaces the stored credential.
- Confirm
connected: trueonGET /api/v1/integrations/{id}/status, then re-run the failed action.
INTEGRATION_ACTION_FAILED (502)
The connection is healthy and the action reached the provider, but the provider rejected it: a 4xx validation refusal, a rate limit, or a provider 5xx. Read the raw transport line for the failed call before re-invoking — it carries the provider’s own status and body. Fix the payload, the rate budget, or the provider-side object, then retry; a blind retry resends the same rejected payload and burns provider rate limit for nothing.
UNKNOWN_INTEGRATION_ACTION (400)
The action slug in the URL is not in the catalog the provider advertises. The response message lists the actions that are valid for the provider (Available: ...) — pick one of them. The same catalog is visible in the card drawer’s Actions tab on Settings → Integrations. A 400 here is raised before any provider call is made, so correcting the slug and retrying costs nothing.
The sync ladder
When a sync call fails, the code tells you which leg failed and which side owns it.SYNC_TRIGGER_FAILED (502)
POST /api/v1/integrations/{id}/sync could not start the named sync against the integration server. Retry once after a minute. If the same sync keeps failing while the card reads connected, the usual cause is the sync’s provider-side configuration — escalate with the request id.
SYNC_RECORDS_FAILED (502)
GET /api/v1/integrations/{id}/data?model=... could not page through the model’s synced records. Retry once; a persistent failure with a healthy card is an upstream read fault, not a tenant misconfiguration — escalate with the request id and the model you queried.
NANGO_NOT_CONFIGURED (503) and NANGO_UNAVAILABLE (502)
Both codes are platform-side: the integration server is not configured, or is briefly unreachable, and nothing on your side changes either code. Wait a minute and retry once; if NANGO_NOT_CONFIGURED persists, or NANGO_UNAVAILABLE outlives the window the status page shows, escalate — there is nothing to fix from your tenant.
Provider-side versus platform-side
INTEGRATION_*, UNKNOWN_INTEGRATION_ACTION, and WOO_* codes are provider- or tenant-side: the fix lives in your connection, your key, or your payload. NANGO_* codes are platform-side. SYNC_TRIGGER_FAILED and SYNC_RECORDS_FAILED sit between: one retry is yours, persistence is an escalation. The split decides whether you reconnect or simply wait.
DISCONNECT_FAILED (502) recovery
A disconnect that ends in DISCONNECT_FAILED has torn down part of the connection and may leave the rest live — the card can keep reading connected and scheduled work can continue. Retry the disconnect once. If it fails again, do not hammer it: check Settings → Audit Log for the disconnect entries, and escalate with the request id so the leftover connection is reconciled on the platform side. Already-synced records remain available after a successful disconnect; on-demand providers simply stop serving new lookups.
Appendix: WooCommerce store-URL family
Connecting a WooCommerce store validates the store URL end to end, and each rejection is its own code:
The ladder runs URL shape, reachability, auth, then REST presence — fix the first failing rung; later rungs only run once earlier ones pass.
What NOT to do
- Do not blind-retry
INTEGRATION_ACTION_FAILED. The provider rejected the payload; re-sending it without reading the raw response resends the same rejection and burns rate limit. - Do not loop reconnects on
INTEGRATION_AUTH_EXPIRED. One reconnect with a freshly rotated key clears it; repeated reconnects with the same dead key change nothing. - Do not treat
INTEGRATION_CONNECTION_MISSINGas an action bug. No retry creates the missing connection; connect first. - Do not chase
NANGO_NOT_CONFIGUREDfrom your side. It is a platform configuration state; no tenant setting changes it. - Do not read an empty sync list as a broken connection on on-demand providers (Resend, People Data Labs, WorkOS).
Escalation
Bring the provider key (e.g.posthog), the integration id from the card, the failing action slug or sync name, and the request_id from meta.request_id on the failed response to support@devotel.io. The raw transport line that decodes a provider rejection is located by that request id.
Related reading
- CRM integration sync error codes — the sibling runbook for the Salesforce / HubSpot OAuth lane.
- Connect API-key providers — per-provider prerequisites for the credential form.
- Settings → Integrations console — card drawers, statuses, and the empty-sync-list rule.
- Error codes reference — retry classes for every code.
- Troubleshooting hub — runbooks by surface.