Skip to content
Display settings
Reading preferences

Saved only in this browser.

Start free

eSignature Webhook Failure Handling: A Dead-Letter, Replay, and Privacy Design for Platform Teams

Executive brief

For teams evaluating resource esignature api guide

Use this guide to frame compliance risk, signing workflow fit, buyer readiness, implementation effort, and cost before choosing an eSignature path.

  • Clarifies where electronic signatures can reduce approval delays.
  • Connects the topic to relevant eSignly plans, API options, and security controls.
  • Helps decision makers compare legal, operational, and adoption tradeoffs.
View related solutionCompare plans
eSignature Webhook Dead Letters, Replay & Privacy Controls
eSignature Webhook Dead Letters, Replay & Privacy Controls

Most eSignature integrations are tested on the happy path: a signer completes a document, a webhook arrives, a record flips to "executed." The path that decides whether your integration survives an audit, an outage, or a privacy review is the other one: an event that can never be processed, arrives for a record you do not recognize, contradicts your current state, or carries signer data that ends up in a queue nobody owns.

This article answers one question for the engineer or platform lead who carries the pager: how should an eSignature integration handle webhook events that fail permanently, arrive out of order, or cannot be trusted, without losing signed-document evidence, applying a stale event, or leaking signer personal data?

It is a deliberate follow-on to eSignly's existing guidance on API timeouts and unknown outcomes and on idempotency, retries, and webhook resilience. Those pieces cover how to send safely and receive reliably. This one covers what happens after reliability has run out: terminal failure, dead letters, replay, and who owns the data while it waits.

The design below is a proposed design, not an established eSignly method and not a statement of how any specific vendor behaves. It assumes the safest general posture for any webhook source: delivery is at-least-once, ordering is not guaranteed, and the sender's retry behavior must be confirmed in its current API reference. All code is illustrative and is not an official eSignly API contract.

Key Takeaways

  1. Acknowledge only what you have durably recorded. A 2xx response should mean "verified and committed to our database," never "received and logged somewhere."
  2. Dedupe, record, and schedule in one atomic write. If the inbox row is also the work item, there is no gap between "we saw it" and "we will act on it."
  3. A dead-letter queue is a holding area, not an archive. Retention clocks, redrive behavior, and access rules need an owner before the first failure.
  4. Never replay blindly. A replayed event must pass through the same verification, tenant-scoped dedupe, and conditional mutation as a live one, after reconciling against authoritative state.
  5. Unknown means unconfirmed. It is neither success nor verified failure, and it needs a deadline and an owner.
  6. Identifiers are data too. Envelope IDs, document IDs, and signer emails can identify a person or a contract. Keep them out of logs, alerts, and test fixtures by default.
  7. Use a go/no-go gate, not a score. Every control in the readiness table must pass for consequential workflows. This is a design-review gate, not a compliance certification.

Why Some eSignature Events Can Never Be Processed Cleanly

Key takeaway: Retrying fixes transient failures only. Several other failure classes will never succeed on retry, and treating them all the same is how teams lose events or loop forever.

An eSignature webhook is a message about something that happened on another system's clock. Your system receives it later, possibly twice, possibly after you have moved on, and possibly before you finished recording the thing it describes. That mismatch is structural, not a bug in any vendor.

The signing platform's integrations page describes the basic mechanic: you configure a webhook URL, and the platform sends a POST request with a JSON payload when events such as a document being sent, viewed, signed, or declined occur (see eSignly's integrations page). What that page does not promise, and what no webhook design should assume, is exactly-once or strictly ordered delivery. Build as if neither exists.

Once you accept that, a handful of failure classes appear. They need different handling, which is why a single "retry then dead-letter" rule is not enough.

Six failure classes and what each one means

ClassExampleWill retry fix it?Correct disposition
Transient dependency failureYour database or CRM API is down for minutesYesRetry with backoff and jitter, capped attempts
Unknown reference"Completed" event arrives for a sign request your system has no record of, perhaps because your create call timed outSometimesHold for a bounded time, then reconcile against provider state
Out-of-order or stale eventA "viewed" event arrives after "completed," or a "signed" event arrives after the contract was voided internallyNoCompare to current state; apply, discard as stale, or escalate
Schema or contract violationA new field type or missing required field breaks your parserNo, until code changesQuarantine, fix the code, replay after approval
Conflicting duplicateSame event ID, different payload contentNoQuarantine as an anomaly; never overwrite the first record
Authenticity failureSignature does not verify, or timestamp is outside your windowNoReject at the edge; do not enqueue the payload

