Skip to content
ConsultEvo

Webhooks: A Practical Guide to Reliable Integrations

A webhook is an HTTP request that a provider sends to your registered endpoint when a subscribed event occurs. A reliable implementation authenticates the request, validates its contents, preserves it durably, acknowledges it promptly, processes the work asynchronously, and defines how duplicates and missed events will be handled.

That design is different from simply exposing a URL. The receiver needs an event contract, an operational owner, a deduplication rule, and a provider-specific recovery path. A payment notification, for example, can be accepted by a small endpoint and sent to a background worker for fulfillment instead of making the payment provider wait for fulfillment to finish.

Webhooks report that something happened. An API can retrieve or change the current state of an object. Most dependable integrations use both: receive the notification, then fetch authoritative state when the event is incomplete, thin, stale, or needed for reconciliation.

What a webhook does, and what it does not guarantee

Use a webhook when your system should react to subscribed events without repeatedly checking for changes. Use an API for user-initiated reads, historical queries, reconciliation, and actions that need an immediate request and response. Pair them when you need timely notification and complete or authoritative data.

Polling illustrates the trade-off, but it is not a performance benchmark. Checking one resource every five seconds for 24 hours makes 17,280 requests per day, calculated as 86,400 seconds divided by five. That assumes one request per check, no batching or caching, and no failed requests. A webhook may avoid those repeated checks, but it does not guarantee a particular delivery time, ordering, or recovery policy.

Decision point

A webhook tells you that something happened; an API can help establish what is true now. Fetch current state when a decision depends on omitted fields, a thin event, possible staleness, or a backfill.

Choose the delivery model before designing the handler

Start by identifying the system of record for every important field. The provider may be authoritative for payment status, while your CRM is authoritative for an internal assignment. A webhook can trigger a synchronization without becoming the source of truth for every value.

  • Prefer a webhook for event-triggered reactions such as queueing a build, starting fulfillment, or notifying an operations team.
  • Prefer an API for a user-initiated read, a filtered historical query, an action that needs an immediate response, or reconciliation after downtime.
  • Use both when the webhook signals a change and the API supplies the current object, omitted fields, or a recovery path.

Stripe documents both snapshot and thin event payloads. A thin event may require an API request before the receiver can make a business decision. That pattern is provider-specific, but the operating principle is broadly useful: treat the notification as a trigger to inspect state, not automatically as the complete state itself.

The same distinction applies to HubSpot. Its Webhooks Journal and v4 management model is separate from push-to-target-URL subscriptions and uses offsets for event retrieval. Do not treat a Journal history window as proof of a workflow action’s retry period.

Define the event and delivery contract

Before implementation, record the event types you subscribe to, the provider event identifier, any delivery-attempt identifier, event occurrence and receipt times, authentication method, accepted response and deadline, retry policy, ordering behavior, redelivery method, recovery window, and API route for reconciliation.

Keep a logical event distinct from its delivery attempts. A provider may send the same event more than once, and a manual redelivery may reuse a delivery identifier. Store the identifiers the provider actually supplies. Choose the deduplication key from the provider’s documented semantics and the operation you intend to perform. There is no universal event ID that can safely be invented across different HubSpot webhook models.

This envelope is illustrative, not a vendor schema:

{
  "event_id": "evt_example_123",
  "event_type": "record.updated",
  "occurred_at": "2026-10-14T12:00:00Z",
  "object_id": "record_456",
  "data": {
    "status": "active"
  }
}

A useful data model separates at least four grains:

  • Delivery attempt: one transport attempt, with receipt time, response, and transport error.
  • Logical event: one provider event, with its provider event ID and business payload.
  • Processing run: one worker execution, including retry number and processing result.
  • Destination write: one attempted update to a CRM, accounting system, fulfillment system, or other destination.

Enforce uniqueness in the database. A non-atomic “check whether it exists, then insert” sequence can create duplicates when two workers run concurrently. Use a unique constraint with an atomic insert, upsert, or equivalent transaction. For a Stripe event, the provider event ID is commonly useful for duplicate delivery detection. For GitHub, X-GitHub-Delivery identifies a delivery and should be retained, while the business operation may need an additional key based on the event and destination.

Receive quickly, then process durably

The endpoint’s immediate job is to establish that the request is authentic and acceptable, preserve it, and acknowledge it within the provider’s documented deadline. A successful 2xx means the receiver accepted the request. It does not mean that fulfillment, CRM updates, notifications, or AI work has completed.

01Authenticate and validateVerify the provider-specific signature or authentication method, tenant ownership, event type, content type, size, and required structure. Reject or quarantine invalid requests.
02Persist the observationRecord the raw payload reference, provider identifiers, receipt time, and validation result. Use a database uniqueness rule or transactional upsert for concurrent deliveries.
03Acknowledge acceptanceReturn the provider-accepted 2xx response after durable acceptance and within that provider’s documented deadline. GitHub documents a 10-second window, which is GitHub-specific.
04Process and record the outcomeA worker performs the downstream action, records success or failure, and stores any destination write identifier separately from transport acceptance.
05Reconcile or escalateUse the provider’s redelivery or API recovery path, or assign the failed item to a named operator when automatic recovery is unavailable.

Put slow work on a durable queue or equivalent background system. Track states such as accepted, processing, succeeded, failed, and awaiting review. Give operators a way to inspect the event, see processing history, and run a controlled replay.

Do not infer event order from network arrival. GitHub warns that deliveries can arrive out of order and may sometimes take several minutes. Stripe also does not guarantee event order. Use provider-documented sequence information where available, compare current object state through the API when needed, and prevent an older event from silently overwriting newer state.

Secure the endpoint and validate the payload

Use HTTPS for production endpoints and the authenticity mechanism documented for the exact provider feature. Verify signatures against the exact input specified by the provider, before parsing or transforming it when raw bytes are required. Validate content type, payload size, schema, event type, account or tenant ownership, and allowed fields before dispatching work. Keep secrets in protected configuration or a secret manager, and do not place them in public URLs or logs.

  • Stripe: Verify the Stripe-Signature header with the endpoint signing secret and the raw request body. Parsing or changing the body before verification can cause verification to fail. Stripe requires publicly accessible HTTPS for live endpoints; local development can use Stripe CLI forwarding.
  • GitHub: Configure a webhook secret and HTTPS endpoint. Check X-GitHub-Event and, where relevant, the payload’s action before routing work. Track X-GitHub-Delivery for delivery-level diagnostics.
  • HubSpot: Identify the sending feature and signature version first. Workflow documentation describes a request-signature context using the app secret, method, URI, and unparsed body. HubSpot v3 documentation describes X-HubSpot-Signature-v3 and X-HubSpot-Request-Timestamp for supported OAuth apps, including timestamp validation. Do not apply either procedure to an unspecified HubSpot webhook model.

Provider patterns: Stripe, GitHub, and HubSpot

The architecture is reusable, but identifiers, acknowledgement rules, authentication, and recovery options are not interchangeable. The following examples describe verified provider behavior where stated and proposed implementation choices where the provider documentation leaves the application design to you.

Trigger AI job Validation and action Fallback
Stripe payment event None. Payment status comes from the event or an authoritative API read. Verify the raw-body signature, persist the event ID atomically, acknowledge, then queue fulfillment or accounting. Fetch the object when a thin or stale event is insufficient. Use Stripe’s documented retries, API reconciliation, or an operator review. Live-mode retries can continue for up to three days, a Stripe-specific policy.
GitHub repository event None for standard CI triggering. Use explicit event and action rules. Verify the secret, inspect X-GitHub-Event and any action, track X-GitHub-Delivery, acknowledge within 10 seconds, and enqueue CI or notification work. GitHub does not automatically redeliver failed deliveries. Use its manual or developer-built recovery process for recent deliveries.
HubSpot workflow or event None by default. Map known CRM fields deterministically; use AI only for a separate, bounded text task. Select the HubSpot model first, validate its feature-specific authentication and request contract, durably accept the request, and queue the destination update. Check the selected feature’s current recovery options. Do not assume a universal HubSpot retry period.

Stripe: payment event to fulfillment

For a selected Stripe event, verify the raw request, persist its Stripe event ID under a unique constraint, and acknowledge before fulfillment begins. A worker can then create a fulfillment task or accounting entry. If the event is thin, incomplete for the decision, or potentially stale, fetch the related object through Stripe’s API.

Stripe documents duplicate deliveries, unordered events, and live-mode retries for up to three days. Those are Stripe-specific rules, not a general webhook promise. For supported Stripe API writes, idempotency keys can make request retries safer, but they do not replace deduplication of incoming webhook events. See Stripe’s webhook documentation and Stripe API idempotent requests.

GitHub: repository event to CI

Subscribe only to events the workflow needs. On receipt, verify the configured secret, inspect X-GitHub-Event and any relevant payload action, then enqueue the build or notification. Track X-GitHub-Delivery. A redelivery can reuse that identifier, so delivery tracking must not treat every HTTP attempt as a new business event.

GitHub does not automatically redeliver failed deliveries. Its documentation describes manual or developer-built recovery, with recent delivery records and redelivery available for three days. That window is a GitHub recovery detail, not a universal retention period. See GitHub receiver best practices, failed-delivery guidance, and redelivery instructions.

HubSpot: distinguish three integration models

