---
title: "Reconciliation"
description: "Combine webhooks and polling to credit deposits exactly once and recover safely."
canonical_url: "https://checkout.verify.et/docs/reconciliation"
markdown_url: "https://checkout.verify.et/docs/reconciliation.md"
last_updated: "2026-10-06"
x_farming_labs_generated_preamble: true
---

# Reconciliation
URL: /docs/reconciliation
LLM index: /llms.txt
Description: Combine webhooks and polling to credit deposits exactly once and recover safely.
Related: /docs/webhooks, /docs/integration, /docs/troubleshooting

# Turn outcomes into one ledger entry

Use webhooks for low-latency notification and the deposit API as the current source
of truth. A scheduled poller closes gaps caused by downtime or exhausted retries.

| Path | Best use | Required protection |
| --- | --- | --- |
| Webhook | Prompt processing | Signature verification and event deduplication |
| `GET /v1/deposits/{id}` | Current state lookup | API authentication and rate-aware retry |
| `GET /v1/deposits` | Periodic sweep | Cursor/checkpoint and bounded time windows |
| `GET /v1/deposits/{id}/events` | Investigation | Treat as history, not a second credit trigger |

## Credit exactly once

Use the Verify Checkout deposit ID as a unique ledger key inside the same database
transaction that credits your customer.

```ts
await database.transaction(async (transaction) => {
  const inserted = await transaction.creditEvents.insertIfAbsent({
    externalId: deposit.id,
    amount: deposit.amount,
    currency: deposit.currency,
  });

  if (inserted) await transaction.wallets.credit(deposit.merchant_customer_id, deposit.amount);
});
```

`succeeded` is the crediting outcome. Failed and expired deposits must not be
credited. Hold review outcomes for operational resolution. For any unfamiliar or
non-terminal state, store it and wait rather than assuming success.

## Recovery loop

1. Verify and durably enqueue each webhook before returning `2xx`.
2. Deduplicate by event ID and apply ledger changes by unique deposit ID.
3. Retrieve the deposit before acting when events arrive out of order.
4. Periodically list unresolved deposits and poll their current state.
5. Use the event timeline and `meta.requestId` to investigate discrepancies.

<Callout type="info" title="Retries are normal">
  At-least-once delivery means repeated events are expected, not exceptional.
  Correctness comes from idempotent storage, not from assuming one delivery.
</Callout>

## Sitemap

Sitemap discovery is not enabled for this deployment.
