---
title: "Lines and rails"
url: https://services.dev/docs/money/lines-and-rails
captured: [money-ledger.txt, money-rails.txt]
---
# Lines and rails

URL: https://services.dev/docs/money/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.

## Lines

`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](https://services.dev/docs/people/pool/share.md#the-placement-line) |

A pass-through on api.lawyer, when the office asks for a second class's fee:

```bash
git diff services/trademark-response.ts
```

```txt title="magic values: none"
-  price: { usd: 349, release: 'file' },
+  price: { usd: 349, release: 'file', lines: { office: { at: 'cost', from: 'fee' } } },
```

```txt
→ GET /owner/matters/job_7Hr2   # the office asked for a second class's fee
```

```txt title="200 · job_7Hr2 · trademark-response · delivered · $699.00 released · magic values: none"
  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 receipt
```

A referral share on api.forsale, charged to the seller beside the 5%, so the closer keeps every dollar of theirs:

```bash
grep -n -B1 "referral" services/deal.ts   # the referrer's line, beside the price
```

```txt title="magic values: none"
51-  price: { usd: 0, share: '5%', of: 'closed_value', on: 'won', ai: 40,
52:    lines: { referral: { share: '1%', of: 'closed_value', to: 'referrer', on: 'won' } } },
```

```txt
→ GET /owner/deals/job_7Hr4   # won, with a referrer
```

```txt title="200 · job_7Hr4 · deal · won · $9,920.00 charged, held to 2027-01-12 · magic values: none"
  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 share
```

## Rails

Each 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 |

## The rules decide the rail

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`](https://services.dev/docs/reference/check/rail_conflict.md) 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.

```bash
grep -A3 "'trademark-response': {" rules.ts
```

```txt title="magic values: none"
    '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:

```bash
npx services.dev check services/trademark-response.ts
```

```txt title="magic values: none"
services/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 fee
```

## The two-seller checkout

The 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:

```txt
→ GET /owner/matters/job_7Hq3/charges
```

```json title="captured/money-rails.txt · 200 · magic values: none"
{
  "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" } }
  ],
  "has_more": false
}
```

```txt
→ POST /matters {"service":"trademark-response",…,"max_usd":349,"payment_method":"pm_…0341"}   # the card covers one charge, not both
```

```json title="402 · magic values: none"
{
  "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:

```txt
→ GET /matters/job_7Hq3/receipt   # the client, in the customer portal
```

```txt title="200 · job_7Hq3 · paid · $349.00 · one checkout, two sellers · chk_7Hq3 · magic values: none"
  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
```

```txt
→ GET /me/earnings/tsk_7Hq3   # as mbr_7Hq3, in the delivery portal
```

```txt title="200 · tsk_7Hq3 · api.lawyer · attorney · respond · $175.00 · your own sale · magic values: none"
  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     yours
```

A member-rail role needs a member whose payout account can accept payments. Until it can, the claim answers `rail_unavailable` with the cure:

```txt
→ POST /tasks/tsk_7Hr5/claim   # as mbr_7Hs3, whose payout account can't take payments yet
```

```json title="409 · magic values: none"
{
  "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](https://services.dev/docs/money/refunds-and-disputes.md#two-sellers). Where each charge lands at Stripe, and who carries a lost dispute on it, is [flow of funds](https://services.dev/docs/money/flow-of-funds.md).

## In each app

| 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 |

## Every form

| 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`](https://services.dev/docs/reference/check/rail_conflict.md) | `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](https://services.dev/docs/money/plans.md#free), placement on [Launch](https://services.dev/docs/money/plans.md#launch), and referral shares on [Team](https://services.dev/docs/money/plans.md#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](https://services.dev/docs/money/plans.md#never-for-sale)).

---

- Up: [Money](https://services.dev/docs/money.md)
- Previous: [Release](https://services.dev/docs/money/release.md)
- Next: [Flow of funds](https://services.dev/docs/money/flow-of-funds.md)