Notice that only the first row is helped by the retry machinery most teams build first. The other five are decisions, and decisions need an explicit owner and a durable record of the outcome.

How Most Teams Handle Failed Webhook Events, and Why It Breaks

Key takeaway: The common patterns optimize for getting a 200 back quickly. None of them answers what happens to the event afterward, which is the part auditors and customers eventually ask about.

Teams rarely design failure handling up front. It accretes: a try/catch, a log line, a retry loop, then a queue, then a dead-letter queue added after the first incident. Each step is reasonable. The result is a system where nobody can say what state a given event is in.

Common approaches compared

ApproachWhat it doesWhere it fails
Log and return 200Always acknowledges, writes failures to application logsThe sender stops retrying while your only copy lives in a log that rotates. The event is effectively lost, and the log may now hold signer data.
Return 500 on any errorLets the sender retry everythingPoison events retry until the sender gives up. You depend on the sender's schedule and ceiling, which you do not control.
In-process retry loopRetries inside the request handlerSlow responses cause sender-side timeouts and duplicate deliveries. Worker restarts erase retry state.
Queue plus DLQ, no policyMoves failing messages to a dead-letter queue after N attemptsThe DLQ becomes a landfill. Retention expires silently, and redrive happens by ad hoc script.
Manual database patchAn engineer updates the record by hand after reading the payloadNo dedupe, no audit record of why, and no check that the event is still current.

The queue-retention trap, with a sourced example

Dead-letter queues carry their own clocks. In Amazon SQS standard queues, a message's expiration is based on its original enqueue timestamp, and that timestamp is unchanged when the message moves to a dead-letter queue. AWS's own documentation gives the arithmetic: if a message spends one day in the source queue and the dead-letter queue's retention is four days, it is deleted from the dead-letter queue after three more days. AWS therefore recommends setting dead-letter retention longer than the source queue's (Amazon SQS dead-letter queue documentation).

Two more behaviors from the same documentation matter for replay. A redrive task resets the retention period, and redriven messages receive a new message ID and enqueue time (SQS dead-letter queue redrive). The practical consequence: your idempotency key must be the provider's event identity, never the queue's message ID, or a redriven event will look new. SQS also does not support filtering or modifying messages during redrive, so any "fix then replay" step has to happen outside the queue.

These details are specific to SQS. Other brokers differ, which is exactly why retention and redrive semantics belong in your design document and not in tribal knowledge.

A Proposed Design: The Five-Lane Event Disposition Model

Key takeaway: Give every verified event exactly one durable disposition: apply, hold, retry, reconcile, or quarantine. Acknowledge only after the record exists.

The following is a proposed design for teams building or reviewing an eSignature webhook receiver. It is not a proprietary eSignly framework and is not a description of any production system. Its purpose is to make the question "what happened to this event?" answerable with a database query.

The flow

Provider POST    |    v [1 Verify authenticity: signature over the raw body, timestamp window]    |-- fail --> reject (4xx), increment counter, store no payload    v [2 One transaction: insert inbox row (tenant_id, provider_event_id,     payload hash, state=RECEIVED, next_attempt_at=now)]    |-- commit fails --> 5xx (sender may redeliver)    |-- same event id, same hash --> duplicate: 2xx, no new work    |-- same event id, different hash --> write CONFLICT record, 2xx after commit    v 2xx acknowledgment (a durable record now exists)    |    v [3 Worker claims row with a lease, then classifies]    |-- APPLY      : conditional update succeeds       --> APPLIED    |-- HOLD       : reference not known yet            --> HELD (deadline)    |-- RETRY      : dependency down                    --> backoff + jitter, capped    |-- RECONCILE  : uncertain or contradictory input   --> read authoritative state    |-- QUARANTINE : terminal (schema, conflict, stale) --> QUARANTINED, alert without payload

Verified acknowledgment: what each response should mean