HubSpot uses webhook terminology for different products and features. Select the model before designing authentication, storage, or recovery:

  • Workflow action: The Send a webhook action sends CRM data to an external endpoint. HubSpot’s current Knowledge Base identifies this action with Data Hub Professional and Enterprise availability. Confirm the target account’s subscription, permissions, UI, methods, and authentication options before implementation.
  • Developer-platform event subscription: A project-based app configuration specifies a target URL and subscribed events. Current documentation describes POST delivery and a required 2xx acknowledgement, along with configuration such as maxConcurrentRequests. Follow that feature’s setup rather than a workflow-action tutorial.
  • Webhooks Journal and v4 management APIs: This is a separate API model for managing subscriptions and retrieving event history. It uses offsets and does not use the push model’s target URL. The Journal documentation describes three days of historical event data. That is not evidence of a workflow action’s retry period.

HubSpot workflow documentation describes request-signature verification using an app secret, HTTP method, URI, and unparsed body. Its v3 signature documentation covers a different context involving supported OAuth apps. Verify the sending feature and version before writing verification code.

Do not combine configuration or recovery assumptions across these models. Organizations reviewing how HubSpot workflows fit into wider operating processes can explore HubSpot systems support.

Use AI only for a bounded decision

Hypothetical design: A support platform sends an authenticated new-ticket event. The integration stores the event and queues classification. It sends only minimized, permitted message text to an AI classifier, which suggests a category and urgency. A deterministic validator checks the output against allowed values, verifies the ticket identity and freshness, and routes low-confidence or consequential cases to a human.

The classifier must not determine payment status, consent, permissions, deletion, or other provider-authoritative fields. Those values should come from the source event, an authoritative API, or a controlled business rule.

{
  "source_event_id": "evt_ticket_789",
  "ticket_id": "ticket_456",
  "category": "account_access",
  "urgency": "normal",
  "confidence": 0.86,
  "evidence_spans": [
    "cannot access my account"
  ],
  "model": "recorded-model-identifier",
  "prompt_version": "ticket-routing-v1"
}

The fields and values are illustrative. Before writing to a CRM or ticket field, require a valid schema, an allowlisted category and urgency, a matching record, a freshness check, and a defined confidence threshold. Invalid output, conflicting data, or low confidence goes to a review queue.

Keep the data at its actual grain. Store one row per logical source event, one per AI run, one per field-level decision where needed, and one per destination write attempt. A proposed AI-run key can combine the logical event ID with a run identifier, model, and prompt version. A write-attempt key can combine the event ID, destination record, field, and operation. Enforce these keys with a database uniqueness constraint or transactional upsert. Do not use only a date, customer ID, event type, or prompt version as a unique key.

AI agent services can help teams define a bounded AI role and its controls.

Test, recover, and measure the integration

Test the real receiver path before launch with valid and invalid signatures, malformed payloads, duplicate deliveries, out-of-order events, queue failures, slow downstream services, and replay behavior. Use non-sensitive test data. webhook.site can temporarily inspect incoming requests, while Pinggy can expose a local development server for callback testing. Neither is production persistence, delivery, or retry infrastructure.

Recovery must match the selected provider and feature. Stripe documents automatic live-mode retries for up to three days. GitHub does not automatically redeliver failed deliveries, but supports manual or developer-built recovery for recent deliveries. For HubSpot, use the recovery mechanism for the specific workflow, developer-platform, or Journal model selected. If a recovery window has expired, reconcile through an API where supported or assign a controlled operator recovery task.

Make failed work visible with event and delivery identifiers, receipt time, processing state, error category, destination, and replay history. Useful measures include accepted-event rate, processing latency, duplicate suppression, age of unresolved failures, replay success, and manual-review volume. These are operational measures, not promises about provider performance.

Review before rollout
  • The exact provider feature, event contract, identifiers, and system of record are documented.
  • Signature or other authenticity checks have positive and negative tests.
  • The endpoint persists or durably queues before acknowledging.
  • Duplicate handling uses a database-enforced uniqueness rule or transactional upsert.
  • Ordering, retry, redelivery, and recovery behavior are recorded for this feature.
  • Slow downstream work, dead-letter items, and manual review have named owners.
  • An API reconciliation path is defined where the provider supports one.

Decide whether a webhook is the right fit

Use a webhook when an event should trigger a timely reaction and the team can operate a durable receiver and recovery path. An infrequent read-only task may be simpler as an API request. A high-value event workflow needs more than a callback URL: it needs durable acceptance, correct data grain, provider-specific deduplication, and a recovery owner.

Before launch, answer four questions: Who owns an unprocessed event? How are duplicate deliveries recognized? Which system is authoritative for each important field? How will missed events be reconciled after downtime or an expired recovery window?

A no-code automation layer may suit a simple, low-risk workflow, but it still needs provider-specific checks for authentication, acknowledgement, duplicate handling, and recovery. See Zapier automation services when evaluating that kind of workflow.