Skip to main content
This guide explains how to reconcile transactions between your internal systems and the Grid API using two complementary mechanisms: real-time webhooks and periodic queries.
Use webhooks for real-time updates and daily queries as a backstop to detect missed events or data drift.

Handling webhooks

Listen for transaction webhooks and apply every status change to your records as it arrives.
A transaction’s status reports where the funds are now, and it can change after settlement. A bank return moves COMPLETED → FAILED and destination.railDetails.status to RETURNED; a dishonored return moves it back to COMPLETED. Only EXPIRED is terminal. Also listen for OUTGOING_PAYMENT.REFUND_COMPLETED and OUTGOING_PAYMENT.REFUND_FAILED to track refunds on failed transactions.
  • Outbound transactions: The originating account is debited at transaction creation. If the transaction ultimately fails, a refund is posted back to the originating account.
  • Inbound transactions: The receiving account is credited only on success. A failure before the credit does not change balances. A return after COMPLETED does: the credited funds are debited back when INCOMING_PAYMENT.FAILED arrives with source.railDetails.status RETURNED.
Grid retries failed webhooks up to 160 times over 7 days with exponential backoff. Use the dashboard to review and remediate webhook delivery issues.
1

Subscribe and verify signatures

Configure your webhook endpoint and verify signatures. See Webhooks.Sample webhook payload:
When funds move over an external rail, that source / destination object may include a railDetails describing the transfer. It is present for US bank rails and on-chain transfers today. Its paymentRail determines the fields: an ONCHAIN transfer carries transactionHash + network (e.g. SOLANA) to match on a block explorer, an ACH transfer carries its traceNumber, a WIRE carries its imad, and RTP / FEDNOW transfers carry their endToEndId. Rail identifiers can land shortly after the status changes, so the webhook payload may not include them yet; retrieve the transaction (GET /transactions/{id}) to read them once settled.
2

Process events idempotently

Use the envelope id, data.id, and timestamp to ensure idempotent handling, updating your internal ledger on each status transition.
3

Keep settled transactions open to late events

Treat COMPLETED and FAILED as settled, not final. An ACH entry can be returned for up to 60 days after it settles, and a return can be dishonored later still. Keep applying every webhook for a transaction, whenever it arrives, and adjust your records when its status changes. Use the daily query below to catch any event your endpoint missed.

Reconcile via queries

Additionally, you can list transactions for a time window and compare with your internal records.
We recommend querying days from 00:00:00.000 to 23:59:59.999 in your preferred timezone.
cURL
Response

Troubleshooting

  • Missing webhook: Check delivery logs in the dashboard and ensure your endpoint returns 2xx. Retries continue for 7 days.
  • Mismatched balances: Re-query the date range and compare each transaction’s current status to your records. Outbound failures are refunded. An inbound failure before the credit changes no balance; an inbound return after COMPLETED debits the credited funds back, and a dishonored return (railDetails.status RETURN_DISHONORED) credits them again.
  • Pagination gaps: Always follow nextCursor until hasMore is false.