SituationResponseReasoning
Signature or timestamp check fails4xx (for example 401 or 403)The sender is not authenticated. Do not store the body. Count it for security monitoring.
Verified, durably committed2xxPer RFC 9110, 2xx indicates the request was successfully received and accepted. Here it additionally means a durable record exists.
Verified, but your database write failed5xxYou have not recorded it, so you must not claim you did. Let the sender's redelivery policy help, and confirm that policy in its documentation.
Verified, committed, but business logic will never accept it2xx after the quarantine record commitsRetrying cannot help. Keep the evidence in your own store rather than depending on the sender's retry window.

Transport authenticity has limits. A valid signature or a TLS connection tells you who sent the bytes. It does not tell you the signer's identity was adequately verified, and it does not tell you the event is current. Those are separate questions handled in your identity and reconciliation steps.

Why the inbox row is also the work item

A frequent bug is a dual write: insert into a dedupe table, then publish to a queue. If the process dies between the two, the event is recorded as seen and never worked. The reverse order produces duplicate work. Making the inbox row carry its own state and next_attempt_at means dedupe, durable recording, and scheduling are a single atomic write. A poller or scheduler claims rows from that table. If you prefer a broker, use a transactional outbox so the publish is derived from the committed row and is recoverable after a crash.

Illustrative inbox schema and claim logic

The SQL below is a PostgreSQL-flavored sketch. It illustrates the invariants: tenant-scoped identity, a payload hash that detects changed-content reuse, an atomic claim that works under concurrent workers, and a conditional mutation on the target record.

CREATE TABLE webhook_inbox (   tenant_id         text        NOT NULL,   provider_event_id text        NOT NULL,   payload_sha256    bytea       NOT NULL,   payload_ref       text        NOT NULL,  -- pointer to encrypted raw body   state             text        NOT NULL DEFAULT 'RECEIVED',   attempts          int         NOT NULL DEFAULT 0,   next_attempt_at   timestamptz NOT NULL DEFAULT now(),   lease_until       timestamptz,   hold_deadline     timestamptz,   received_at       timestamptz NOT NULL DEFAULT now(),   PRIMARY KEY (tenant_id, provider_event_id) );  -- Receiver: dedupe + record + schedule in one statement INSERT INTO webhook_inbox (tenant_id, provider_event_id, payload_sha256, payload_ref) VALUES ($1, $2, $3, $4) ON CONFLICT (tenant_id, provider_event_id) DO NOTHING; -- 0 rows inserted: load existing row, compare payload_sha256. -- Equal: duplicate, acknowledge. Different: write a conflict record, then acknowledge.  -- Worker: atomic claim safe under concurrent workers UPDATE webhook_inbox    SET state = 'PROCESSING', attempts = attempts + 1,        lease_until = now() + interval '2 minutes'  WHERE (tenant_id, provider_event_id) IN (    SELECT tenant_id, provider_event_id      FROM webhook_inbox     WHERE (state IN ('RECEIVED','RETRY') AND next_attempt_at <= now())        OR (state = 'PROCESSING' AND lease_until < now())     ORDER BY received_at     LIMIT 10     FOR UPDATE SKIP LOCKED) RETURNING ;  -- Target-side conditional mutation, not read-compare-then-write UPDATE contract    SET status = 'EXECUTED', executed_event_id = $1  WHERE tenant_id = $2 AND envelope_ref = $3    AND status IN ('SENT','PARTIALLY_SIGNED'); -- 0 rows affected: do not guess. Read current state and classify as -- ALREADY_APPLIED, STALE, or CONFLICT.

Two notes on this sketch. First, the hash should cover the canonical event content, not delivery metadata such as a per-attempt timestamp, or legitimate redeliveries will look like conflicts. Check what your provider actually varies between attempts. Second, "read the row, compare, then write" in application code is not compare-and-swap, because another worker can change the row in between. The WHERE status IN (...) clause makes the database enforce the condition atomically. If your target is a system you cannot condition (a CRM API without conditional updates, for example), disclose that limitation and serialize writes per record, such as one worker per contract ID.

Why This Fails in the Real World

Key takeaway: Capable teams fail here because failure handling is owned by no one. The scenarios below are illustrative composites, not customer results.

These are illustrative scenarios built from common failure patterns. They are not drawn from any named customer or eSignly deployment, and the figures are invented to show mechanics.

Scenario 1: The dead-letter queue that expired its own evidence

