Skip to main content
Sent when funds move between your platform’s balance and an account’s, in either direction. Use it to confirm a split payment share reached its recipient. The account is the event’s origin in both directions, so a platform on event_source connect and the account on account both receive it, whichever side created the transfer. The default for a new endpoint is account, its own events only, so a platform that never sets event_source receives nothing about transfers on the accounts it owns. See Connect events.

Event fields

string
The event’s unique identifier, prefixed evt_. Use it to deduplicate deliveries.
string
Always transfer.created.
string
When the event occurred, in UTC.
string
The account the transfer involved. On an event from an account you own, this is that account, not your platform.
string
The origin account’s id, repeated at the top level. Present only when the origin has a parent; absent on your platform’s own events. This is how a platform tells which of its accounts the event concerns.
string
The transfer’s id, prefixed tr_.
string
Whoever was debited. Your platform on a transfer out, the account on a transfer back.
string
Whoever was credited.
string
The amount moved, as a decimal string in data.currency.
string
The currency moved, as an ISO 4217 code. Both balances hold it; a transfer never converts.
string | null
The description set on the transfer.
object
The metadata set on the transfer, returned unchanged.
string
What this movement is. payout is a seller’s share of a sale you made, and manual is a transfer you created yourself. The platform’s own cut of a sale is never a transfer, see Platform fees.
string | null
The charge that funded this movement, prefixed ch_, when one did. Null on a transfer you created yourself, which is tied to no charge.
string | null
When the transfer was created, in UTC.

When it fires

transfer.created fires once, at creation, for every transfer: one you create directly on the transfers endpoint, and one written automatically by settlement, an account’s share of a destination charge the platform made. It does not fire again later; a transfer has no further state change to report once it exists.
Order transfers by data.created_at rather than by arrival. Webhook delivery does not guarantee ordering, and for money movement the timestamp is the reliable sequence.

What to do on receipt

Match data.transfer_id (or data.metadata, if you set your own reference there) against the order or payout you expect it to confirm, and mark that share as delivered. Branch on data.kind to tell the two movements apart without fetching anything: record a payout as a seller’s share, and a manual transfer as whatever your own process made it. On a payout, data.source_charge_id names the charge that funded it, so you can tie the movement back to the sale in the same handler. No event fires for the platform’s own cut of a sale: read it from the payment object’s platform_fee, or list it directly at Platform fees.