POST request. This page explains how events move through their lifecycle, how to respond, the retry and delivery guarantees, how to handle out-of-order delivery, and how Rain versions payloads. To register an endpoint and verify signatures first, see Set up webhooks.
At a high level, every event follows the same delivery path from Rain to your endpoint.
Signed request Rain POSTsDelivered (2xx)Rain builds the eventDecision / no-op
Webhook lifecycle
Most events follow a lifecycle as the underlying resource moves through its states. A spend transaction, for example, can move fromrequested to created, then updated, and finally completed. Not every event passes through every stage, and some events fire only once.
Each webhook payload shares the same envelope:
Respond to webhooks
Acknowledge each webhook quickly and keep your response lightweight:- Return a JSON response with a
200status code to acknowledge successful receipt - Process heavy work asynchronously after you acknowledge, so slow handlers don’t trigger timeouts and retries
- Include relevant information in your response if you need to communicate back to Rain (for example, rejection codes for authorization webhooks)
- Avoid returning HTML error pages or plain text responses. If you do, Rain truncates and stores them, like this:
Synchronous events
Three events are synchronous: Rain waits for your response before completing the action. Respond within the timeout shown below.Retry behavior and delivery guarantees
Rain automatically retries failed webhook deliveries. A delivery is considered failed if your endpoint does not return a2xx status code, times out, or is unreachable. Because Rain retries, your endpoint may receive the same event more than once, and events may arrive out of order. Design your handler to be idempotent and to tolerate out-of-order delivery (see Handle event ordering).
How retries work
This schedule applies to asynchronous events only. When a delivery fails, Rain retries 15 times with exponential backoff for up to one week. Rain starts with a 2.5s delay for the first retry, and backs off with a coefficient of 3 (so the next retry is 7.5s, then 22.5s, and so on). Rain caps it at a day between retries. Synchronous events are never retried. Iftransaction.requested, challenge.requested, or raindrop_balance.requested times out, the authorization or challenge it belongs to fails. There is no second delivery to catch, so a missed authorization decision is final.
Idempotency
Webhooks may be delivered multiple times, so your handler should be idempotent. Each webhook payload includes a uniqueid field that you can use to detect duplicates. Store processed webhook IDs and check for duplicates before processing.
Handle event ordering
Rain webhooks may arrive at your endpoint out of chronological order due to network delays, retries, or processing variations. TheeventReceivedAt field in webhook payloads indicates when the underlying event was received by Rain’s system, so you can determine the true chronological order of events even if webhooks arrive out of sequence.
Understand eventReceivedAt
eventReceivedAt is an optional ISO-8601 timestamp field (format: YYYY-MM-DDTHH:mm:ss.sssZ) that indicates when Rain first received the underlying event that triggered the webhook.
Best practices for ordering
Check foreventReceivedAt: The field is optional and may not be present in all webhooks. Always check for its presence before using it.
Use UTC timezone: eventReceivedAt is always in UTC (indicated by the Z suffix). Ensure your parsing and comparison logic uses UTC and doesn’t convert to local time.
Consider a buffer window: For more robust implementations, use a buffer window (for example, 30 to 60 seconds) before processing webhooks to account for late arrivals.
Availability
Fortransaction.requested, transaction.created, transaction.updated,
transaction.completed, user.updated, and company.updated,
eventReceivedAt is opt-in and excluded by default. Contact your Rain
account manager to enable it for your tenant.
Some other events, such as
raindrop_balance.requested,
dispute.chargebackCreated, and transactionReward.created, show
eventReceivedAt in their example payloads without this opt-in step.
Confirm with your Rain account manager which of your subscribed events
include the field by default versus which require enabling it.Versioning
Each webhook payload is versioned. Theversion field in the envelope reflects the schema version of that event’s body. Rain adds fields in a backward-compatible way, so new optional fields can appear in a payload without a breaking version change.
The version you receive is pinned by your webhook configuration. If you never set a version for an event, Rain sends that event’s default version, which is its earliest — not its latest. To receive fields added in later versions, set the version for that event with the webhook configuration endpoints. Requesting a version that doesn’t exist falls back to the default rather than failing.
For the change history of each event, review the changelog entries for that event, which record what changed in each version. Check them before you rely on a recently added field, and treat any field documented as optional as one that may be absent from a given payload.
What’s next
Set up webhooks
Register your endpoint, choose a signing key, and verify signatures.
Transaction events
See the payloads, fields, and triggers for spend, collateral, payment, and transfer events.