A team routes failed webhook messages to a dead-letter queue after several attempts, and sets a short retention on it to keep costs down. A downstream CRM outage lasts most of a weekend. On Monday, an engineer sees alarms clear and assumes the backlog drained. Several "completed" events had already aged out, because retention was measured from the original enqueue time, not from the moment they hit the DLQ. The contracts were signed on the provider's side; the company's order system never learned it.

Why intelligent teams still fail: the alert fired on queue depth, not on message age. Nobody owned the question "how long can an unprocessed event live?" The fix is a design rule: retention for dead letters is longer than the source queue, age-of-oldest alarms exist, and the inbox table (not the broker) is the system of record for event state.

Scenario 2: The replay that resurrected a voided contract

A parsing bug quarantines a batch of "signed" events. After the fix, an engineer redrives everything. One event belongs to a contract that sales operations voided and reissued two days earlier. Replay applies the old signature to the superseded record, and a provisioning job grants access under terms that no longer exist.

Why it happens: replay ran through a faster path than live traffic and skipped the state check. Nobody had written down that "replay" is a privileged operation with preconditions. The fix: replay re-enters the same classifier, the conditional mutation rejects a record whose state has advanced, and stale events default to discard-or-escalate, never apply.

Scenario 3: The alert that carried the signer's email

To make on-call triage easier, the failure handler posts the full payload to a team chat channel. The payload includes signer email addresses and document titles. The channel has broad membership, a long retention default, and external guests. No one intended a disclosure; the alert template simply predated the privacy review.

Why it happens: debugging convenience and data protection were owned by different groups with no shared checklist. The fix is to alert on event ID, tenant, state, and error class only, and to fetch the payload through an access-controlled tool when an engineer needs it.

The common thread

  1. Failure handling was built reactively, after the first incident.
  2. The message broker was treated as the record of truth rather than a transport.
  3. Replay and data retention were treated as engineering conveniences instead of governed operations.
  4. No single role could answer "what happened to event X?" in minutes.

Replay, Reconciliation, and Uncertain Input Without Double Effects

Key takeaway: Replay is a controlled re-entry, not a shortcut. When the outcome is unknown, reconcile against authoritative state first; do not retry a consequential mutation blindly.

Replay decision matrix

Replay situationPreconditionDefault actionApproval
Event never applied because a dependency was downInbox state is RETRY or PROCESSING with expired leaseRe-enter classifier; conditional mutation decidesAutomatic, rate-limited
Event already APPLIEDInbox state is APPLIEDNo-op; record that a duplicate was suppressedNone; cannot be forced
Quarantined for schema violation, code since fixedFix deployed and tested against redacted fixturesDry-run, then single or small-batch replayEngineering owner
Target record has moved on (voided, superseded, amended)Current state differs from event's assumed stateReconcile; default to discard-as-stale or escalateBusiness process owner
Conflicting duplicate (same ID, different content)Hash mismatch recordedNever auto-apply; investigateSecurity and engineering
Reproducing a bug in a non-production environmentRedacted or synthetic payloadDo not copy production payloadsPrivacy owner if exceptions are requested

Reconcile-first for uncertain input

Uncertain input includes an event that references an unknown envelope, an event that contradicts current state, and an outbound call whose response you never received. In each case, the right move is to read the authoritative state from the provider (a read-only status lookup, as supported by the API you use) and compare it to your record before you mutate anything. Confirm in the current eSignly API documentation which status-retrieval operations exist and what they return, then build the reconcile step on those, not on assumptions.

Treat the result as one of three outcomes: confirmed (authoritative evidence supports applying the event), refuted (authoritative evidence shows it is stale or wrong), or unknown (you could not obtain evidence). Unknown is not success and it is not verified failure. Give it a state of its own, an owner, a deadline, and an escalation path. The companion article on timeouts and unknown outcomes covers the outbound side of this in more depth.

Outbound operations: identity, payload hash, and legitimate later operations

When your system initiates a consequential action, such as sending a contract for signature, bind a durable operation identity to the exact approved payload. The sketch below shows the idea.

