Aller au contenu principal

New: the Landed Cost API quotes duties and taxes at checkout in 40 markets. About the Landed Cost API

International OrdersInternational Orders

Webhooks

Webhooks

Receive events when orders, payments, refunds and payouts change, verify signatures, and handle retries safely.

Webhooks tell your server when something happens in your account: an order is paid, a refund succeeds, a payout fails. Use them to fulfil orders and update your records. Don't rely on browser redirects, which shoppers can close.

This is preview documentation for a prototype. Endpoints, fields and keys are illustrative.

Register an endpoint

Add an endpoint in the dashboard under Developers → Webhooks, or with the API:

curl https://api.international-orders.com/v1/webhook_endpoints \
  -u sk_test_51Hx...: \
  -d url="https://example.com/webhooks/io" \
  -d "events[]=order.paid" \
  -d "events[]=refund.succeeded" \
  -d "events[]=payout.failed"

The response includes a signing secret starting with whsec_. Store it with your other secrets.

The event object

Every event has the same shape. The changed object is in data.object.

{
  "id": "evt_1Nb7cY4fH8qA",
  "type": "order.paid",
  "created": "2026-10-01T09:14:22Z",
  "livemode": false,
  "data": {
    "object": {
      "id": "ord_7Hc2kQ9xL4mP",
      "object": "order",
      "status": "paid",
      "amount": 12900,
      "currency": "EUR"
    }
  }
}

Common events

EventWhen it's sent
order.paidThe order's payment is captured. Fulfil now
order.cancelledThe order was cancelled
payment.authorizedFunds are held (manual capture)
payment.failedA payment attempt failed
refund.succeededThe network confirmed a refund
dispute.openedA shopper disputed a payment
payout.paidA payout reached the bank
payout.failedA payout was rejected

Browse every event and its payload in the webhook explorer.

Verify signatures

Each request carries an IO-Signature header with a timestamp and an HMAC-SHA256 signature of the raw body. Verify it before you trust the event.

import { InternationalOrders } from "@international-orders/node";

const io = new InternationalOrders(process.env.IO_SECRET_KEY!);

export async function POST(req: Request) {
  const body = await req.text();
  const signature = req.headers.get("io-signature") ?? "";

  let event;
  try {
    event = io.webhooks.verify(body, signature, process.env.IO_WEBHOOK_SECRET!);
  } catch {
    return new Response("Invalid signature", { status: 400 });
  }

  if (event.type === "order.paid") {
    await fulfil(event.data.object.id);
  }
  return new Response(null, { status: 200 });
}

Use the raw request body. Parsing and re-serialising JSON changes the bytes and breaks the signature. The SDK also rejects events more than five minutes old, which protects against replays.

Retries

Respond with a 2xx status within 10 seconds. Anything else counts as a failure, and we retry with exponential backoff for up to three days.

AttemptDelay after previous
21 minute
310 minutes
41 hour
5 onwardsEvery 6 hours, until 3 days have passed

If an endpoint keeps failing, we email you and eventually disable it.

Handle events safely

  • Return quickly. Acknowledge the event, then do slow work in a background job.
  • Expect duplicates. Retries can deliver the same event twice. Store evt_ IDs you've processed and skip repeats.
  • Don't assume order. Events can arrive out of sequence. If you need the latest state, retrieve the object from the API.
  • Filter. Subscribe only to the events you use.

Test locally

Send a test event to any endpoint from the dashboard, or forward events to your machine with the CLI:

io listen --forward-to localhost:3000/webhooks/io
io trigger order.paid

Next steps