How to create and configure webhooks

Updated:


September 4, 2024

This guide goes over how to create and configure webhooks with Unified.to. Webhooks deliver events to your server when records change in your customers' accounts (see webhook vs API for the basics).

Looking for help with troubleshooting webhook issues? See: How to troubleshoot unhealthy webhooks.

Before you begin

This guide assumes you have a basic understanding of webhooks.

Create a webhook

Webhooks and connections are closely related; webhooks can only be created from existing connections and you can create multiple webhooks off a single connection. Webhook support is per integration and per object. If an object doesn't support webhooks on an integration, create returns an error saying so. Check the integration's Feature Support tab in the dashboard before building on a webhook. If you delete a connection, any webhooks that are associated with it will also be deleted.

There are two ways to create a webhook:

Method 1: Use the Unified API

Send a POST request to /unified/webhook(see below for configuration options). For example:

POST /unified/webhook?include_all=true

{
    "hook_url": "YOUR_WEBHOOK_URL",
    "connection_id": "YOUR_CONNECTION_ID",
    "object_type": "ats_candidate",
    "event": "updated"
}

API reference: Create a webhook

By including the optional parameter include_all in the query, the webhook will receive all historical data for the connection (see: Get all initial data for a connection).

This is the payload that your server receives when webhook data comes in:

NameTypeDesc
dataobject arrayAn array of objects specific to the webhook's connection. (eg. CRM contacts)
webhookWebhookThe webhook object. You can use the id to manage or delete your webhook.
noncestringRandom string
external_xrefstringThe external_xref you set on the connection, returned so you can identify the user or account.
sig256stringA security signature generated using HMAC-SHA256. It combines your workspace secret with the payload data and nonce i.e HMAC-SHA256(workspace.secret, data + nonce) . Use this to verify the authenticity of incoming webhooks.
typeenumINITIAL-PARTIAL, INITIAL-COMPLETE, VIRTUAL, NATIVE
The objects in data use the same format as the corresponding API endpoint. The fields option, including raw, raw.* and custom fields, works the same way on webhooks as on API calls, for native and virtual webhooks.

A note on the type enums:

  • INITIAL-PARTIAL: included with each page of results for the initial sync
  • INITIAL-COMPLETE: included with last page (e.g. last 5 elements for the limit 100) of initial sync or with an empty list (no more results)
  • VIRTUAL: included with every page when reading new data from a virtual webhook
  • NATIVE: included with every page when reading new data from a native webhook

Method 2: Use the Unified.to app

If you prefer to create webhooks through the UI, you can do so at app.unified.to.

  1. Navigate to Integrations > Webhooks.
  2. Click New Webhook.
  3. Click on the input and a list of your connections will appear. Select the connection from which you want to create a webhook.
  4. Choose how to configure your webhook (see below).
  5. Click Save.

Information about the other fields can be found under their respective tooltips in the UI.

Webhook configuration options

Whether you use the API or our web UI, these are the configuration options you can specify when creating a webhook:

  1. Object: The data you are interested in e.g. Deal, Company, Application, etc.
  2. Event: The events you want to subscribe to. Note: The updated event will also be sent when the data object is first created. Native webhooks forward deleted events where the vendor sends them. On virtual webhooks, deleted events are reliable only on BambooHR, Dropbox, Google Drive, Gmail, JobAdder, OneDrive, SharePoint, RingCentral, Egnyte and Box.
  3. Type: Virtual webhooks cover integrations whose APIs don't offer webhooks, or whose webhooks are limited. Where an integration supports both, choose native for immediate updates and virtual to set how often changes are checked and control cost. The type can't be changed after creation (including with PUT); delete and recreate the webhook to switch. For more details, see: Understanding virtual webhooks.
  4. Filter (optional): Specify any properties you want to filter incoming events by. See: Use filters to refine webhook events
  5. Fields (optional): Comma-separated list of fields to include in the webhook payload. Leave blank to include all fields. The 'raw' field is NOT included by default. If you want to include all fields as well raw, just enter 'raw'. To read more about raw fields, see: Raw and custom fields.
  6. Interval (virtual webhooks only): Specify how often Unified.to checks the integration for changes. The minimum is 1 minute on paid plans and 60 minutes on the trial. The interval is ignored on native webhooks and doesn't affect the initial sync.

List your webhooks

To view your webhooks, make a GET request to /unified/webhook or visit app.unified.to and navigate to Integrations > Webhooks.

API reference: Get all webhooks

Get all initial data for a connection

When you create a webhook, you can choose to fetch all existing data immediately.

  1. If you are using the API, add the include_all query parameter when creating the webhook.
  2. If you are using the UI, check off Initially sync all data in the configuration options.