CREATE TABLE outbound_operation (   tenant_id        text        NOT NULL,   operation_id     text        NOT NULL,   -- stable business intent, e.g. contract + version   payload_sha256   bytea       NOT NULL,   -- hash of the approved, immutable payload   state            text        NOT NULL DEFAULT 'CLAIMED',   provider_ref     text,   created_at       timestamptz NOT NULL DEFAULT now(),   PRIMARY KEY (tenant_id, operation_id) );  -- Claim atomically; only one worker proceeds INSERT INTO outbound_operation (tenant_id, operation_id, payload_sha256) VALUES ($1, $2, $3) ON CONFLICT (tenant_id, operation_id) DO NOTHING; -- 0 rows: load existing. Same hash: resume or reconcile that operation. -- Different hash: reject as changed-payload key reuse. Never overwrite.

The rules this encodes:

  1. Tenant-scoped identity. Two tenants can legitimately generate the same internal ID. The key is the pair, never the ID alone.
  2. Immutable payload hash. Reusing an operation ID with different content is a defect or an attack, not a retry.
  3. Atomic claim. The unique constraint decides which concurrent worker owns the work.
  4. Legitimate later operations. A re-send after a decline, or a new contract version, is a new operation with a new identity derived from the new business intent. Do not suppress it as a duplicate.
  5. Ambiguous timeout. Move to reconcile, not retry. Resend only after the authoritative state shows no matching request exists, or when the provider's documented idempotency mechanism guarantees safety. If your provider does not document one, enforce it yourself with the ledger above and verify behavior before relying on it.

Privacy and Retention Ownership for Dead Letters and Replay Stores

Key takeaway: Dead-letter and replay stores hold signer data longer than anyone planned. Assign retention, access, and erasure ownership before launch, and treat identifiers as potentially personal data.

Webhook payloads often contain more than status. Depending on your configuration and the provider's payload design, they can include signer names, email addresses, document titles, timestamps, and IP-related details. Even "just IDs" can be personal or confidential data when they can be linked back to a person or a contract. Plan on the assumption that anything in the payload may be sensitive, then verify the actual fields for your integration.

Handling by data element

ElementWhy it mattersDefault handling
Signer email or nameDirectly identifies a personKeep in encrypted raw-payload store only; never in logs, alerts, or tickets
Envelope or document IDLinkable to a person or deal through your own systemsAllowed in operational telemetry with access control; treat as internal identifiers
Document titles and namesMay contain client names or deal detailsExclude from alert text; fetch on demand under access control
IP address or device data, if presentCan be personal data and evidentiary detailStore only where required; apply the same retention as the evidence record
Webhook secrets and signature headersAllow forgery if exposedNever log; rotate on suspicion; store in a secrets manager
Payload hash and event IDLow sensitivity, high operational valueSafe default for logs and alerts

The OWASP Logging Cheat Sheet lists categories of data that generally should not be logged in the clear, including credentials and sensitive personal data, and recommends masking or removing them. For a framework on identifying and protecting personally identifiable information, see NIST SP 800-122. Both are guidance, not law, and neither tells you what your own legal obligations are.

Who owns what

DecisionTypically owned byWhy
Mechanics: queue configuration, redrive tooling, alarmsEngineering or platformThey operate the system
Retention schedule for quarantined and raw payloadsPrivacy or data protection lead, with LegalBalances minimization against evidence retention
Whether a quarantined event can be applied or discardedBusiness process ownerThey own the contract's consequences
Access to raw payloadsSecurity, with named approversLeast privilege and auditability
Erasure requests versus legal holdsLegal and privacyEngineering should not decide this at 2 a.m.

Scope your claims carefully

Three distinctions keep this section honest. First, vendor statements are not your obligations met: eSignly states that it maintains ISO 27001, SOC 2 Type II, HIPAA, GDPR, 21 CFR Part 11, and PCI DSS alignment, and publishes information on its security page and compliance page. Treat those as vendor statements, request current reports and data processing terms, and note that a vendor's attestation covers the vendor's systems, not your webhook receiver, your queue, or your chat channel. Second, compliance-support features are not compliance: audit trails and access controls help, but whether your use satisfies GDPR, HIPAA, or FDA 21 CFR Part 11 depends on your role, your data, and your validation work. Third, regulated records may constrain deletion. If an event is part of an electronic record under rules such as 21 CFR Part 11, your retention and deletion design needs Legal and quality input, not just an engineering default. This article is not legal advice.

