Get Payment Notifications
Track payments as they happen — query settled intents on demand or register a webhook that fires the moment money moves.
Once payments start flowing through your wallets, you need to know when money arrives. Traditional payment systems scatter this information across batch files, polling endpoints, and network-specific notification formats — each with its own schedule, its own format, and its own failure modes.
The ledger gives you two ways to track payments, and you can use both together:
| Approach | How it works | Best for |
|---|---|---|
| Query intents | Pull — you ask the ledger for recent payments on demand | Dashboards, reconciliation checks, on-demand reporting |
| Register an effect | Push — the ledger calls your server the moment a payment settles | Real-time notifications, POS confirmations, automated workflows |
This guide walks you through both, building on the store wallet from Create a Wallet.
Approach 1: Query intents
The simplest way to check for payments — ask the ledger what happened. Every payment is an intent, and the ledger keeps a complete, queryable record of every intent that has touched your wallets.
List intents for a wallet
Query all intents where your wallet received funds:
curl "https://{ledger-host}/v2/intents?filter[data.claims.target.handle]=store1@greatcoffee.co" \
-H "Authorization: Bearer {your-token}" \
-H "x-ledger: {your-ledger}"This returns every intent where store1@greatcoffee.co was the target — every payment the store received. The response includes the amount, currency, source, and status for each intent.
The response is paginated. By default, the ledger returns the most recent intents first. Use the limit and offset query parameters to page through large result sets — for example, ?limit=50&offset=100 returns intents 101 through 150.
Filter by status
You usually care about completed payments — the ones that actually settled:
curl "https://{ledger-host}/v2/intents?filter[data.claims.target.handle]=store1@greatcoffee.co&filter[meta.status]=completed" \
-H "Authorization: Bearer {your-token}" \
-H "x-ledger: {your-ledger}"Each intent includes its unique handle (the idempotency key set by the sender), the claims with source, target, amount, and currency, and the status confirming settlement.
Available filters
The intents endpoint supports filtering on any combination of these fields:
| Filter | What it matches | Example value |
|---|---|---|
data.claims.target.handle | Receiving wallet | store1@greatcoffee.co |
data.claims.source.handle | Sending wallet | svgs:98765432@otherbank.co |
data.claims.symbol.handle | Currency | cop, usd |
data.claims.action | Movement type | transfer, issue, destroy |
meta.status | Intent lifecycle state | completed, rejected, pending |
meta.domain | Institution domain | greatcoffee.co |
This approach is ideal for building dashboards, running reconciliation checks, or generating end-of-day reports.
Approach 2: Register an effect
Querying works for on-demand checks, but if you need to react the moment a payment lands — update a POS screen, send a receipt, trigger a downstream process — you want the ledger to call you. That's what an effect does.
An effect is a subscription: you tell the ledger which event to watch for and where to send the notification. The ledger handles delivery, retries, and ordering.
Create a webhook effect
Register an effect that calls your server whenever store1@greatcoffee.co receives a payment:
curl -X POST "https://{ledger-host}/v2/effects" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {your-token}" \
-H "x-ledger: {your-ledger}" \
-d '{
"data": {
"handle": "greatcoffee-payment-received",
"signal": "balance-received",
"filter": {
"wallet.data.handle": "store1@greatcoffee.co"
},
"action": {
"schema": "webhook",
"endpoint": "https://greatcoffee.co/api/webhooks/payment-received"
}
}
}'Three fields define the subscription:
| Field | What it does |
|---|---|
| signal | The event type to watch — balance-received fires every time a wallet is credited |
| filter | Narrows the signal to a specific wallet, currency, or domain |
| action | Where to send the notification — webhook sends an HTTP POST to your endpoint |
Once registered, every payment that settles to store1@greatcoffee.co triggers a POST to your endpoint automatically.
Handle the webhook call
The ledger sends a POST request with the full event payload — the wallet that was credited, the currency, the intent that triggered the credit, and the amount:
// Your server — Express, Fastify, or any HTTP framework
app.post('/api/webhooks/payment-received', async (req, res) => {
// Acknowledge immediately — the ledger retries if it doesn't get a 2xx
res.status(202).send()
const event = req.body
const { signal, wallet, symbol, intent, amount } = event.data
// Check idempotency — the handle uniquely identifies this event
if (await isAlreadyProcessed(event.data.handle)) return
console.log(`Received ${amount} ${symbol.data.handle} on ${wallet.data.handle}`)
console.log(`Intent: ${intent.data.handle}`)
// Your business logic — update POS, send receipt, trigger payout
await processPayment(event)
})Webhook security
In production, verify that webhook calls originate from the ledger before processing them. The ledger signs every webhook payload — validate the signature against the ledger's public key before trusting the event data. See Bridge Authentication for details on signature verification.
Three things matter in this handler:
Acknowledge first, process later. Return a 202 immediately. The ledger considers any non-2xx response or network timeout a failed delivery and retries with exponential backoff — starting at 1 second, increasing by 20% each attempt, up to a maximum interval of 1 hour.
Use the event handle for idempotency. Network retries can deliver the same event more than once. The event.data.handle is a unique identifier — check it before processing to avoid duplicate side effects.
The payment is already settled. The ledger fires the effect after the credit commits. By the time your server receives the call, the funds are already in the wallet — there is no window where the notification arrives but the balance hasn't settled.
Verify the effect is registered
curl "https://{ledger-host}/v2/effects/greatcoffee-payment-received" \
-H "Authorization: Bearer {your-token}" \
-H "x-ledger: {your-ledger}"Built-in reliability
Effects aren't fire-and-forget. The ledger guarantees delivery with automatic retries:
| Scenario | What the ledger does |
|---|---|
| Your endpoint returns a 2xx | Delivery confirmed — moves on |
| Your endpoint returns a non-2xx error | Retries with exponential backoff (1s → 1.2s → 1.44s... up to 1 hour max) |
| Your endpoint is unreachable | Same retry behavior — keeps trying |
Your endpoint returns 501 Not Implemented | Stops retrying — treats as permanent rejection |
If your server is down for maintenance, the ledger queues events and delivers them when your endpoint comes back. No need for a separate dead-letter queue or reconciliation process for missed notifications.
End-to-end flow
With both approaches set up, here is the complete flow when a customer pays the store:
The effect gives you the real-time notification. The intent query gives you the on-demand audit trail. Together they cover both the "something just happened" and the "show me everything that happened" use cases.
What you learned
- How to query intents by wallet, status, and currency using filters
- How to register a webhook effect that fires when a wallet receives a payment
- How to handle webhook calls with idempotency and immediate acknowledgment
- How the ledger guarantees delivery with automatic retries
Next steps
- About Intents — how the two-phase commit protocol guarantees every payment is atomic
- About Anchors — how simple identifiers like QR codes and phone numbers resolve to wallets
- Get Notifications — advanced effect configuration including bridge effects and additional signals
Collect a Payment
Generate a QR code at checkout and start receiving payments from any connected network — one API call to create the code, one scan to collect the money.
About Minka
What Minka is, how the distributed ledger works, and why Latin America's financial infrastructure is being rebuilt on it.