raindrop_redemption.completed once a booking is confirmed. What you build depends on where your points balances live: Onchain, where you are the source of truth and Rain calls you for balances and burns, or Offchain, where Rain keeps the canonical ledger and you mostly fulfill the booking. This page walks through the flow for both modes and the code recipes that go with each. For shared reference such as status values, API endpoints, and billing, see Travel Redemptions.
Partner-Managed programs skip the Rain-Managed user authorization step. A fresh balance check (webhook for onchain, DB for offchain) is the pre-commit gate before a booking, and there is no
raindrop_redemption.created webhook for partner-managed travel redemptions.Launch the travel portal
Both modes open the travel portal the same way Rain-Managed programs do: in a webview, with an encrypted session token (a JWE) that identifies the cardholder. The token recipe is identical across modes—see Launch the travel portal on the Rain-Managed page.Rain signs every webhook below with an HMAC SHA256 signature in the
Signature header, computed over the exact JSON body using your API key as the secret. Verify it before processing (see How Webhooks Work). Some tenants also receive a version field on redemption webhooks; treat it as optional and ignore any fields you don’t recognize.Partner-Managed Onchain

Partner Managed (onchain) travel redemption flow
Balance check
Rain sends a synchronousraindrop_balance.requested webhook whenever the travel portal needs to display or verify a balance. Respond within 1500ms with the cardholder’s spendable balance—confirmed points minus any you’ve already reserved for in-flight redemptions, so the portal can’t double-spend.
Request payload:
body.id is the cardholder’s Rain user ID.
Your response:
availableBalance must be a non-negative integer string of whole points. If your endpoint times out, returns non-2xx, or returns a malformed response, Rain returns 503 to the travel portal.
Booking completion
When a booking is confirmed, Rain firesraindrop_redemption.completed. Acknowledge it immediately, then burn the points in your system out of band. raindropAmount is in whole points—scale it to your token’s native units before burning.
Refund
When a booking is canceled, Rain firesraindrop_redemption.refunded so you re-credit the points. The payload carries no amount, so look up how many points you debited by body.id (the redemption ID from the completion webhook).
Webhook listener
A single endpoint handles all three. The balance check responds synchronously; the completion and refund handlers acknowledge first and process out of band.partnerOnchainWebhookListener.ts
Test in sandbox
If your travel portal is not connected yet, stand in for it by calling the travel redemption endpoints yourself in sandbox. Use anAdmin key or a custom key with raindrops-travel:read and raindrops-travel:write. Each call triggers the webhooks your listener handles, with the payloads shown in Balance check, Booking completion, and Refund.
- Check the balance. Call
GET /issuing/raindrops/travel-redemptions/balance?userId=<id>. Rain sendsraindrop_balance.requestedto your endpoint synchronously and waits up to 1500ms. Rain returns youravailableBalanceasavailablePoints. - Create a booking. Call
POST /issuing/raindrops/travel-redemptionswithuserId,amountin whole points, abookingIdthat starts withsim_,bookingType,totalBookingAmountCents, andbookingDescription. Rain sendsraindrop_balance.requestedagain as a pre-check. If the user has too few points, the call returns400. If your endpoint does not answer, the call returns503. Otherwise, Rain skips the travel provider confirmation, marks the redemptionCOMPLETED, returns200, and sendsraindrop_redemption.completed. Debit the user when the webhook arrives. - Refund the booking. Call
POST /issuing/raindrops/travel-redemptions/{redemptionId}/refund. Rain marks the redemptionREFUNDED, returns200, and sendsraindrop_redemption.refunded. The payload has no amount, so re-credit the user by redemption ID.
totalBookingAmountCents, plus any redemption premium, on your next sandbox tenant report. A refund reverses the charge.
Once the travel portal is connected, it makes the same calls with real booking IDs. Rain confirms each booking with the travel provider before completing it. Your webhook handlers do not change.
Partner-Managed Offchain

Partner Managed (offchain) travel redemption flow
raindrop_redemption.completed, and it is informational—Rain has already debited the points by the time it fires. Use it to record the booking or trigger fulfillment in your own system.
partnerOffchainWebhookListener.ts
raindrop_redemption.completed.
To debit offchain points for a statement credit, use the statement-credit endpoint.
Webhook summary
For onchain partners,
raindrop_redemption.completed signals that you should debit or burn points in your system. For offchain partners, Rain has already debited the DB, so the webhook is informational.
Refunds
After the travel portal receives notice from the supplier (for example, a hotel or airline) that a booking was canceled and must be refunded, it sends Rain a message. Rain then re-issues the burned points to the cardholder and marks the redemptionREFUNDED. How the restored points settle depends on the mode: