Skip to main content

Documentation Index

Fetch the complete documentation index at: https://nango.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

Nango POSTs webhooks to your app to notify it of important events: a new connection was created, a sync run finished, an async action completed, or an external webhook was forwarded. This page covers how to receive and verify webhooks from Nango, plus the payloads for auth, sync, and async action webhooks.
To process webhooks coming from external APIs (not from Nango), see Process external webhooks. To forward external API webhooks through Nango to your app, see Webhook forwarding.

Set up webhooks from Nango

Webhook settings in Nango are specific to each environment.
To subscribe to Nango webhooks:
  1. Set up a POST endpoint in your app to receive the Nango webhooks
  2. Input the endpoint’s URL in your Environment Settings, under Webhook URLs (direct link for your dev environment)
  3. Implement verify incoming webhooks to ensure sure only authentic Nango webhooks are processed
  4. Implement processing logic for each webhook type from Nango you want to handle
    • Make sure your processing logic handles the webhooks you have enabled in the environment settings
You can configure up to two webhook URLs per environment. Nango webhooks will be sent to both. To test webhooks locally, use a webhook forwarding service like ngrok, or webhook.site.

Verifying webhooks from Nango

Validate webhooks from Nango by looking at the X-Nango-Hmac-Sha256 header. It’s an HMAC-SHA256 hash of the webhook payload, using the webhook signing key found in Environment Settings > Webhooks > Signing key in the Nango UI.
Nango webhook requests include an X-Nango-Hmac-Sha256 header for secure verification. A legacy X-Nango-Signature header (using plain SHA-256) is also sent for backwards compatibility but should not be used. If you’re currently using X-Nango-Signature, migrate to X-Nango-Hmac-Sha256 for improved security.
The webhook signature can be generated with the following code:
async (req, res) => {
    const isValid = nango.verifyIncomingWebhookRequest(req.body, req.headers);
}
Only accept a webhook if the X-Nango-Hmac-Sha256 header value matches the webhook signature.

Types of Nango webhooks

New Nango webhook types are added regularly, without considering this a breaking change. Your webhook handling logic should gracefully support receiving new types of webhooks by simply ignoring them.
All webhooks from Nango are POST requests. The exact webhook type definitions can be found here.

Auth webhooks

New connection webhooks have "type": "auth" and "operation": "creation". They are sent after a connection has been successfully created. Payload received following a connection creation:
{
    "type": "auth",
    "operation": "creation",
    "connectionId": "<your-connection-id>",
    "authMode": "OAUTH2 | BASIC | API_KEY | ...",
    "providerConfigKey": "<your-integration-id>",
    "provider": "<your-provider-key>",
    "environment": "DEV | PROD | ...",
    "success": true,
    "tags": {
        "end_user_id": "<your-end-user-id>",
        "end_user_email": "<your-end-user-email>",
        "organization_id": "<your-organization-id>"
    }
}
Processing webhooks with "type": "auth" and "operation": "creation" is necessary. After a connection is created, these webhooks give you the generated connection ID which lets you access the connection later on.Use tags to reconcile and save the connection ID with the user/org/workspace that initiated the connection.
All authMode values can be found here. The authMode value depends on the provider value. All operation values are:
  • creation: a new connection has been created
  • override: a connection has been re-authorized
  • refresh: an OAuth connection’s access token has failed to refresh
Payload received following a refresh token error:
{
    "type": "auth",
    "operation": "refresh",
    "connectionId": "<your-connection-id>",
    "authMode": "OAUTH2 | BASIC | API_KEY | ...",
    "providerConfigKey": "<your-integration-id>",
    "provider": "<your-provider-key>",
    "environment": "DEV | PROD | ...",
    "success": false,
    "tags": {
        "end_user_id": "<your-end-user-id>",
        "end_user_email": "<your-end-user-email>",
        "organization_id": "<your-organization-id>"
    },
    "error": {
        "type": "<string>",
        "description": "<string>"
    }
}
Webhooks are only sent for certain connection creation errors. For example, during the OAuth flow, some errors are reported locally in the OAuth modal by the external API. Since Nango does not receive these errors, it cannot trigger a webhook for them.

Sync webhooks

Sync webhooks are sent when a sync function execution finishes, whether successful or not. Payload received following a successful sync execution:
{
    "type": "sync",
    "connectionId": "<your-connection-id>",
    "providerConfigKey": "<your-integration-id>",
    "syncName": "<your-sync-script-name>",
    "model": "<your-model-name>",
    "syncType": "INCREMENTAL | INITIAL | WEBHOOK", // DEPRECATED
    "success": true,
    "modifiedAfter": "<timestamp>",
    "responseResults": {
        "added": number,
        "updated": number,
        "deleted": number
    }
}
modifiedAfter is an ISO-8601 timestamp marking the start of the last run. To read the changed records, use cursor-based fetching as described in Records cache → Cursors and sync progress.
Fetch records promptly: Due to Nango’s data retention policies, you should fetch and store synced records in your own system promptly after receiving webhook notifications. Records not updated for 30 days will have their payload pruned, and sync functions not executed for 60 days will have all records deleted.
By default, Nango sends a webhook even if no modified data was detected in the last sync execution (referred as an “empty” sync), but this is configurable in your Environment Settings. In case of an empty sync, the responseResults would be:
{
    "added": 0,
    "updated": 0,
    "deleted": 0
}
Payload received following a failed sync execution:
{
    "type": "sync",
    "connectionId": "<your-connection-id>",
    "providerConfigKey": "<your-integration-id>",
    "syncName": "<your-sync-script-name>",
    "model": "<your-model-name>",
    "syncType": "INCREMENTAL | INITIAL | WEBHOOK", // DEPRECATED
    "success": true,
    "error": {
        "type": "<string>",
        "description": "<string>"
    },
    "startedAt": "<timestamp>",
    "failedAt": "<timestamp>"
}

External webhook forwarding

Forwarded external webhooks use the same webhook URLs, signing, retries, and logs as other Nango webhooks. See Webhook forwarding for setup, routing behavior, and payload shapes.

Webhook retries & debugging

Nango retries each webhook with non-2xx responses 2 times with exponential backoff (starting delay: 100ms, time multiple: 2, view details in the code). Webhooks time out after 20 seconds. Each webhook attempt is logged in Nango’s logs. You can also use the OpenTelemetry exporter to monitor Nango webhooks in your own observability stack.
Questions, problems, feedback? Please reach out in the Slack community.