Lines and rails
The lines a charge carries beside the price, and who sells each one. Pass-through fees at cost, flat lines, referral shares and placement; then the three sellers a fee can have, the brand, the member at the same checkout, or an entity you own, which the rules decide.
A charge can carry more than your price, and not every dollar of it is yours to sell. Lines say what else the buyer pays. Rails say who sells each fee, on whose account.
price.lines adds lines to the charge. Each is itemized on the receipt and leaves the take's base with its proof:
| Line | Written | Charged to | Leaves the base with |
|---|---|---|---|
| Pass-through | { at: 'cost', from: 'fee' } | the buyer, at what the outside system charged, never marked up | its receipt |
| Pass-through you caused | { at: 'cost', from: 'fee', fault: 'brand' } | you, when the repeat fee follows your own error | its receipt |
| Flat | { usd: 25, to: 'courier' } | the buyer, per job, such as a courier's delivery | its act |
| Referral share | { share: '1%', of: 'closed_value', to: 'referrer', on: 'won' } | the buyer, at that end, never a member's pay | the outcome |
| Placement | set by the Pool you import | you, per Task the Pool fills | the filled Task: placement |
A pass-through on api.lawyer, when the office asks for a second class's fee:
git diff services/trademark-response.ts- price: { usd: 349, release: 'file' },
+ price: { usd: 349, release: 'file', lines: { office: { at: 'cost', from: 'fee' } } },→ GET /owner/matters/job_7Hr2 # the office asked for a second class's fee record file · receipt.rejected · fee_deficiency → fee · rcp_7Hr2 $350.00 paid to USPTO → file · rcp_7Hr3 accepted
ledger +$699.00 · office $350.00 at cost, rcp_7Hr2 (pass-through) · attorney's fee $175.00, sold by the attorney (rail member) · brand $174.00 · AI $2.10 · coverage $4.00 · you $167.90
take on $170.00 · the office fee leaves the base with its receiptA referral share on api.forsale, charged to the seller beside the 5%, so the closer keeps every dollar of theirs:
grep -n -B1 "referral" services/deal.ts # the referrer's line, beside the price51- price: { usd: 0, share: '5%', of: 'closed_value', on: 'won', ai: 40,
52: lines: { referral: { share: '1%', of: 'closed_value', to: 'referrer', on: 'won' } } },→ GET /owner/deals/job_7Hr4 # won, with a referrer ledger +$9,920.00 · closer $6,200.00 (share, from the seller) · referrer $620.00 (line, from the seller) · placement $25.00 · AI $10.80 · you $3,064.20 before the take
take on $3,075.00 · never on the referral or the closer's shareEach role's fee has a seller:
rail | Who sells the fee | Where the money lands | On the receipt |
|---|---|---|---|
'brand' | you, the default | your account; you pay the member out | one seller |
'member' | the member, at the same checkout as your charge | the member's own payout account, whole, never your balance | two sellers, one payment |
'entity' | an entity you own, which contracts with the member and keeps a spread | the entity's account | the entity beside you |
A role's rail is its rules row's rail, so the row that reserves an act also says who may sell it. check fails rail_conflict when a role says otherwise. The rail is fixed when the Task posts, never per act, so one job can carry two: your product fee on the brand rail and a professional fee on the member's.
grep -A3 "'trademark-response': {" rules.ts 'trademark-response': {
respond: { reserved: 'bar admission', where: '*', rail: 'member', position: 'A response for the applicant is signed by an attorney admitted in any state.' },
file: { reserved: 'bar admission', where: '*', rail: 'member', position: 'Filing the response for the applicant is practice before the office.' },
fee: { open: true, position: 'Paying the office its fee is a delivery act.' },check reads both rails back, with what each seller sells:
npx services.dev check services/trademark-response.tsservices/trademark-response.ts · 21 lines · $349 per job, within 48 hours, charged on file's receipt.
rails attorney · member, from the respond and file rows · the attorney sells $175.00 on their own account
brand · api.lawyer sells $174.00 · one checkout, two sellers, one receipt
reads API.LAWYER* TM RESPONSE (Brand.descriptor) · <attorney> VIA API.LAWYER (Pool.descriptor)
ledger +$349.00 · attorney's fee $175.00, sold by the attorney (rail member) · brand $174.00 · AI $2.10 (example) · coverage $4.00 · you $167.90
take on $170.00 · never on the attorney's feeThe buyer enters one card at one checkout. It writes two charges, one on behalf of you and one on behalf of the member, each released by the same fact. At Stripe the card is authenticated once, by a SetupIntent, then two manual-capture PaymentIntents authorize, the member's first. A decline of the second cancels the first before the 402 answers, so a buyer never holds half a checkout. Both capture at the fact, and on a bank account both are debited then:
→ GET /owner/matters/job_7Hq3/charges
{
"object": "list",
"checkout": "chk_7Hq3",
"data": [
{ "id": "chg_7Hq3", "object": "charge", "seller": "brand", "amount": 17400, "currency": "usd", "status": "earned", "take": { "base": 17000 }, "stripe": { "type": "separate", "on_behalf_of": "acct_…L4w1", "payment_intent": "pi_…Hq3", "transfer_group": "job_7Hq3" } },
{ "id": "chg_7Hq4", "object": "charge", "seller": "member", "member": "mbr_7Hq3", "amount": 17500, "currency": "usd", "status": "earned", "take": null, "stripe": { "type": "destination", "on_behalf_of": "acct_…7Hq3", "payment_intent": "pi_…Hq4", "transfer_group": "job_7Hq3" } }
→ POST /matters {"service":"trademark-response",…,"max_usd":349,"payment_method":"pm_…0341"} # the card covers one charge, not both{
"type": "OFFER",
"code": "payment_declined",
"reason": "The card authorized the attorney's $175.00, then declined api.lawyer's $174.00, so the attorney's authorization was canceled: payment_intent.canceled, charge.voided. Nothing is held.",
"next": { "do": "pay", "url": "https://api.lawyer/pay/chk_7Hr0", "note": "another card or a bank account, for both charges together" },
"doc_url": "https://services.dev/docs/money/lines-and-rails#the-two-seller-checkout"
}The receipt names both sellers and how each reads on the buyer's statement, from Brand.descriptor and Pool.descriptor. The member reads the fee as their own sale:
→ GET /matters/job_7Hq3/receipt # the client, in the customer portal api.lawyer $174.00 the response, drafted, reviewed and filed · USPTO receipt rcp_7Hq3
on your statement as API.LAWYER* TM RESPONSE
mbr_7Hq3, attorney $175.00 the attorney's fee, sold by the attorney · bar admission, US-NY
on your statement as J DOE ESQ VIA API.LAWYER
card …4242 · both authorized 2 Nov, together · charged 9 Nov 2026, when the receipt arrived
final 16 Nov 2026 · each seller refunds only its own line→ GET /me/earnings/tsk_7Hq3 # as mbr_7Hq3, in the delivery portal sold Mon 9 Nov 15:12 on your payout account, at the client's checkout $175.00
costs none: api.lawyer pays the processing and the Pool's cover, and services.dev takes nothing from your fee
final yoursA member-rail role needs a member whose payout account can accept payments. Until it can, the claim answers rail_unavailable with the cure:
→ POST /tasks/tsk_7Hr5/claim # as mbr_7Hs3, whose payout account can't take payments yet{
"type": "BLOCKED",
"code": "rail_unavailable",
"reason": "This Task sells your fee on your own account, and your account can't accept payments yet: Stripe asks for your tax ID.",
"next": { "do": "open", "url": "/me/payouts", "note": "finish your payout account, then claim again" },
"doc_url": "https://services.dev/docs/money/lines-and-rails#the-two-seller-checkout"
}The member's charge carries no take, and its refund or dispute is its own: refunds and disputes. Where each charge lands at Stripe, and who carries a lost dispute on it, is flow of funds.
| App | What it shows |
|---|---|
| Customer portal | One receipt with a line per seller, each with its name, credential and statement descriptor, and every pass-through with its receipt |
| Delivery portal | On the member rail, the fee as the member's own sale, on their payout account |
| Owner console | The ledger by rail: what you sold, what members sold, and each pass-through with its receipt |
| Key | Written | Left out | Does |
|---|---|---|---|
price.lines.<name> | { at: 'cost'; from: <step>; fault?: 'brand' } | { usd; to } | { share; of; to; on } | none | A pass-through, flat or share line on the charge |
roles.<r>.pay.rail | 'brand' | 'member' | 'entity' | the row's rail | Who sells the role's fee |
Rules row rail | 'brand' | 'member' | 'entity' | 'brand' | The rail for the act's role |
Brand.descriptor | string, up to 22 characters | the domain, uppercased | How your charge reads on the buyer's statement, with each Service's short name after it |
Pool.descriptor | string, with the member's name as {member} | the member's name, then VIA and your domain | How a member-rail charge reads on the buyer's statement |
| Code | When |
|---|---|
rail_conflict | check: a role's rail contradicts its rules row |
rail_unavailable | a claim of a member-rail Task by a member whose account can't accept payments, or whose country can't settle a charge made on their behalf in the buyer's currency; the answer names the cure |
payment_declined | a checkout where either charge was declined: both are voided, and the 402 asks for another card or a bank account |
Pass-through and flat lines run live on Free, placement on Launch, and referral shares on Team. On every plan, a fee a rules row puts on the member rail sells through the two-seller checkout, and services.dev's take never touches it (never for sale).