Back to Blog
Implementation

Voice AI Webhook Retries: How to Prevent Duplicate CRM Tasks

ConversAI Labs Team
7 min read
Voice AI Webhook Retries: How to Prevent Duplicate CRM Tasks

Featured Article

Implementation

A voice AI webhook handler should accept repeated deliveries without repeating the business action. Verify the sender, identify the event, save it durably, and process the CRM update or follow-up task with its own stable action key. Track receipt and completion separately so a retry can recover failed work without creating a second task.

This guide is for developers and marketing operations teams connecting call results to business systems. It expands the result-handler step in our API and webhook workflow guide. The example below is a proposed application design, not a tested deployment or a claim that ConversAI Labs provides these delivery guarantees.

Why can one call produce duplicate webhook deliveries?

A provider may retry when it does not receive a successful response in time. Your application might already have accepted the event while the acknowledgement was lost. Repeating the request can therefore be legitimate.

For a concrete voice example, Retell documents a ten-second webhook timeout and up to three retries without a successful response. It also distinguishes call-end events from completed-analysis events. A handler that needs analysis must use the appropriate event rather than assume the first result is complete. These details are specific to Retell's webhook contract, reviewed on 16 September 2026; check your own provider's contract before implementation.

Imagine an agent qualifies a callback request and your integration creates a sales task. If the same result is delivered again, the correct outcome is still one task. The integration should record that another delivery occurred without asking the salesperson to follow up twice.

Which identifier should prevent duplicates?

Use two identifiers with different responsibilities:

Identifier Purpose Illustrative value
Event key Recognize repeated delivery of the same event Provider account plus documented event ID
Business-action key Recognize an operation that should happen once Workspace plus callback request plus follow-up action

Keep provider and account scope in the event key if identifiers are not globally unique. Keep workspace scope in the action key so separate customers cannot suppress each other's work.

When no event ID exists, use the provider's documented event semantics. Retell recommends event type plus call ID for its per-call lifecycle events. Its repeating transcript updates and multiple transfer attempts need different handling. Deduplicating every message using only a call ID would discard valid updates. See its event-specific deduplication guidance.

The business key depends on your own workflow. For our example, a callback request should create one qualification follow-up. A later, separately requested callback needs a new request identifier. A phone number alone would merge those distinct requests.

What should the receiving endpoint do?

Keep the receiving path short, with a durable boundary before acknowledgement:

  1. Verify the signature using the provider's supported method and required request representation.
  2. Validate the event type and required fields, then correlate it to the correct workspace and request.
  3. Insert the event into a durable inbox using a unique event key.
  4. If that key already exists, acknowledge receipt while leaving the existing processing state intact.
  5. Return success after durable acceptance; let a worker perform the business action.

GitHub's webhook best practices likewise recommend validating deliveries and using asynchronous processing for timely responses. Its headers and timing contract apply to GitHub, not automatically to a voice platform.

A database constraint is more reliable than an in-memory “seen IDs” list for this design: separate workers need one shared decision about whether an event is new. Do not mark the event completed merely because the inbox insert succeeded. If storage fails, follow the provider's documented failure-response contract and retain an operational alert.

How do you avoid losing work between systems?

Saving an event and sending a queue message are two writes. If only the first succeeds, work can remain stranded. One option is for workers to claim pending inbox records directly. Another is to save the inbox record and a dispatch record in the same database transaction, then publish dispatch records independently.

This second approach uses a transactional outbox. AWS explains how the outbox pattern addresses the gap between database changes and event publication. Delivery can still repeat, so the consumer must tolerate duplicates. The pattern does not make an external CRM write atomic with your database.

For the callback example, keep three separate records: received event, requested follow-up action, and confirmed destination result. Record a destination task ID only when you have evidence of it. This gives an operator a precise place to recover work.

What if the CRM creates the task but the response is lost?

This is the difficult failure case. Your worker sees a timeout, but creating the task again might produce a duplicate.

Use the destination's documented idempotency mechanism when available, reusing the same key for retries of the same operation. Otherwise, use a supported unique external reference and lookup or upsert operation. A separate lookup followed by an unconstrained create still has a race; it is not a guarantee.

If the destination offers neither a reliable idempotency mechanism nor a safe way to confirm the earlier result, mark the operation uncertain and route it for reconciliation. Do not turn every timeout into a new task creation request. In our example, showing one follow-up as “needs verification” is more actionable than silently assigning two identical tasks.

Can events arrive out of order?

Design state changes around the documented contract, not arrival time alone. Stripe explicitly does not guarantee event delivery order and advises identifying duplicate deliveries by event IDs. That is a useful example of why assumptions need checking, not proof of any voice provider's ordering behavior. See Stripe's ordering and duplicate-event guidance.

For your own call-result model, define which fields each event may update. A late progress event should not reopen an already completed follow-up. If required information is missing, fetch current state through a supported read API or leave the action pending. Preserve the original event reference so the decision can be investigated.

What should you test before enabling the workflow?

Use synthetic events and designated test records. The following cases test the proposed design; they are not a report of tests performed against a provider.

Test input or failure Expected evidence
Same event delivered twice One inbox event, recorded delivery attempts, one intended action
Same event arrives concurrently Unique-key conflict handled without duplicate business work
Two different lifecycle events for one call Both retained; only eligible events trigger the action
Worker stops after durable receipt Pending work resumes after restart
CRM write succeeds but response times out Existing action is confirmed or flagged uncertain before retry
Analysis arrives after a call-end event Follow-up waits for the fields its rule requires
Invalid signature or unmatched request No update to an arbitrary customer record

Track pending-action age, failed processing attempts, uncertain destination writes and duplicate deliveries separately. A high webhook receipt count is not a count of completed calls, qualified leads or created tasks.

How does this fit a ConversAI Labs workflow?

Start with one agent task and one destination action. Use the ConversAI Labs documentation and API reference to verify supported authentication, event fields and operations. Confirm retry and signature details for the integration you actually deploy; the vendor examples in this article do not establish ConversAI Labs behavior.

ConversAI Labs publishes this guide. For account setup and current call-credit terms, see pricing. Before adding more automation, make one repeated result safe: one callback request, one intended follow-up, and an auditable recovery path when the destination is unavailable.

C

About ConversAI Labs Team

The ConversAI Labs team writes about building and operating voice AI workflows.