---
title: "Outcomes"
url: https://services.dev/docs/money/outcomes
captured: [money-ledger.txt, money-outcomes.txt]
---
# Outcomes

URL: https://services.dev/docs/money/outcomes

> Pricing on results, as one operating contract. The win rate a price breaks even at, who funds the work before the end, the proof that confirms the amount, how the money is collected, the window that holds it, what reverses it, and the tail that keeps a lost deal watched.

Outcome pricing pays you on results, never on a claim. The outcome names an amount, who proves it, how it's collected and how long it stays held.

## The smallest form

Two lines on api.forsale's deal: the outcome and its proof, then a price that charges nothing on effort:

```bash
grep -n -A1 "outcome:\|price:" services/deal.ts
```

```txt title="magic values: none"
49:  outcome: { amount: 'closed_value', proof: 'payment', match: { customer: 'account', metadata: 'deal' },
50-    window: { bank: '60d', card: '120d' }, tail: '90d', due: '90d', collect: job => (job.output.billing === 'monthly' ? 'each' : 'first') },
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' } } },
```

`check` reads it back, down to the win rate it breaks even at:

```bash
npx services.dev check services/deal.ts
```

```txt title="magic values: none"
services/deal.ts · 42 lines · nothing on effort; 5% of closed_value at won, proven by the account's payment, held 60 days by bank, 120 by card.
  outcome proof payment, read through services.dev's Stripe app on the seller's account · matched on the account's customer and metadata.deal · collect first, or each invoice when billing is monthly · due 90d · window 60d by bank, 120d by card, from each collection · tail 90d
  after   the window, a reversal of in_… is the seller's · the closer waits with the 5%
  hold    mandate · the seller's bank account or card, saved at the order up to max_usd · nothing held before won
  ai      $40.00 a deal, funded by api.forsale, won or lost · then ask
  ledger  +$11,100.00 at won on $74,000 · closer $7,400.00 (share, from the seller) · setter $250.00 · placement $50.00 · AI $11.34 (example) · you $3,388.66
  lost    +$0.00 · setter $250.00 when the meeting was held · placement $50.00, the setter's gig and the closer's · AI up to $40.00 · you −$340.00 when a closer loses it
  odds    a deal a closer loses costs $340.00, a won one leaves $3,388.66 · breaks even at 9.1% won (about 1 in 11)
```

Under the seller's `humans_from`, AI closes alone, and the whole share is yours:

```txt
→ GET /owner/deals/job_7Hq1   # won by AI alone
```

```txt title="200 · job_7Hq1 · deal · won · $1,500.00 charged, held to 2026-12-19 · magic values: none"
  close     ai · committed · closed_value $30,000.00 · under humans_from, so no closer
  proof     payment · in_…5520 on the seller's Stripe account · $30,000.00 paid 20 Oct 2026
  ledger    +$1,500.00 · AI $9.12 of $40.00 · no person, no placement · you $1,490.88 before the take
  take      on $1,500.00, the whole share
```

From $50,000, a closer takes it, and their 10% is charged to the seller beside your 5%:

```txt
→ GET /owner/deals/job_7Hq5   # won by a closer, and proven
```

```txt title="200 · job_7Hq5 · deal · won · $11,100.00 charged, held to 2027-03-09 · magic values: none"
  close     person · closer · mbr_7Hq4 · committed · closed_value $74,000.00
  proof     payment · in_…8841, the seller's own invoice, matched on the account's customer and metadata.deal · $74,000.00 paid 4 Jan 2027, net 30 from the close on 4 Dec
  outcome   verified · $74,000.00 · window 60d from the collection · closes 9 Mar 2027
  money     outcome.verified → chg_7Hq5 $11,100.00 debited off-session on the seller's bank mandate → charge.pending 4 Jan → charge.collected 8 Jan → held under job_7Hq5
  ledger    +$11,100.00 · closer $7,400.00 (share, from the seller) · setter $250.00 · placement $50.00 · AI $11.34 of $40.00 · you $3,388.66 before the take
  held      the 5% $3,700.00, the closer's $7,400.00 and the take, until the window closes
```

