Webhooks
Subscribing to events, verifying a message came from the shop, handling retries, and what not to assume.
A webhook posts to an address you supply when something happens in the shop. The merchant configures them under Settings, Webhooks, or an app can register its own.

The signing secret is generated for them and is the thing you need in order to verify what arrives. A merchant setting this up for you has to copy it across, so say so explicitly rather than leaving them to wonder which of these fields you meant.
Events
| Event | Fires when |
|---|---|
order.placed |
An order is created |
order.shipped |
Tracking is recorded |
order.refunded |
A refund is issued |
order.cancelled |
An order is cancelled |
customer.registered |
An account is created |
The message carries the detail of the thing that happened, so you do not have to come back and ask.
Verifying a Message
Check the signature before acting on anything.
An endpoint that acts on whatever is posted to it is an endpoint anybody can post to, and the obvious abuse is forging an order.placed to trigger whatever your system does with a new order.
Use HTTPS. A webhook body contains customer names and addresses.
Respond Quickly
Answer 2xx as soon as you have stored the message, and do the work afterwards.
A handler that processes before responding will eventually time out, the delivery will be treated as failed, and you will receive the same event again while still working on it.
Expect Duplicates
A retried delivery can arrive after your first attempt actually succeeded. Treat every handler as something that may run twice for the same event.
Key your processing on the identifier in the message, record what you have handled, and ignore a repeat. This is not a rare edge case: it is what happens every time your endpoint is briefly slow.
Expect Gaps
Deliveries fail permanently. An endpoint that is down for long enough stops being retried, and those events are gone.
A webhook alone is not a reliable record
For anything that matters, run a periodic read of the API as well, covering a window wider than your worst outage. The webhook gives you speed. The poll gives you completeness. Systems that rely on webhooks alone discover the gap during the month-end they cannot reconcile.
Ordering Is Not Guaranteed
Two events about the same order can arrive out of order, because retries put the earlier one behind the later one.
Do not infer state from the sequence of messages. Read the current state from the order itself when the answer matters.
Testing
Point a webhook at a request capture service and place a real order. That shows you the exact message before you write anything to consume it.
Then point it at your own endpoint and place another. Writing a handler against documentation rather than a real message is how a field name gets assumed and the integration fails on the first live order.
A Handler Worth Copying
public function handle(Request $request)
{
// 1. Prove it came from the shop before anything else.
abort_unless($this->signatureValid($request), 401);
// 2. Store it and answer. Never process before responding.
$event = ReceivedEvent::firstOrCreate(
['event_id' => $request->input('id')],
['topic' => $request->input('topic'), 'payload' => $request->all()],
);
// 3. firstOrCreate makes a retry harmless: the second arrival finds
// the first and queues nothing.
if ($event->wasRecentlyCreated) {
dispatch(new ProcessEvent($event));
}
return response()->noContent();
}
Three properties worth having: it verifies first, it answers fast, and a duplicate delivery does no work twice.
Reconciling
For anything financial, run a periodic read as well and compare.
A sensible routine is nightly: read orders for the last few days, compare against what you received by webhook, and process anything missing. The window should be wider than your worst plausible outage, not your typical one.
That is also how you find out your endpoint was down, which otherwise you learn from the merchant.
Order of Events and Current State
Two events about the same order can arrive out of order, because a retried delivery queues behind a later one.
Where the answer matters, read the order from the API rather than inferring it from the sequence of messages. The message tells you something happened. The order tells you what is true now.
What the Merchant Can See

The list shows the events each endpoint is subscribed to, whether it is active, and how many deliveries have been attempted. When you are debugging over the phone with a merchant, that delivery count answers the first question: zero means the subscription is wrong or nothing has happened yet, and a rising count with nothing arriving at your end means the problem is between the shop and you.
When Deliveries Stop
Check whether your endpoint is answering before assuming the shop stopped sending. The usual causes are an expired certificate, a URL that moved, or a handler that started timing out under load.
