> ## Documentation Index
> Fetch the complete documentation index at: https://developers.usezend.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Verifying payments

> Credit orders on Zend's signed webhook, not on the browser promise.

Your page can be edited by its user. A resolved `pay()` promise only tells your UI what happened; it doesn't prove anything to your server.

## The flow

**1. Your page asks**

Your page calls `pay`, `request` or `createLink` with a `reference`, such as your order ID.

**2. Zend records it**

Zend records the payment from its own records. For `pay`, it checks the payer, recipient and amount against what your app asked for.

**3. Zend tells your server**

Zend sends a signed `payment.completed` (or `link.claimed`) webhook with your `reference`.

**4. Your server credits**

Your server verifies the signature, dedupes on the event `id`, and credits the order.

```ts theme={null}
import { verifyWebhook } from "@zendfi/appkit/server";

app.post("/zend/webhook", express.text({ type: "*/*" }), async (req, res) => {
  if (!verifyWebhook(req.body, req.header("x-zend-signature") ?? "", process.env.ZEND_WEBHOOK_SECRET!)) {
    return res.sendStatus(401);
  }
  const event = JSON.parse(req.body);
  if (await alreadyHandled(event.id)) return res.sendStatus(200);

  if (event.type === "payment.completed") {
    await creditOrder(event.data.reference, event.data.amount_usd, event.data.from);
  }
  res.sendStatus(200);
});
```

## Look up a payment

If you need to check a reference directly, for example when a user says they paid:

```bash theme={null}
curl "https://api.usezend.app/api/zend/v2/apps/server/payments?reference=article_7" \
  -H "Authorization: Bearer $ZEND_APP_KEY"
```

```json theme={null}
{
  "payments": [
    {
      "payment_id": "…",
      "from": "zu_...",
      "to": "zu_...",
      "amount_usd": 1.32,
      "reference": "article_7",
      "created_at": "2026-11-02T10:00:00Z"
    }
  ]
}
```

Returns up to 50 payments for that reference, newest first.

## Catching up after downtime

Deliveries retry for about a day. If your server was down longer, `GET /apps/server/events` returns the last 100 events with `delivered_at`. See [Webhooks](https://developers.usezend.app/reference/webhooks.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.