## Who funds the work before the end

On deal.ts you fund the $340 a lost deal costs, which the break-even rests on. If the seller funds the setter instead, the deal breaks even at 2.4%, and `check` fails `effort_charged` until `price.effort: 'named'` puts that charge first in the OFFER. [Pay](https://services.dev/docs/money/pay.md#who-funds-it) runs both.

## Proof

`outcome.proof` names who confirms the amount. Every surface labels a verified outcome apart from a self-reported one:

| `proof` | Confirmed by | Labelled |
|---|---|---|
| `'payment'` | a payment on the buyer's own Stripe account, read at the order | verified |
| `'signature'` | the counterparty's signature on the outcome | verified |
| `'counterparty'` | the counterparty's confirmation through its own ask | verified |
| `'receipt'` | an outside system's receipt that carries the amount | verified |
| `'self'`, or left out | your code's `job.outcome({ amount, evidence })` | self-reported |

`'payment'` reads the buyer's Stripe account through services.dev's Stripe app, installed at the order. It watches that payment through the window, so its refund or dispute fires `outcome.reversed` by itself. A payment outside Stripe proves by `'receipt'` or `'counterparty'`.

A self-reported amount never sets anyone's money alone. The buyer sees it with its evidence and can contest it inside the window, and a contested amount stays held until a credentialed peer rules. No share pay rests on `'self'`:

```txt
→ GET /owner/jobs/job_7Hq2   # claim-appeal: an outcome your code reports
```

```txt title="200 · job_7Hq2 · claim-appeal · delivered · $300.00 charged · magic values: none"
  outcome   self-reported 9 Nov 2026 · $1,200.00 · job.outcome() with payment-notice.pdf
  contest   open to the buyer until 9 Dec 2026 · none filed
  ledger    +$99.00 at delivery · +$201.00 at outcome · AI $0.84 · you $299.16
```

## How the payment finds the job

`outcome.match` ties one payment to one job: it comes from the `customer` party and carries the job's id under `metadata`. The end step commits an invoice drafted that way on the buyer's account, api.forsale's `pay_link`, so no other sale counts.

`outcome.due` bounds the wait, 90 days unless set; past it, `outcome.lapsed` ends the outcome with nothing charged. A party that already pays the buyer answers 409 `account_is_customer`, whose `next` orders with `expansion: true`: the share is of what the account adds. [The sales money](https://services.dev/docs/examples/sales/money.md#how-the-payment-finds-the-deal) runs it.

## Collecting at the outcome

At `outcome.verified`, the share and every pay charged `from: 'buyer'` are collected on the buyer's mandate, one charge per seller, and held under the job. For an amount paid over time, `outcome.collect` times the cash; `price.on` stays the end:

| `collect` | Charged |
|---|---|
| `'first'`, the default | the whole share, at the first payment |
| `'each'` | each payment's part, each held for its own window |
| `'full'` | the whole share, once the amount is paid in full |

```txt
→ GET /owner/deals/job_7Ht1   # collect 'each': a $74,000.00 contract paid monthly
```

```txt title="200 · job_7Ht1 · deal · won · 3 of 12 invoices paid · $2,775.00 charged · magic values: none"
  proof     payment · in_…T101 to in_…T112 on the seller's Stripe account, matched on the subscription
  each      $6,166.67 paid → $925.00 charged: the 5% $308.33 and the closer's $616.67, each held 60 days from its own payment
  held      $2,775.00 · final 11 Jan, 10 Feb and 12 Mar 2027 · 9 invoices to come
  ledger    each invoice +$925.00 · closer $616.67 · you $308.33 before the take · the first also carries the setter's $250.00, placement $50.00 and AI $11.34 · you $3,388.66 over the 12
```

## When the charge fails

A declined collection retries under `Brand.dunning`. If it stays unpaid: the buyer's next orders answer 402, flat pay stands, a share charged to the buyer is still the member's at `outcome.final`, and the loss is yours, with no take on it:

```txt
→ GET /owner/deals/job_7Hs8   # won; the first collection was declined
```

```txt title="200 · job_7Hs8 · deal · won · $9,300.00 collected on day 3, held to 2027-01-17 · magic values: none"
  18 Nov    outcome.verified · chg_7Hs8 card declined, insufficient_funds · charge.failed
  19 Nov    ask_7Hs8 to the seller: update the card · Stripe retries on 19 and 20 Nov
  21 Nov    collected on the new card · charge.collected $9,300.00 · held under job_7Hs8
  unpaid    had the retries failed: outcome.unpaid on 2 Dec (Brand.dunning, 14 days) · the closer's $6,200.00 still theirs at outcome.final · the loss yours, with no take on it · the seller's next orders answer 402
```

## The window

`outcome.window` holds what depends on the outcome until it closes: your share, any share pay, and services.dev's take on them. Its default is the horizon of the money behind the proof, and `check` fails `window_too_long` on a window past it:

| Proof | Window, unless set | The horizon it follows |
|---|---|---|
| A card payment | `'120d'` | how long a cardholder can dispute it |
| A bank payment | `'60d'` | how long a debit can be returned |
| A signature | `'30d'` | the counterparty's time to rescind |
| A receipt | `'7d'` | as any charge |
| Self-reported | `'30d'` | the buyer's time to contest |

`window: { bank: '60d', card: '120d' }` holds each payment for its own horizon. After the window, a reversal is the buyer's to carry. A member sees the window on the teaser before they claim:

```txt
→ GET /me/earnings/tsk_7Hq5   # as mbr_7Hq4, the closer, on closers.deals
```

```txt title="200 · tsk_7Hq5 · api.forsale · closer · close · $7,400.00 · held · magic values: none"
  committed Fri 4 Dec 14:02     won, awaiting the payment      deal.ended         $0.00
  proven    Mon 4 Jan 09:20     won, proven by the payment     outcome.verified   $0.00
  held      Fri 8 Jan 09:00     the seller's debit collected   charge.collected   $7,400.00
  accrues   Tue 9 Mar 2027      when the 60-day window closes  pay.accrued
  payable   Thu 11 Mar 2027     two days after                 pay.payable
  paid      Fri 12 Mar 2027     weekly, on the Pool's schedule
```

At the window's close, the money is final and held pay accrues:

```txt
→ GET /owner/deals/job_7Hq5   # 9 Mar 2027: the window closed
```

```txt title="200 · job_7Hq5 · deal · won · $11,100.00 · final · magic values: none"
  money     outcome.final → charge.earned $11,100.00 → pay.accrued $7,400.00
  ledger    +$11,100.00 · closer $7,400.00 · setter $250.00 · placement $50.00 · AI $11.34 · you $3,388.66 before the take
```

Held money moves your cash, not your margin. api.forsale's November pays its setters now and its 5% in January:

```bash
npx services.dev jobs ledger --month 2026-11 --held   # api.forsale: paid on the close
```

```txt title="captured/money-ledger.txt · magic values: none"
api.forsale · November 2026 · 21 deals ended · 3 won, 18 lost
  collected     +$33,300.00   3 won deals: the 5% $11,100.00 and the closers' $22,200.00, by bank debit
  held          −$33,300.00   all of it, under each deal's job, final 12 Jan to 28 Jan 2027
  processing       −$15.00   $5.00 a bank debit
  pay            −$5,000.00   setters and nurturers, flat, won or lost
  placement        −$625.00   25 filled gigs on closers.deals
  AI               −$809.02
  cash           −$6,449.02   this month
  at the windows  +$11,100.00 to you · $22,200.00 to the closers
  take           on $4,700.00: won bases $10,200.00, less the $5,500.00 the lost deals cost
```

## What reverses

Held share pay reverses for one cause only: the outcome's own money going back inside the window, recorded as `outcome.reversed`:

```txt
→ GET /owner/deals/job_7Hw6   # another won deal: its payment was refunded inside the window
```

```txt title="200 · job_7Hw6 · deal · won · reversed · $0.00 kept · magic values: none"
  proof     payment · in_…9310 refunded 3 Dec 2026, day 20 of 60
  money     outcome.reversed → chg_7Hw6 refunded $11,100.00 from the hold → the closer's $7,400.00 never left it
  ledger    +$0.00 · setter $250.00, paid at the held meeting · placement $50.00 · AI $12.02 · you −$312.02
  take      reversed with the share
```

| What happens | Your share | Held share pay | services.dev's take | Flat pay, placement |
|---|---|---|---|---|
| The outcome's money goes back inside the window | refunded to the buyer | reverses: it was held, never paid | reverses | stands |
| Part of it goes back inside the window | adjusts pro rata, `outcome.adjusted` | adjusts pro rata | adjusts | stands |
| Your goodwill refund of the share | refunded | stands, and accrues at `outcome.final` | reverses | stands |
| A dispute on another of your charges | nothing moves | nothing moves | nothing moves | stands |
| A reversal after the window | final | the member's | final | stands |

A referral share moves with yours, and flat pay is [never clawed back](https://services.dev/docs/money/pay.md#pay-protection). A partial refund moves every share line by one fraction:

```txt
→ GET /owner/deals/job_7Hs2   # won; the seller's customer was refunded $18,500.00 on day 31
```

```txt title="200 · job_7Hs2 · deal · won · adjusted · $8,325.00 kept of $11,100.00 · magic values: none"
  proof     payment · in_…2207 partly refunded 14 Dec 2026, day 31 of 60 · $74,000.00 → $55,500.00
  money     outcome.adjusted → chg_7Hs2 refunded $2,775.00 to the seller, pro rata
  lines     the 5% $3,700.00 → $2,775.00 · the closer's $7,400.00 → $5,550.00, still held · the take on $2,475.00
  stands    the setter's $250.00 and placement $50.00
  ledger    +$8,325.00 · closer $5,550.00 · setter $250.00 · placement $50.00 · AI $11.34 · you $2,463.66 before the take
```

## The tail

`outcome.tail` keeps a lost or withdrawn deal watched, 90 days unless set, so no one marks it lost and closes it around you. A payment from that account inside the tail verifies it won and pays the roles that worked it. A revival mints a new deal with its lineage and never charges twice:

```txt
→ GET /owner/deals/job_7Hw7   # marked lost 2 Dec; the account paid on 19 Dec
```

```txt title="200 · job_7Hw7 · deal · won by the tail · $9,300.00 charged, held to 2027-02-17 · magic values: none"
  ended     lost on 2 Dec 2026, by the seller · watched for 90 days (outcome.tail)
  proof     payment · in_…3391 from Contoso Logistics, on the seller's Stripe account · $62,000.00 paid 19 Dec 2026
  outcome   verified by the tail · lost → won · the same deal, charged once
  pay       closer mbr_7Hq4, whose gig worked it · $6,200.00, held 60 days
  ledger    +$9,300.00 · closer $6,200.00 · setter $250.00 · placement $50.00 · AI $14.20 · you $2,785.80 before the take
```

## The outcome object

```txt
→ GET /owner/deals/job_7Hq5/outcome
```

```json title="captured/money-outcomes.txt · 200 · magic values: none"
{
  "object": "outcome",
  "job": "job_7Hq5",
  "amount": { "field": "closed_value", "amount": 7400000, "currency": "usd" },
  "proof": { "by": "payment", "ref": "in_…8841", "match": { "metadata": { "deal": "job_7Hq5" } }, "verified": true, "at": "2027-01-04T09:20:05Z" },
  "collect": "first",
  "window": { "for": "60d", "horizon": "120d", "from": "charge.collected", "closes_at": "2027-03-09T09:00:00Z" },
  "tail": { "for": "90d" },
  "contest": null,
  "status": "held",
  "held": [
    { "line": "share", "amount": 370000, "charge": "chg_7Hq5" },
    { "line": "pay", "role": "closer", "member": "mbr_7Hq4", "amount": 740000, "charge": "chg_7Hq5" },
    { "line": "take", "base": 340000 }
  ]
}
```

| Event | When |
|---|---|
| `outcome.reported` | your code reported an amount: self-reported |
| `outcome.verified` | the proof confirmed the amount; the share is collected and held |
| `outcome.contested` | the buyer contested a self-reported amount; it stays held until a peer rules |
| `outcome.adjusted` | part of the money behind it went back; each share line moved pro rata |
| `outcome.unpaid` | the collection stayed declined when dunning ran out |
| `outcome.lapsed` | no matching payment came by `outcome.due`; nothing is charged |
| `outcome.final` | the window closed; held money is final and held pay accrues |
| `outcome.reversed` | the money behind it went back inside the window |

## In each app

| App | What it shows |
|---|---|
| Customer portal | The amount, its proof, the share charged, the date it's final, and the contest, open until the window closes on a self-reported amount |
| Delivery portal | A share as held, with its window's end, before the claim and after it, and the flat pay already paid |
| Owner console | Held outcome money by the date it's final, the live win rate against the break-even, and every reversal with its cause |

## Every form

| Key | Written | Left out | Does |
|---|---|---|---|
| `outcome.amount` | a `money` output | the price's `of` | The amount the share is of |
| `outcome.proof` | `'payment' \| 'signature' \| 'counterparty' \| 'receipt' \| 'self'` | `'self'` | Who confirms it |
| `outcome.match` | `{ customer?: <party input>; metadata?: string; invoice? }` | the job's id under `metadata.<your word for job>` | How a payment proof finds its payment |
| `outcome.due` | `Within` | `'90d'` | How long after the end the payment may come before the outcome lapses |
| `outcome.collect` | `'first' \| 'each' \| 'full'` | `'first'` | When the share is charged on money paid over time |
| `outcome.window` | `Within \| { card?; bank? }` | the proof's horizon | How long outcome money stays held, from the charge's collection |
| `outcome.contest` | `'buyer' \| false` | `'buyer'` on `'self'` | Who can contest a self-reported amount inside the window |
| `outcome.tail` | `Within` | `'90d'` | How long a lost or withdrawn deal stays watched for its payment |
| `price.share`, `price.of`, `price.on` | `Pct`, a `money` output, an end | none | The share, of what, at which end |
| `input.expansion` | `'boolean?'`, declared on the Service | none | Takes the share on what a party that already pays adds |
| `price.usd` | `number` | required | Charged at delivery and counted toward the share; `0` is nothing on effort |
| `price.ai` | `number \| { usd; then }` | a fifth of `usd` | The AI you fund per job: needed when `usd` is `0` |

| Code | When |
|---|---|
| `ai_unfunded` | `check`: `usd: 0` and no `ai` budget |
| `effort_charged` | `check`: a `usd: 0` price charges the buyer before its end, unnamed |
| `share_pay_unverified` | `check`: share pay rests on a self-reported amount |
| `window_too_long` | `check`: a window longer than its proof's horizon |
| `tail_unproven` | `check`: a tail with a proof other than payment, signature or receipt |
| `account_is_customer` | 409 on an order: the party already pays the buyer; `next` offers `expansion: true` |
| `proof_unconnected` | `deploy --live`: a payment proof whose buyer hasn't installed services.dev's Stripe app |
| `win_rate_unmet` | `check`, under `margin: 'strict'`: the last 30 days won less often than the break-even |
| `fee_policy` | `check`: a share your brand's [fee policy](https://services.dev/docs/money/pay.md#your-fee-policy) forbids |

Outcome prices and flat pay at an end run live on [Launch](https://services.dev/docs/money/plans.md#launch), and share pay, which scales with the deal, on [Team](https://services.dev/docs/money/plans.md#team). A share charges at most the buyer's `max_usd`.

---

- Up: [Money](https://services.dev/docs/money.md)
- Previous: [Subscriptions](https://services.dev/docs/money/subscriptions.md)
- Next: [Release](https://services.dev/docs/money/release.md)