Go/No-Go Readiness Gate and What to Verify With Your Provider

Key takeaway: Every control below must pass before a consequential workflow, such as contract execution or provisioning, depends on webhook-driven state. One failure is a no-go. There is no score to average away a gap.

Mandatory go/no-go controls

Use this as a design-review gate. It does not certify production readiness or compliance. It identifies gaps that commonly turn into incidents.

#Control (all required)Evidence to showNo-go if
1Authenticity verified over the raw body before any storageTest with tampered body and stale timestamp; both rejectedVerification runs after parsing or after enqueue
22xx returned only after a durable commitFault-injection test: kill the database mid-request, observe 5xxAcknowledgment precedes persistence
3Dedupe key is tenant-scoped provider event identitySchema and unit test with two tenants sharing an IDKey is a queue message ID or a bare ID
4Dedupe, record, and scheduling are atomic or explicitly recoverableCrash test between steps shows no lost or double-run eventSeparate dual write with no reconciler
5Changed-payload reuse of an event or operation ID is rejected and recordedTest with same ID, different hashSecond payload overwrites or is silently ignored
6Concurrent workers cannot process the same itemLoad test with lease-based claimClaim relies on read-then-update in application code
7State mutation is conditional on the target sideZero-row-affected path is classified, not retried blindlyRead-compare-then-write with no serialization or disclosure
8Terminal states exist and are reachable (QUARANTINED, DISCARDED_STALE)Runbook plus a drill that reaches each stateOnly success and retry exist
9UNKNOWN has an owner and a deadlineQuery lists unknown items with age and assigneeUnknown is logged and forgotten
10Dead-letter retention exceeds source retention; age alarms existConfiguration export and alarm testAlarm is on depth only
11Replay passes through the live classifier and requires approval by typeReplay drill with a stale event is discarded or escalatedReplay uses a bypass script
12No signer data in logs, alerts, or non-production fixturesLog scan and alert template reviewPayloads appear in chat or tickets
13Retention, access, and erasure owners are namedWritten policy with ownersOwnership is "engineering" by default

Questions to confirm with any eSignature provider

Do not assume answers. Check the current API reference and, for contractual points, the agreement itself. eSignly's published integration documentation describes webhook configuration and event types such as sent, viewed, signed, and declined. Other behaviors below should be verified in the current API reference before you build on them.

QuestionWhy it changes your design
How are webhooks authenticated (signature scheme, header name, timestamp)?Determines control 1 and your replay-attack window
Is the event ID stable across redeliveries of the same event?Required for control 3
What is the retry schedule, the ceiling, and how are non-2xx responses treated?Sets your acknowledgment strategy and how long you can rely on redelivery
Is ordering guaranteed?If not, you need the Hold and Reconcile lanes
Which status-lookup endpoints exist for reconciliation?Enables read-only authoritative comparison
Can missed events be resent on demand?Determines whether provider-side replay is an option
Which personal data fields appear in payloads, and can they be minimized?Drives section six handling
Is an idempotency mechanism documented for create operations?If not, your outbound ledger is mandatory
Which source IP ranges or network controls are documented?Optional defense in depth; do not rely on it alone

For related depth on signature verification and trust boundaries, see eSignly's guide to webhook security. If a failure has already damaged your evidence chain, the emergency playbook for recovering non-repudiation covers recovery.

Want to test this design against a real sandbox?

Start with the free API plan, wire up a webhook receiver, and run the readiness gate against live event types before you commit.

Try eSignly's API and run your failure drills first.

Start Free

2026 Update: What to Re-verify Each Year

The principles here are stable, but the details around them move. Once a year, and after any provider or infrastructure change, re-check the following:

  1. The provider's current webhook documentation: signature scheme, retry behavior, event types, and payload fields.
  2. Your queue or broker's retention, redrive, and visibility behavior, using its current documentation rather than memory.
  3. Current vendor attestation reports and data processing terms.
  4. Your own drill results for controls 2, 4, 6, and 11. A control that has not been exercised recently is an assumption.

Conclusion: Decide Before the Incident Does