Once the initial sync is complete, you will receive a final payload with type: INITIAL-COMPLETE and the requested webhook will continue to work as normal. Initial sync works the same way for native and virtual webhooks, wherever the integration supports it. Once it completes, a native webhook receives events as the integration sends them; a virtual webhook checks for changes on its interval.

API reference: Create a webhook subscription

A note on retrieving webhook data

Our system will POST initial data to your webhook in chunk sizes up to the limit supported by the integration. The limit is shown on the integration's Feature Support tab in the dashboard.

When performing the initial retrieval, depending on the amount of data being sent, the integration's API's rate-limiting rules, and your server's performance, it could take a very long time. If you do not want to get all of the existing data (for example, you already have it or don't need it), then do not include the include_all parameter in the request.

After the initial retrieval is completed, whenever updated data is available, your webhook will be called with a list of data objects, up to the max limit. If there are more entries than the limit, then your webhook URL will be POSTed to multiple times.

For details about the webhook payload that is sent to your server, click here.

Specify which fields to receive from a webhook

If you only want a subset of fields when receiving updated data, you can define them with the fields parameter in both the API and the UI. This is useful if you don't want the entire payload being sent to your servers. For more details, see: Fields.

API reference: Create a webhook subscription

Use filters to refine webhook events

Note: Filters are supported on virtual webhooks and on native webhooks for some integrations. Check the integration's Feature Support tab for which filters apply. For more information, see: Understanding virtual webhooks

Some webhooks support filters, allowing you to filter the events you receive. For instance, if you're subscribed to Deal events from a CRM, you could filter by company_id to only receive events from that specific company.

Filter availability varies by integration type and data model. To check which filters are supported for a particular webhook, open the integration's Feature Support tab in the dashboard and check the List Options and Virtual Webhook Options sections. Parameters that end in _id or type can be used as filter options when creating a webhook, helping you tailor your subscriptions to your specific needs. For worked examples in the dashboard and the API, see How to filter webhook events.

Trigger webhooks manually

If you don't want to wait for the next scheduled check while testing a virtual webhook, you can trigger it right away. Manual triggering applies to virtual webhooks only; the API returns 400 for native webhooks.

  1. In the web app, navigate to Webhooks.
  2. Click the Trigger icon next to your webhook:
    Untitled.png

This can also be accomplished with the API.

API reference: Trigger a webhook

Note: When you trigger a webhook, we will schedule the next dispatch event to go out right away. This is treated like a regular webhook event. Therefore, if your webhook is listening for update events and no new updates have occurred since the last run, then no new events will be sent to your server.

Frequently asked questions

Is there a page_max_limit for webhooks?

An integration's page_max_limit typically comes directly from the API provider. You can see that limit on the integration's Feature Support tab in the dashboard. You don't have to set limits for webhooks; they will use the integration's max limit.

Does changing the interval for virtual webhooks affect the initial retrieval?

Increasing frequency of virtual webhooks has no effect on the initial retrieval of historical data. Each page read is scheduled to be read one after another as soon as possible.

How do I distinguish between an updated event and a created event?

When a new data object is created, it triggers both created and updated events. If you want to track both of these events but also tell them apart, we recommend subscribing to the updated event and then compare created_at and updated_at for incoming data. If they are the same, that means the data object was newly created.

What happens if the webhook dispatch fails? Is there a retry mechanism in place?

If your endpoint doesn't respond, a native webhook is retried 3 times immediately, then marked unhealthy; the event isn't redelivered unless the integration sends it again. A virtual webhook makes up to 3 immediate attempts 1 second apart, then backs off progressively for up to about two weeks, re-reading the same page from the integration rather than resending a stored payload. Its cursor advances only after a successful delivery. When retries are exhausted, the webhook is marked unhealthy and scheduling stops. There's no way to re-enable an unhealthy webhook: fix your endpoint, then recreate the webhook. Failed delivery attempts aren't billed. Read more about it here.

Why do I receive duplicate webhook events and how should I handle them?

Duplicate webhook events can occur for several reasons:

  • Some integrations (like HubSpot) trigger separate events for each property change on an object
  • Rapid changes to objects can trigger multiple events that may arrive out of order due to network conditions

To handle duplicates effectively:

  1. Always use the object's latest state when updating your database
  2. Implement atomic writes to avoid race conditions. Only update records if the incoming data is newer:
-- Pseudo-code example
IF incoming_object.updated_at >= stored_object.updated_at THEN
    UPDATE record
ELSE
    -- Skip update as we already have newer data
END IF

Vendor-specific native webhook setup

