---
title: "Year-end close"
url: https://services.dev/docs/examples/tax/year-end-close
captured: [tax-build.txt, tax-check.txt, tax-money.txt]
---
# Year-end close

URL: https://services.dev/docs/examples/tax/year-end-close

> The year's books, reconciled and closed before the return reads them. AI reconciles each account and proposes the entries, the officer decides which to post, and for $900 instead of $300 an accountant from gigs.accountants attests the close. The closed books are kept on the taxpayer for that year's return.

*tax's words: return is a job, taxpayer is a subject, review is a task, preparer is a member (examples/tax/brand.ts).*

A return is only as good as the books it reads. The Year-End Close closes them first: the AI reconciles each account to its statement and proposes the adjusting entries, an adversarial tie-out checks them, and the officer decides which to post. It sells two ways on one order, the AI's close for $300, or the same close attested by an accountant for $900.

```bash
cat services/year-end-close.ts
```

```txt title="magic values: none"
import { Service } from 'services.dev'

// The year's books, closed before the return reads them. The AI reconciles each account to its statement and proposes
// the adjusting entries, an adversarial tie-out checks them, and the officer decides which to post. For $900 instead of
// $300, an accountant from gigs.accountants reviews the close and attests it in their own session: the brand imports that
// Pool, so it recruits no one and pays its operator a placement line on each filled review. The closed books are kept on
// the taxpayer for the year, and that year's return opens with its books item answered.
export default Service({
  name: 'Year-End Close',
  description: "A year's books, reconciled and closed.",
  input: {
    owner: 'party: the officer who decides', ein: 'text: such as 12-3456789', tax_year: 'text: such as 2026',
    books: 'url: a read-only link to the ledger, such as https://books.example/acme', statements: "file[]: each account's year-end statement",
  },
  output: { trial_balance: 'file', entries: 'file: each adjusting entry, with its source', closed_books: 'url: the books, closed for the year' },
  subject: { kind: 'taxpayer', key: 'ein', period: 'tax_year', keeps: { closed_books: 'closed_books' } },
  roles: { accountant: { pool: 'gigs.accountants/accountants', pay: 250 } },
  deliver: {
    reconcile: { by: 'ai', cite: 'each account against its statement' },
    check: { review: 'adversarial', lenses: ['numeric tie-out', 'cutoff'] },
    post: { ask: 'owner', to: 'decide', choices: ['post every entry', 'post some, in writing'] },
  },
  price: { usd: 300, approved: 900 },
})
```

`check` reads it back. The accountant comes from another operator's Pool, imported by name, with its terms pinned:

```bash
npx services.dev check
```

```txt title="magic values: none"
  ledger  +$900.00 · AI $1.26 (example) · preparer $150.00 · signer $105.00 · you $643.74 · 4 jurisdictions
services/year-end-close.ts · 15 lines · $300 per job, or $900 with an accountant's approval, within 48 hours, charged on delivery.
  roles   accountant · from gigs.accountants/accountants, a Pool another operator runs · $250 an approval · placement $20.00 a filled review
  import  gigs.accountants · its operator runs the roster, verification, dispatch and payouts · terms pinned at 2026-09 · $250 is at or above its $200 minimum
          +$900.00 · AI $1.26 (example) · accountant $250.00 · placement $20.00 · you $628.74 · approved
  margin  at least $240.00 a job (80%), $450.00 approved (50%) · a job that stops costs you at most $450.00
```

## One order, two prices

Without `max_usd`, the order answers an OFFER with both, and the buyer picks one with `approved`:

```txt
→ POST /returns {"service":"year-end-close","owner":{"name":"Ada Lovelace","email":"ada@example.com"},"ein":"12-3456789","tax_year":"2026","books":"https://books.example/acme","statements":["bank-2026.pdf","card-2026.pdf"],"key":"close-2026"}
```

```txt title="captured/tax-money.txt · 402 · OFFER · $300 for the AI's close, or $900 with an accountant's approval. · magic values: owner.email = signs@example.test, metadata.sandbox.asks = {"organizer.books":"after 160d","organizer.assets":"waive","organizer #2":"after 2d","w9":"after 19d"}, metadata.sandbox.outside = {"reject":{"file.US-NY":["ein_mismatch"]}}, metadata.sandbox.events = { notice.received: { at: 2027-11-14T15:00:00Z, data: { notice, reply_by, tax_years } } }"
  choices   approved: false · $300.00 · AI reconciles every account and proposes the entries; you decide which to post
            approved: true · $900.00 · an accountant from gigs.accountants reviews the close and attests it before you get it
  next      POST /returns {…,"max_usd":300} or {…,"approved":true,"max_usd":900}
```

## An accountant's approval

The approval is a step the accountant attests in their own session, on gigs.accountants, after the officer posts. The brand pays its operator $20 for each review it fills, never out of the accountant's $250:

```txt
→ GET /owner/returns/job_4Tz2   # approved
```

```txt title="captured/tax-money.txt · 200 · job_4Tz2 · year-end-close · delivered · $900.00 charged · approved · magic values: owner.email = signs@example.test, metadata.sandbox.asks = {"organizer.books":"after 160d","organizer.assets":"waive","organizer #2":"after 2d","w9":"after 19d"}, metadata.sandbox.outside = {"reject":{"file.US-NY":["ein_mismatch"]}}, metadata.sandbox.events = { notice.received: { at: 2027-11-14T15:00:00Z, data: { notice, reply_by, tax_years } } }"
  record  reconcile · ai · 14 accounts | check · ai · adversarial · 2 lenses · pass | post · owner · decided "post every entry" · 6 entries | approve · accountant · tsk_7Hz2 · mbr_ga_4410 of gigs.accountants · attested
  ledger  +$900.00 · AI $1.26 · accountant $250.00 · placement $20.00 to gigs.accountants · you $628.74 · approved
  take    on $630.00 · the accountant's pay and the placement leave the base
  kept    sbj_7Hq2 · closed_books 2026 · the 2026 return's organizer opens with its books item answered
```

## Kept for the return

`keeps: { closed_books }` writes the closed books on the taxpayer for the year. That year's annual return opens with its organizer's books item answered, and says where it came from. [Annual return](https://services.dev/docs/examples/tax/annual-return.md) reads it, and [Two doors](https://services.dev/docs/examples/tax/pool.md#two-doors) covers importing a Pool.

---

- Up: [The tax example](https://services.dev/docs/examples/tax.md)
- Previous: [Carryforward watch](https://services.dev/docs/examples/tax/carryforward-watch.md)
- Next: [Information returns](https://services.dev/docs/examples/tax/information-returns.md)
