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

# Webhook Event Log & Manual Resend

> How to inspect webhook delivery in the Merchant Portal: what counts as a successful delivery, why a record can be missing entirely, which Order ID each event shows, and how manual resend interacts with automatic retries.

The **Webhooks** page in the Merchant Portal records every webhook Waffo sent
you and lets you resend failed ones yourself. The callback contract itself lives
in [Webhook overview](/docs/en/developer-docs/webhook/overview) and [Webhook retries](/docs/en/developer-docs/webhook/retry);
URL setup lives in [Portal Self-Service Security Configuration](/docs/en/support/portal-security-config-faq).

## How do I check whether a specific webhook was delivered?

Open **Merchant Portal → Webhooks** and filter by event type, status
(`SUCCESS` / `FAILED`), Order ID, or time range. Each record carries:

| Field | What it tells you |
| - | - |
| Event type | Which event was pushed (payment, refund, chargeback, subscription). |
| Status | `SUCCESS` or `FAILED`, derived from your HTTP response. |
| Order ID | The business identifier of the event — see the table further down. |
| Notify URL | The callback URL actually used for this attempt. |
| Triggered at | When the delivery record was created. |
| Next retry | When the next automatic retry is scheduled. It is populated **only** while a record has failed *and* still has retry budget left — so it is empty both for a delivered record and for one whose retries are exhausted. |
| Request body | The full payload Waffo sent, in the detail view. |
| HTTP response | The failure summary your endpoint returned (failed records only). |

The log starts from the point the feature went live; older notifications are not backfilled.

## I just triggered a notification and it is not in the list. Is it lost?

Probably not. A notification still being sent sits in an in-flight state the
list **does not return by default**, so a record can take a few seconds to
appear — deliberately, so an in-flight attempt is never shown as `FAILED`.

## My server returned HTTP 200, so why does Waffo show FAILED?

HTTP 200 alone is not enough. A delivery counts as `SUCCESS` only when your
endpoint returns **HTTP 200 *and* a response body of `{"message":"success"}`**.
Every other outcome — HTTP 200 with a different or empty body, `failed`,
`unknown`, a timeout, an unparseable response — is `FAILED`.

## Can I resend a failed webhook myself?

Yes, in three modes:

| Mode | Use it when |
| - | - |
| Single | You are re-driving one known event. |
| Multi-select | You picked several failed records from the list. |
| By time range | Your endpoint was down for a period and you want to replay the failures in that window. |

A single request resends **at most 50 records**. In time-range mode you can
estimate the window's failed-record count first, then narrow it if it exceeds the limit.

## Does a manual resend go back into the automatic retry queue?

**Yes — and this is the point most easily missed.** A manual resend runs through
the same delivery path as an automatic one: it counts as an attempt against the
record's retry budget, and if it fails, the next automatic retry is rescheduled
as long as budget remains. The next retry time is only cleared once the budget
is exhausted.

The consequence: **a manual resend against a still-broken endpoint spends one of
your remaining attempts.** Verify or fix your endpoint first, then resend. Once
the budget is exhausted the record stays `FAILED` with no next retry time, and
recovering it is your side's job — read it back with
[Order Inquiry](/docs/api-reference/introduction)
rather than waiting for another delivery.

## Why is Resend greyed out on some records?

There are exactly three reasons a record cannot be resent: it has **no callback
URL** stored (there is nothing to send to), it is **still in its first delivery**
(an in-flight attempt is not resendable), or the record does **not belong to your
merchant ID**.

A record that already delivered successfully is **not** in that list — a
successful record *can* be resent, deliberately, because a delivery Waffo
recorded as accepted may still not have been processed on your side.

Resend also requires the webhook-resend permission on your Portal role. Without
it the action and the row selection are not rendered at all rather than shown
disabled, so an operator who sees no resend control anywhere is looking at a
permissions question, not an eligibility question — ask your Portal Admin.

## The Webhooks page has no record at all for one of my transactions

An empty result almost always means **no notification URL was resolved** — not
that delivery failed. With no URL, Waffo sends nothing and writes no log record.
Check where that event type takes its URL from:

| Event | URL source |
| - | - |
| Payment | The `notifyUrl` passed when the order was created. |
| Refund | `refundNotifyUrl` on the refund request takes priority; if empty, the Refund Notify URL configured in the Portal is used and stored on that refund order. |
| Chargeback | Only the Chargeback Notify URL configured in the Portal — it cannot be passed per request. |
| Subscription | The `notifyUrl` held on the subscription object itself. |

A missing chargeback record therefore usually means the Chargeback Notify URL
was never configured; a missing refund record means neither the request
parameter nor the Portal setting was present.

## Which Order ID does the log show, and why can't I find a chargeback by my original order number?

The Order ID column is the event's own identifier, and it differs per event:

| Event | Order ID in the log |
| - | - |
| Payment | `acquiringOrderId` |
| Refund | `acquiringRefundOrderId` |
| Subscription status / period change | `subscriptionId` |
| Chargeback | The dispute reference of the chargeback case |

Chargeback records are listed and searched by the dispute reference, **not** the
original payment order — searching a chargeback notification by your original
order number returns nothing. That number travels as `originalOrderId` inside
the payload, so read it from the request body in the record's detail view.


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