Some integrations need native webhooks registered in the vendor's own app first. These guides cover the vendor-side steps:

See also

Share
All guidesWebhooksWebhook modelVirtual webhooksAdvertising Report Metrics by IntegrationATS to Vector DB: How to Power Talent Intelligence with Real-Time DataBuilding AI applications with Unified and LangbaseConcur & Concur (Company) — Connection GuideConfigure Greenhouse Native Candidate WebhooksConnect Amazon Seller Central to Unified.toConnecting BambooHR via OAuth 2Connecting Google Workspace Integrations with a Service AccountCorrect WelcomeKit Scopes for Jungle IntegrationCreating Ads using the Unified Ads APICreating Walmart Items via UnifiedEnd-Users, Integrations, and ConnectionsEnriching Unified Objects with Custom MetadataEnterprise-managed authorization (EMA) with a static keyEnterprise-managed authorization (EMA) with a workspace secretEnterprise-managed authorization (EMA) with Microsoft Entra IDExtended observability — pushing API logs to ClickHouseExtended observability — pushing API logs to Grafana / LokiExtended Observability - Pushing API Logs to your Datadog InstanceFacebook Messenger Webhook SetupFireflies Integration GuideGetting started with WorkableHandling Delegated vs. Application Scopes in Microsoft IntegrationsHiBob & Unified: connection and time off guideHow long are logs retainedHow to access employees and usersHow to add API support for the Create Activity in CrelateHow to Associate a Connection ID with Your End-UserHow to build a Candidate Assessment product with Unified.toHow to build a candidate sourcing or job board app with Unified.toHow to build a Discord support bot with Unified.to and LangbaseHow to Build a Fintech Application with Unified's Payments APIHow to Build an E-Commerce Product Integration with UnifiedHow to build an invoicing system with Unified.toHow to build Enterprise Search using RAGHow to configure Bullhorn Redirect URI for creating a connectionHow to configure webhooks in HubSpotHow to configure webhooks in Thrive LearningHow to configure webhooks in Toast for UnifiedHow to Connect Anthropic to Real-Time SaaS Data with Unified.to MCP ServerHow to Connect Cohere to Real-Time SaaS Data with Unified.to MCP ServerHow to Connect Google Gemini to Real-Time SaaS Data with Unified.to MCP ServerHow to Connect LLMs to Real-Time SaaS Data with Unified.to MCP ServerHow to Connect OpenAI to Real-Time SaaS Data with Unified.to MCP ServerHow to Connect Zoom and Zoom PhoneHow to create a Connection In Microsoft TeamsHow to create a token-based connection in HighlevelHow to Create a Unified.to Connection to HighLevelHow to Create a Xero Connection in Unified.toHow to create Connection with HubspotHow to customize portal URLs for Stripe and GoCardlessHow to filter webhook eventsHow-to Get a Private Support Channel for Your Unified IntegrationHow to get your 8x8 Connect API Key and Account ID: Step-by-step guideHow to get your ADP Workforce Now Oauth2 client ID, Oauth2 client secret, Oauth2 PEM certificate and Oauth2 private key: Step-by-step guideHow to get your Amazon S3 AWS Region, AWS S3 Key and AWS S3 Secret: Step-by-step guideHow to get your Ashby API Key: Step-by-step guideHow to get your Brex API token: Step-by-step guideHow to get your Bullhorn OAuth2 Client ID, OAuth2 Client Secret, API Username and API Password: Step-by-step guideHow to get your Ceridian Dayforce Username, Password and Client Namespace: Step-by-step guideHow to get your Crelate API key: Step-by-step guideHow to get your Dashlane API Key: Step-by-step guideHow to get your Deel Access Token: Step-by-step guideHow to get your Dialpad API Key: Step-by-step guideHow to get your Discord OAuth 2 credentials and bot tokenHow to get your ELMO client ID and client secret: Step-by-step guideHow to get your Gainsight Client ID, Client Secret and Gainsight API Domain: Step-by-step guideHow to get your Greenhouse API Key and Job board token: Step-by-step guideHow to get your Helpscout API Key: Step-by-step guideHow to get your HiBob Service User ID and Service User Token: Step-by-step guideHow to get your HighLevel API Key and Location ID: Step-by-step guideHow to get your HubSpot developer key and OAuth 2 credentials (Legacy Apps)How to get your Humaans API Key: Step-by-step guideHow to get your iCIMS API Username, API Password and Customer ID: Step-by-step guideHow to get your JobDiva Client ID, Username/email and Password: Step-by-step guideHow to get your Jobvite API Key, API Key Secret and Email: Step-by-step guideHow to get your Lever API Key: Step-by-step guideHow to get your Loxo Agency slug, API Key and Agency ID: Step-by-step guideHow to get your Microsoft Active Directory / Entra ID Client ID, Client Secret and Tenant ID: Step-by-step guideHow to get your Microsoft Azure AD OAuth 2 credentialsHow to get your OAuth 2 credentials for GmailHow to get your OAuth 2 credentials for Microsoft Dynamics 365How to get your OAuth 2 credentials in PipeDriveHow to get your OpenAI API Key: Step-by-step guideHow to get your Paycom SID/Username and Token/Password: Step-by-step guideHow to get your PCRecruiter Username, Password, Database ID, App Key and App ID: Step-by-step guideHow to get your SAP SuccessFactors (OpenID Connect) Username, Password, Client ID, Client Secret, Dependency Name, IAS Host and API URL: Step-by-step guideHow to get your SAP SuccessFactors Username, Company ID, Password and API URL: Step-by-step guideHow to get your Shopify Admin API access token and Store ID: Step-by-step guideHow to get your Wayfair Client ID, Client Secret and Vendor Encrypted Key: Step-by-step guideHow to get your Workable API Token and Subdomain: Step-by-step guideHow to get your yotpo APP Key / Store ID and Secret Key: Step-by-step guideHow to Handle Attachments in Invoice, Bill and Credit MemoHow to migrate or import your integrations into Unified.toHow to obtain your GitHub OAuth2 credentialsHow to Power Claude with Live Customer Data Using Unified MCPHow to register a Google developer app and get OAuth 2 credentialsHow to register a Salesforce developer app and get OAuth 2 credentialsHow to register a Slack developer account and get OAuth 2 credentialsHow to Register a Workday Developer App and Get OAUTH2 CredentialsHow to Register a Workday Developer App and Get OAUTH2/ SOAP CredentialsHow to Register a ZendeskSell Developer App and Get OAUTH2 CredentialsHow to Register a Zoho Developer App and Get OAUTH2 CredentialsHow to Register an ADP Developer App and Get OAUTH2 CredentialsHow to Register an Atlassian Developer App and Get OAUTH2 CredentialsHow to Register your Facebook OAuth2 ApplicationHow to Register your Google Ads OAuth2 ApplicationHow to Register your MetaAds OAuth2 applicationHow To Request & Write Raw Integration DataHow to Retrieve Microsoft Dynamics 365 Business Central CredentialsHow to set up a custom API URL with a CNAMEHow to set up a HiBob marketplace installHow to Set Up a Microsoft Teams Bot with UnifiedHow to set up and configure NotionHow to set up Google Business Profile API access and get OAuth 2 credentialsHow to Set Up LinkedIn Webhooks with UnifiedHow to set up native webhooks for QuickBooks Online with UnifiedHow to set up Slack webhooks using event subscriptionsHow to set up Telegram (bot) with Unified.toHow to set up your scopes in HubSpotHow to setup a Freshbooks developer appHow to setup a TikTok Shop applicationHow to Setup AWS Assume Role for AWS Secret ManagerHow to setup Oracle JD EdwardsHow to Setup Quickbooks DesktopHow to setup Sage 100 with Unified.toHow to troubleshoot unhealthy connectionsHow to troubleshoot unhealthy webhooksHow to use SCIM with the Unified APIHow to use the Passthrough APIHow to Use Unified.to's Generative AI API with OpenAI and ClaudeHow to use User Provisioning and Verification with UnifiedHow virtual webhook retry and recovery worksIntegration set-up guide for LeverManaging custom validation rules in SalesforceNetSuite Authentication Setup for UnifiedNotice of Deprecation of Fields and Objects (Nov 2025)Oracle HCM / Taleo OAuth Credentials GuideRetrieval-Augmented Generation (RAG)SalesForce (External Client Apps) on Multiple OrganizationsSAML Single-Sign-OnScaling MCP Tools with Anthropic's (& OpenAI's) Defer LoadingSet Environments for your Unified.to WorkspaceSetting up a Slack Bot Connection with Unified.toSetting up OAuth 2 Credentials for Greenhouse's APIsTrello Connection Guide in UnifiedUnderstanding OAuth2 Authorization flowsUnderstanding Response Time Headers in the Unified APIUnified Assessment API: Embed Assessments Inside ATS PlatformsUnified's MCP ServerUnified MCP Server with LangChain and LangGraphUnlock real-time data with virtual webhooksUse Unified to sign in your users into your applicationWorkable: Creating candidates and attaching them to jobsWorkday vs Workday Legacy — Why Unified.to Supports BothWorking with hierarchical tree data in Storage, Messaging, and KMS APIs
Are we missing anything? Let us know
Was this page helpful?