A webhook receiver is finished when you can explain, for any event, what it was, what you did with it, and why. These actions turn that standard into a plan:

  1. Run the thirteen-control gate against your current receiver and mark each as pass or fail with evidence. Treat any fail as a blocker for consequential workflows.
  2. Move event state into your own database. Make the inbox row the record of truth and the broker a transport, then add disposition states for hold, reconcile, and quarantine.
  3. Write the replay policy as a table like the one above, with approval roles, and remove any bypass scripts.
  4. Name the privacy and retention owners for raw payloads and quarantined items, and strip signer data from logs and alerts.
  5. Schedule a failure drill: a stale event, a conflicting duplicate, and a database outage. Record what actually happened, then fix the gaps.

About the eSignly Expert Team

eSignly has provided online eSignature software and APIs since 2014 and serves more than 100,000 users. The company states that it maintains ISO 27001, SOC 2 Type II, HIPAA, GDPR, 21 CFR Part 11, and PCI DSS alignment; readers should review the current details on its security and compliance pages and request supporting documentation as part of vendor diligence. This article was reviewed by the eSignly Expert Team. It offers engineering guidance, is not legal advice, and does not certify any specific implementation as compliant.

Frequently Asked Questions

Should a webhook receiver return 2xx for an event it cannot process?

It depends on why processing failed.

  1. If authenticity checks fail, return a 4xx and do not store the payload.
  2. If you could not durably record a verified event, return a 5xx so you are not claiming receipt.
  3. If the event is verified and durably recorded but business logic will never accept it, return 2xx after the quarantine record commits, since retrying will not help.

Confirm how your provider treats each status code in its current documentation.

What is the difference between a dead-letter queue and an inbox table?

A dead-letter queue holds messages a consumer could not process, with broker-specific retention and redrive rules. An inbox table is your application's durable record of every verified event and its state. The proposed design uses the inbox as the system of record and treats the queue as transport, so retention expiry in a broker cannot erase the only evidence of an event.

Can I safely replay a webhook event from a dead-letter queue?

Only if replay re-enters the same path as live traffic: verification, tenant-scoped dedupe on the provider event ID, and a conditional mutation that checks current state. Replaying through a bypass script risks applying stale events, for example to a voided or superseded contract. Redrive can also change message IDs, so dedupe on the provider's event identity, not the queue's.

How do I handle an outbound API call that timed out?

Do not retry blindly if the call creates something consequential, such as a signature request. Record the operation in a ledger with a tenant-scoped ID and an immutable payload hash, then query the provider's authoritative state to learn whether the request exists. Resend only when evidence shows it does not, or when a documented provider idempotency mechanism makes resending safe.

Are envelope IDs and document IDs sensitive?

They can be. Identifiers that can be linked to a person, a customer, or a contract may count as personal or confidential data depending on your context and applicable law. Treat them as internal identifiers with access control. The default-safe values for logs and alerts are event ID, tenant, state, and payload hash.

Does a vendor's SOC 2 or ISO 27001 certification cover my webhook pipeline?

No. A vendor's attestation addresses the vendor's own systems and controls within its stated scope. Your receiver, queue, logging, alerts, and replay tooling are your responsibility. Use vendor reports as diligence inputs, and review your own pipeline against your legal and security requirements.

How long should I keep quarantined webhook payloads?

There is no universal number. Retention should come from your privacy and legal owners, balancing data minimization against evidence needs and any regulated-record obligations. Set it explicitly per lane, keep it longer than the source queue's retention, and document who can approve exceptions or legal holds.

Build the integration you can defend after a bad night.

Webhook failures are inevitable. Lost evidence, stale replays, and leaked signer data are not. Explore eSignly's API, security, and integration documentation, then pressure-test your design with real events.

Create a free account and run your first API signing flow.

Free Trial
Related solution

This article is most relevant for CTOs and developers who need to roll out a practical signing workflow. Use the related eSignly path to compare plans, API options, compliance fit, and implementation next steps.

Explore related solutionCompare plans
Editorial review

Reviewed for electronic signature decision makers

This guide is reviewed for clarity, legal and operational relevance, service alignment, and practical conversion path before being connected to an eSignly plan or API workflow.

Reviewed byeSignly content, product, and conversion review team
Reviewed2026-10-19
FocusResource Esignature Api Guide

For regulated, high-volume, or customer-facing workflows, validate legal duties, plan assumptions, and integration requirements with your internal stakeholders before rollout.