Overview

Nango sends webhook notifications to your backend in different cases:

  • Sync webhook: new data from syncs is available (guide)
  • Authorization webhook: an authorization flow completes (guide)
  • External API webhook forwarding: an external API webhook is forwarded to your app (guide)

Configuring Nango webhooks

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

You can configure up to two webhook URLs per environment. Nango webhooks will be sent to both.

The webhook settings also let you enable or disable the various types of webhooks Nango provides.

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.

Webhooks from Nango are POST requests. Nango sends multiple types of webhooks to your backend. All webhook types are sent to the same URL(s) configured in your Environment Settings.

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,
    "endUser": { 
        "endUserId": "<your-end-user-id>", 
        "organizationId": "<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 the values of endUser.endUserId (and optionally endUser.organizationId) to reconcile and save the connection ID with the user/org who 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 been refreshed

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,
    "endUser": { 
        "endUserId": "<your-end-user-id>", 
        "organizationId": "<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 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",
    "success": true,
    "modifiedAfter": "<timestamp>",
    "responseResults": {
        "added": number,
        "updated": number,
        "deleted": number
    }
}

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
  ]

The syncType possible values are:

  • INITIAL: for the very first execution of a sync.
  • INCREMENTAL: for subsequent executions of a sync.
  • WEBHOOK: when an external API webhooks triggers the execution of the sync’s onWebhookPayloadReceived function.

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",
    "success": true,
    "error": {
        "type": "<string>",
        "description": "<string>"
    },
    "startedAt": "<timestamp>",
    "failedAt": "<timestamp>"
}

External webhook forwarding

Nango can forward webhooks received from 3rd-party APIs. See details in this guide.

Webhook retries

Nango retries each webhook with non-2xx responses 7 times with exponential backoff (starting delay: 100ms, time multiple: 2, view details in the code).

Each webhook attempt is logged in the Logs tab. You can also use the OpenTelemetry exporter to monitor Nango webhooks in your own observability stack.

Webhook verification

Validate webhook provenance by looking at the X-Nango-Signature header.

It’s a SHA-256 hash generated using the secret key found in the Environment Settings in the Nango UI.

The webhook signature can be generated with the following code:

async (req, res) => {
    const signature = req.headers['x-nango-signature'];
    const isValid = nango.verifyWebhookSignature(signature, req.body);
}

Only accept a webhook if the X-Nango-Signature header value matches the webhook signature.

Questions, problems, feedback? Please reach out in the Slack community.