Flow of funds
Every ledger line as Stripe holds it. One charge model, separate charges and transfers on behalf of each seller; the accounts and who controls them; the held money that waits under its job; money that moves outside a charge; the order money is drawn back in; the event map by how a charge is held; and the sandbox values that test each path.
services.dev runs Stripe Connect, and every seller is a connected account on it: your brand, each member who sells on their own rail, each door operator and each insurer. This page is the one that names Stripe's objects; every other Money page and every example cites it.
Every charge your brand sells is a separate charge and transfer. The PaymentIntent sits on services.dev's account, on_behalf_of your account, so you are the merchant of record and the buyer's statement names you. It carries its job as its transfer_group and no transfer_data, so nothing moves until the fact. At the fact, one transfer per claimant moves the money, each naming the charge as its source_transaction. Only a fee a member sells on their own rail is a destination charge. services.dev's take is what stays on its own account after every transfer, written as its own ledger entry, never an application fee.
| Line | The Stripe object | Seller of record | Lands on | The way back |
|---|---|---|---|---|
| Your charge | a PaymentIntent on services.dev's account, on_behalf_of your account, transfer_group the job, no transfer_data | you | services.dev's account, untransferred, until its fact | refunded from the hold before the fact; after it, by the draw order |
| Your share | a transfer to your account at the fact, source_transaction the charge: the charge less every other line | — | your account | a reversal of that transfer |
| services.dev's take | what stays on services.dev's account after every transfer, its own le_ entry | — | services.dev | returned pro rata with each refund |
| A member's own charge | a destination charge: on_behalf_of the member, transfer_data to the member, whole | the member | the member's account | the member's own refund; a lost dispute is recovered from you |
| Pay on your rail | a transfer to the member, source_transaction the job's charge | you | the member's account | never reversed |
| Money outside a charge | an account debit, py_, from your account to services.dev, then a transfer onward | you | the member's, the operator's or the insurer's account | never reversed |
| Placement, coverage | a transfer to the operator's or the insurer's account, from the charge or by a debit | you | their account | stands |
| Pass-through | a line of your charge, paid on to the outside system | you | the outside system | its own refund, when it gives one |
| Processing | Stripe's fee on each charge, netted from your share; on a member's charge, recovered from you by a debit | — | Stripe | stays spent on a refund |
| Tax | Stripe Tax on your charge with Brand.tax: 'stripe', automatic_tax.liability your account; a member-rail fee is taxed on the member's own account | you | your account, to remit | refunded with its line |
| A subscription cycle | a Stripe invoice on services.dev's account, on_behalf_of your account, its PaymentIntent held like any charge | you | services.dev's account until the cycle releases | as your charge |
| A payout | a Stripe payout from each account to its bank, on Stripe's timing | — | the bank | a returned payout comes back to that account's balance |
| Your services.dev plan | a Stripe subscription on services.dev's account, billed to you | — | services.dev | — |
npx services.dev jobs flow job_7Hq3 # api.lawyer: a receipt releases two chargesjob_7Hq3 · transfer_group job_7Hq3 · services.dev's account holds each charge, and each seller is a connected account
chg_7Hq3 $174.00 pi_…Hq3 on services.dev's account · on_behalf_of acct_…L4w1, api.lawyer · separate charge, no transfer_data
authorized 2 Nov, captured 9 Nov on the receipt
→ tr_…Hq3 $157.17 less the take on $170.00 to acct_…L4w1, source_transaction ch_…Hq3
$174.00 less coverage $4.00, AI $2.10 and processing $10.73 on both charges
→ tr_…Hq3c $4.00 to the attorneys Pool's insurer, source_transaction ch_…Hq3
chg_7Hq4 $175.00 pi_…Hq4 · destination charge on_behalf_of acct_…7Hq3, the attorney · authorized and captured with chg_7Hq3
→ transfer_data to acct_…7Hq3, whole · no take
take its own entry, le_7Hq3t · what stays on services.dev's account after both transfers
payouts api.lawyer to bank …6789 daily · the attorney on their own schedule, a line per brand| Account | Controlled by | Capabilities | Connected at |
|---|---|---|---|
| Your brand | services.dev: losses.payments: 'application', requirement_collection: 'application', stripe_dashboard.type: 'none' | transfers, and card_payments and us_bank_account_ach_payments for the charges made on its behalf | services.dev payouts connect, in the owner console |
| A member | the same | transfers; card_payments where a Rules row puts their fee on their rail | the last step of /join |
| A door operator, an insurer | the same | transfers | when the door or the cover is listed |
| A buyer's own Stripe account, for a payment proof | the buyer: services.dev's Stripe app, never a connected account | reads customers, invoices, charges, refunds and disputes; writes only the invoice the end step drafts | the order, in the customer portal |
services.dev's account carries every loss first and recovers it from your brand by the draw order, so no loss reaches a member: a member's account is paid by transfers and never debited.
services.dev holds only held dollars waiting for their fact, each tagged to its job. A captured hold and outcome money sit on services.dev's account, untransferred, under the job's transfer group, in no one's available balance, so a refund elsewhere, a dispute elsewhere or a negative balance can't reach them:
npx services.dev jobs flow job_7Hq5 # api.forsale: a won deal, held to its windowjob_7Hq5 · transfer_group job_7Hq5
placement $50.00 4 and 9 Nov, a gig at each fill · py_…Hq5p and py_…Hq5q debited from acct_…F0r5, api.forsale · → tr_…Hq5p to closers.deals
setter $250.00 10 Nov, at meet.held · py_…Hq5s debited from acct_…F0r5 · → tr_…Hq5s to acct_…7Hs1, the setter · no charge exists yet
chg_7Hq5 $11,100.00 pi_…Hq5 on services.dev's account · on_behalf_of acct_…F0r5 · us_bank_account on mandate_…Hq5, off-session
processing 4 Jan, succeeded 8 Jan · untransferred under job_7Hq5, in no one's available balance
held $3,700.00 the 5% · $7,400.00 the closer's share · until 9 Mar 2027
9 Mar → tr_…Hq5a $3,683.66 less the take on $3,400.00 to acct_…F0r5: the 5% less AI $11.34 and processing $5.00 · source_transaction ch_…Hq5
12 Mar → tr_…Hq5b $7,400.00 to acct_…7Hq4, the closer, on the Pool's Friday run · source_transaction ch_…Hq5Some money moves when no charge exists to move it from: flat pay before any charge, such as a setter's at the held meeting; placement and AI on a job that ends lost; a lost dispute on a member's charge. Each is an account debit from your account to services.dev, then a transfer onward, so a member is always paid from money already collected. A Task with flat pay posts only once its pay can be drawn; until then the order answers 402 pay_unfunded with the cure:
npx services.dev jobs flow job_7Hs3 --debits # api.forsale: a lost deal, with no charge to draw fromjob_7Hs3 · lost 10 Nov · competitor · the mandate is never charged
placement $25.00 3 Nov · py_…Hs3p debited from acct_…F0r5 · → tr_…Hs3p to closers.deals
setter $250.00 3 Nov, at meet.held · py_…Hs3s debited from acct_…F0r5 · → tr_…Hs3s to acct_…7Hs1
AI $40.00 10 Nov, at the end · py_…Hs3a debited from acct_…F0r5 · stays on services.dev's account
drawn from api.forsale's available balance · its bank account …6789 had it been short · never a member's transferWhen money goes back, services.dev draws it in this order and stops at the first that covers it:
- the job's untransferred hold;
- a reversal of your transfer on that job;
- your account's available balance;
- a debit to your saved bank account.
It never draws on a member's transfer, another job's held share or a member-rail charge, and check fails held_pay_exposed on any definition that would. A balance still negative after the fourth step answers your new orders 402 balance_negative until it is paid:
npx services.dev jobs flow job_7Hr1 --refunds # a goodwill refund of api.lawyer's line rfd_7Hr1 $174.00 re_…Hr1 on ch_…Hr1, from services.dev's account
1 · the hold: none, the charge had released
2 · tr_…Hr1 reversed in full from acct_…L4w1, $157.17 less the take · the take returned with it
3 · py_…Hr1 $16.83 debited from acct_…L4w1: coverage $4.00, AI $2.10 and processing $10.73, which stay spent
chg_7Hr2 $175.00 the attorney's sale · untouchednpx services.dev jobs flow job_7Hn9 --disputes # lost, on an attorney's own charge dsp_7Hn9 $175.00 du_…Hn9 on ch_…Hn9 · the amount and the $15.00 fee debited from services.dev's account, which carries it
recovered from acct_…L4w1, api.lawyer, as le_7Hn9m make_whole, by py_…Hn9 · tr_…Hn9 to the attorney standsEach Stripe event has one meaning, set by how the charge is held:
| services.dev event | An authorization | A captured hold | A mandate |
|---|---|---|---|
charge.held | payment_intent.amount_capturable_updated | payment_intent.succeeded, at the order | — |
charge.mandated | — | — | setup_intent.succeeded |
charge.authorization_expiring | services.dev's own clock, a day before capture_before | — | — |
charge.pending | — | — | payment_intent.processing: a bank debit in flight |
charge.collected | payment_intent.succeeded, at capture | the fact itself: the money already sits on services.dev's account | payment_intent.succeeded |
charge.failed | — | — | payment_intent.payment_failed, or requires_action on an off-session charge |
charge.voided | payment_intent.canceled | a full refund from the hold | payment_intent.canceled |
| services.dev event | The Stripe event behind it |
|---|---|
charge.refunded | charge.refunded, with transfer.reversed once your share has moved |
dispute.prevented | radar.early_fraud_warning.created, then the refund |
dispute.opened, dispute.closed | charge.dispute.created, charge.dispute.closed |
pay.paid | transfer.created, to the member's account |
payout.paid, payout.failed | payout.paid, payout.failed, on the account that paid out |
pay.waiting | account.updated, with requirements.currently_due |
take.credited | transfer.created: the month's lost-cost netting, returned to your account |
subscription.renewed, subscription.unpaid | invoice.paid, invoice.payment_failed |
Each event on the feed carries the Stripe ids behind it:
npx services.dev events --source stripe --job job_7Hq5 # each services.dev event, and the Stripe event behind it 10 Nov 11:34 pay.accrued ← the meet.held guard · then py_…Hq5s, and transfer.created for tr_…Hq5s
4 Jan 09:21 charge.pending ← payment_intent.processing · us_bank_account on mandate_…Hq5
8 Jan 09:00 charge.collected ← payment_intent.succeeded
9 Mar 09:00 charge.earned ← the window's own clock · transfer.created for tr_…Hq5a
12 Mar 16:02 pay.paid ← transfer.created for tr_…Hq5b, on the Pool's run · payout.paid follows on acct_…7Hq4, on Stripe's timing| Key | Written | Left out | Does |
|---|---|---|---|
Brand.tax | 'stripe' | false | false | Calculates tax on your charges with Stripe Tax and collects it as its own line |
Brand.payouts | { rail: 'stripe'; schedule? } | rail: 'stripe', daily | Your connected account, and how often it pays you: payouts |
| Code | When |
|---|---|
pay_unfunded | 402 on an order: flat pay before any charge can't be drawn from your balance or your bank account |
balance_negative | 402 on an order: your balance is negative after the draw order |
held_pay_exposed | check: a definition would draw on held share pay, a member's transfer or a member-rail charge |
Every path runs in test mode, set by magic values on the order's metadata.sandbox:
| Value | What it makes happen | At Stripe |
|---|---|---|
payment: 'decline' | the charge declines, and dunning runs | pm_card_chargeDeclined |
payment: 'auth_expired' | the authorization nears its lapse, and the hold is captured | the test clock past capture_before |
payment: 'dispute' | the buyer's bank opens a dispute after capture | pm_card_createDispute |
payment: 'early_warning' | an early fraud warning arrives first | a test card that raises radar.early_fraud_warning.created |
payment: 'bank' | the charge is a bank debit, pending four days, then collected | us_bank_account, test routing 110000000 |
payout: 'fail' | the member's next payout fails | test bank account 000111111116 |
proof: 'paid' | the outcome's payment lands at once | invoice.paid on the buyer's test account |
proof: 'refunded_day_20' | the payment behind the outcome is refunded on day 20 | the test clock at day 20, then charge.refunded |
services.dev's test clock advances a Stripe test clock with it, so every window and schedule moves together:
→ POST /deals {"account":{"name":"Test Freight"},"value":80000,"offer":"https://seller.example/offer","max_usd":12000,"payment_method":"pm_card_visa","key":"test-1","metadata":{"sandbox":{"proof":"paid"}}}
→ GET /owner/deals/job_9Tq1 # the AI and a test closer work it; the proof pays at once
← 200 · job_9Tq1 · deal · won · $11,100.00 charged, held to 2027-01-12 · test clock at 13 Nov 2026
ledger +$11,100.00 · closer $7,400.00 · setter $250.00 · placement $50.00 · AI $11.34 · you $3,388.66 before the take
→ POST /test_clocks/default/advance {"by":"60d"} # backed by a Stripe test clock
2027-01-12 job_9Tq1 outcome.final · charge.earned $11,100.00
2027-01-12 tsk_9Tq3 pay.accrued $7,400.00 · the closer
2027-01-14 tsk_9Tq3 pay.payable
2027-01-15 pyo_9Tq3 pay.paid $7,400.00 · Friday's run · test bank …0000