Synthetic Industry

Troubleshooting guide · updated 2026-10-11

PayPal webhooks can repeat and arrive late: make the ledger update safe to repeat

Use PayPal's delivery contract to design an event inbox with a unique event id, raw-body verification, held dependent events and a report-based safety net.

The delivery contract

PayPal requires a listener to return a 2xx status for every delivery. If it gets no response, cannot connect or receives an error, it retries each delivery up to 25 times over three days. That single rule explains most surprises: a slow handler that times out is retried even though it did its work, and a handler that crashed before recording anything may be retried hours later. The listener must be reachable over HTTPS, and its signature check depends on details that are easy to break.

Verification needs the raw body and the right webhook id

PayPal offers a self-verification method that builds a string from the transmission id, the time stamp, your webhook id and a CRC32 of the body, or a postback of the event to PayPal's verification endpoint. PayPal says the CRC32 must be computed from the original raw body; the general rule is in the guide "Verify a webhook signature on the exact bytes you received, not the data you parsed". The PayPal-specific points are that the webhook id, issued when you register the listener, appears in neither the headers nor the body, and that events created with the simulator do not belong to an app, use a placeholder id and cannot be verified by postback, so a failing check on a simulator event says nothing about your live listener.

  • Do not disable verification to make deliveries pass.
  • Keep the webhook id in configuration, not in logs or shared notes.

Assume repeats and late events

PayPal's invoicing webhook documentation says delivery is at least once, so the same event can arrive repeatedly, and that events can arrive out of order; it advises querying current status rather than trusting arrival order and using the event id as a deduplication key recorded in the same database transaction as the business update. That page covers invoicing events; we found no PayPal page promising an ordering guarantee for payment events, so the same defensive approach is the prudent one for sales and refunds.

The general pattern for repeats, an inbox with a unique event id and a quick acknowledgement, is in the guide "The same webhook arrives twice and runs twice? Acknowledge fast and make a repeat do nothing". The PayPal-specific additions are to key ledger entries by the capture or refund identifier as well, and to hold an event whose parent, such as the sale for a refund, is not yet recorded.

A report-based safety net

Webhooks can be missed, for example after a long outage or a disabled endpoint. A periodic comparison against PayPal's transaction report catches what never arrived; the related guide on report windows explains its limits. Treat the report as a check and a replay source, not a second writer that can create the same entries again.

  • Compare counts per day between inbox and report.
  • Replay only events whose identifiers are absent from the inbox.

What fits, what does not, and how it is accepted

The job "Make PayPal refunds and fees appear in the ledger once each, linked to their sale" (from £445, an untested published price) includes event handling that records each event id once and holds dependent events. It is accepted when delivering the same refund event twice or replaying a month adds no entry and an early refund is held then posted after its sale.

It does not decide your accounting treatment or cover disputes. Your own developer can follow this guide without us. It is written from vendor documentation read on 11 October 2026 and nothing was run against a live account. Send invented examples and counts first, never credentials, bank details, invoices or customer records; real records are handled only after written agreement through a secure handoff.

Sources and limits

  • PayPal: integrate webhooks Checked 2026-10-11.
    • A listener must return a 2xx status; failed deliveries are retried up to 25 times over 3 days.
    • Signature verification needs the original raw body (CRC32 of the unparsed body) and the webhook ID, which is not included in the headers or body.
    • Simulator events do not belong to an app and cannot be verified by postback.
  • PayPal: invoicing webhooks Checked 2026-10-11.
    • For invoicing webhooks PayPal says delivery is at least once, so events can repeat, and events can arrive out of order, so a handler should query current status rather than rely on arrival order.
    • PayPal recommends using the event id as the deduplication key, recorded in the same database transaction as the business update.
  • PayPal: Transaction Search API Checked 2026-10-11.
    • The list transactions call supports a maximum date range of 31 days, requires an end date, and can take up to three hours for executed transactions to appear.
    • Page size defaults to 100 and can be up to 500, and the call covers the previous three years.
    • Each transaction carries an event code, an amount and a fee amount.
    • A transaction identifier is not unique in the reporting data: the response can list two records with the same identifier, one affecting the balance and one not.