---
title: "The preparers' Pool"
url: https://services.dev/docs/examples/tax/pool
captured: [tax-branches.txt, tax-check.txt, tax-pool.txt]
---
# The preparers' Pool

URL: https://services.dev/docs/examples/tax/pool

> The brand's own Pool on gigs.tax, and accountants imported from gigs.accountants. Preparers, signers and representatives join, the verifier writes what each holds, a signer signs as the paid preparer for the brand's firm, and every member knows what protects them, what they answer for and when it ends.

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

One Pool of the brand's own serves every Service that needs a preparer, a signer or a representative. [The rules table](https://services.dev/docs/examples/tax/rules.md) reserves each act, and the Pool says who holds what it takes. That's how the brand meets licensing by design.

```bash
cat pools/preparers.ts
```

```txt title="magic values: none"
  door: 'gigs.tax',
  roles: {
    preparer: { credential: 'ptin', where: '*' },
    signer: { credential: { all: ['ptin'], any: ['cpa', 'enrolled agent'] }, where: '*', reviews: 'preparer' },
    representative: { credential: ['cpa', 'enrolled agent', 'attorney'], where: '*' },
  scopes: { ptin: '*', 'enrolled agent': '*', cpa: { federal: '*', state: 'region' }, attorney: { federal: '*', state: 'region' }, ctec: 'US-CA' },
    located: 'jurisdiction: where you work from', areas: ['returns', 'amendments', 'notices', 'questions'], hours: 'number: spare hours a week',
  verify: { url: 'https://verify.example.test/preparers', fresh: { ptin: '12-31' } },
  located: { abroad: 'disclose: a preparer outside the US' },
  coverage: { per_act: 500_000, by: 'pool', tail: 'assessment' },
  clear: { attest: 'I have no conflict with this taxpayer, or I disclosed it and they consented in writing', checks: ['business', 'owner'] },
  firms: true,
  affinity: '14d',
  retains: { signed: keptUntil },
  standby: [
  payouts: 'same-day',
```

[The whole file](https://services.dev/docs/examples/tax/build.md#poolspreparersts), and `check` after it.

## What each line sets

| Key | In this Pool |
|---|---|
| `roles` | `preparer` holds a PTIN. `signer` holds a PTIN, and a CPA licence or an enrolled agent's card, and reviews preparers. `representative` holds a CPA licence, an EA card or a bar admission |
| `scopes` | A PTIN and an EA card count on every leg of a return. A CPA licence and a bar admission count federally, and in the state that granted them. A CTEC registration counts in California |
| `join` | Ten fields over three steps, after the email, and resumable, the CAF number among them |
| `verify` | The only writer of what a member holds, through its own token. A PTIN is fresh to 31 December, and the portal gives notice to renew on 1 November and 1 December |
| `located` | A return whose §7216 consent leaves out disclosure abroad goes only to members who work in the US |
| `coverage` | $500,000 an act, on the Pool's own policy, its tail running to each return's assessment date |
| `clear` | Before the packet opens: no conflict with this taxpayer, or one disclosed and consented to in writing, checked against the business and its owner |
| `firms` | A practice joins with its bench and keeps its own conflicts ledger |
| `affinity` | The signer of record is offered next year's return first, for 14 days |
| `retains` | Each signed packet is kept to the year's assessment date, or three years past the return period it was filed in, whichever is later: `keptUntil` in `lib/tax.ts` |
| `door` | `gigs.tax`, the Pool's own door |
| `standby` | Two windows, spring and October, each with its hours and weekly retainer: [The season](https://services.dev/docs/examples/tax/season.md) |
| `payouts` | `'same-day'`: each act is payable two days after it and paid that evening, and a re-sign after a repair is a new act, paid again |

## You sign as the paid preparer, for the brand's firm

| On the return | What goes there |
|---|---|
| The paid-preparer block | the signer's name, PTIN and credential, for apis.tax's firm name and EIN |
| The e-file | apis.tax's EFIN, never the signer's own |
| The officer's Form 8879 | apis.tax as the e-file originator |
| The pay | $45 and $15 a jurisdiction to sign, $90 and $15 a jurisdiction to repair: $105 and $150 on Acme's four states |

## Join and verify

Joining is email first and resumable:

```txt
→ POST /practitioners/join {"email":"grace@example.com"}
```

```txt title="magic values: none"
← 200 mbr_7Hq2 · practitioners · grace@example.com · applying, step 1 of 3: name, credential, number, caf · on
→ POST /practitioners/join {"email":"grace@example.com","answers":{"name":"Grace Hopper","credential":"cpa","number":"P01234567"}}
← 200 mbr_7Hq2 · practitioners · grace@example.com · applying, step 2 of 3: regions, located, areas, hours · on
→ POST /practitioners/join {"email":"grace@example.com","answers":{"regions":["US-NY"],"located":"US-NY","areas":["returns"],"hours":10}}
← 200 mbr_7Hq2 · practitioners · grace@example.com · applying, step 3 of 3: turnaround, min_fee · on
→ POST /practitioners/join {"email":"grace@example.com","answers":{"turnaround":"24h","min_fee":40}}
← 200 mbr_7Hq2 · practitioners · grace@example.com · verified (simulated): cpa in US-NY · on
```

Only the verifier's token writes what a member holds: here a PTIN, fresh to 31 December, and a New York CPA licence:

```txt
→ POST /practitioners/preparers/mbr_7Hq2/verify {"facts":{"credentials":{"ptin":["*"],"cpa":["US-NY"]},"fresh":{"ptin":"2027-12-31"}}}
```

```txt title="magic values: none"
← 200 mbr_7Hq2 · practitioners · grace@example.com · verified: ptin on every leg, fresh to 2027-12-31; cpa federally and in US-NY · on
```

## Who may claim

Each claim is checked against the role and the leg. A PTIN alone can't prepare California's; an enrolled agent's card counts on every leg:

```txt
→ POST /reviews/tsk_7Hq3/claim   # as mbr_7Hq6
```

```txt title="magic values: none"
← 403 ineligible · credential: prepare on US-CA needs ptin, and ctec, cpa, enrolled agent or attorney, and the verifier holds ptin alone for mbr_7Hq6 · rules 2026-10 · services['annual-return'].prepare
```

```txt
→ POST /reviews/tsk_7Hq3/claim   # as mbr_8Ea1
```

```txt title="magic values: none"
← 200 claimed · prepare · tsk_7Hq3 · US-CA · $150.00 · held for you 24 hours
```

A PTIN lapsed on 31 December can't sign at all:

```txt
→ POST /reviews/tsk_7Hq2/claim   # as mbr_lapsed_credential
```

```txt title="magic values: owner.email = signs@example.test, owner.email = declines@example.test, owner.email = silent@example.test, metadata.sandbox.asks = { approve: pay it }, metadata.sandbox.asks = { approve: pay a different amount }, metadata.sandbox.asks = { approve: skip, in writing }, metadata.sandbox.outside = never, metadata.sandbox.brand = stale, metadata.sandbox.brand = verified, member = mbr_eligible, member = mbr_lapsed_credential"
← 403 ineligible · credential: signer needs ptin, and cpa or enrolled agent, and the verifier holds no current one for mbr_lapsed_credential: the PTIN lapsed on 31 December, unrenewed.
```

## Never their own work

`reviews: 'preparer'` keeps a signer off a return they prepared, so Katherine prepares California's repair and Grace Hopper signs:

```txt
→ GET /owner/returns/job_4Tx2   # the owner console
```

```txt title="magic values: none"
  record  consent · owner · §7216 · use: prepare · disclose: none | organizer · owner · upload | compute · code | draft · ai | check · ai · adversarial · 3 lenses · pass | sign · person · ptin and enrolled agent · * · mbr_8Ea1 | authorize · owner · Form 8879-CORP · id-verified | file · IRS and states · US-CA rejected · business_rule · repairing at prepare | prepare · claim refused · mbr_7Hq6 · ineligible on US-CA | prepare · person · ptin and enrolled agent · US-CA · mbr_8Ea1 | sign · person · ptin and cpa · * · mbr_7Hq2 · not the preparer | authorize · signature void | authorize · owner · Form 8879-CORP · id-verified | file · IRS and states · efin simulated · 4 accepted
  ledger  +$1,800.00 · AI $1.68 · preparer $150.00 · signer $210.00 · you $1,438.32
```

## What protects you

| What | How | The key |
|---|---|---|
| Your signature covers what you read | It binds the packet's hash; any change after it voids it, and the new version is a new act | `sign.stamp` |
| Sending back costs you nothing | A send-back is paid like a signature, and scores nothing against you | the review's verbs |
| Each act is insured | $500,000 an act on the Pool's policy, its tail to the return's assessment date | `coverage` |
| A missed date isn't yours unless it waited on you | The penalty for a date the brand missed is credited from the brand's line | `clocks.file.guarantee` |
| Your conflicts stay yours | The ledger holds only hashes of the parties you name, and a firm keeps its own | `clear`, `firms` |
| Stepping aside is free | A conflict or a pass costs nothing and is never scored | the review's verbs |
| Your work is kept | Each signed packet is kept to the year's assessment date, or three years past its return period, whichever is later | `retains` |

## Of record

The signer stays of record for a return until its assessment date, three years after it was filed or due. Until then:

| | Of record means |
|---|---|
| Notices | You hear each notice on that return first, and may claim its response |
| Rungs | Rungs that run steps, like the extension three days out, run without you |
| Penalties | A penalty for a date the brand missed comes from the brand's line, never yours |
| Misses | A miss counts against you only when the step was waiting on you |

While you're Away, another signer of the same credential covers your seats, then the brand: [the seat of record](https://services.dev/docs/people/of-record.md).

## Two doors

apis.tax operates gigs.tax, so its Pool is a file in the folder. gigs.accountants is another operator's, so the Year-End Close imports that Pool by name and pays the operator a placement line:

| | gigs.tax | gigs.accountants |
|---|---|---|
| The Pool | `pools/preparers.ts`, the brand's own | `pool: 'gigs.accountants/accountants'`, imported |
| Who staffs | preparing, signing, representing and adopting advice, on six Services | the Year-End Close's approval |
| Portal | `gigs.tax/practitioners`; the brand's `/practitioners` redirects there | the operator's |
| Join | `gigs.tax/join`: one application and one verified PTIN for every Pool on the door | the operator's |
| Roster, verification, dispatch, payouts | the brand's | the operator's |
| Rules and pay | the brand's rows, and its `pay` per role | the brand's rows, and `pay` at or above the operator's published minimum, $200 |
| Placement | none | $20.00 a filled review, never out of the accountant's $250 |
| Plan | Team: a door your account operates | Launch: a Pool another operator runs |

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

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

[Importing a Pool](https://services.dev/docs/people/pool/share.md#import-a-pool-another-operator-runs), [Pool()](https://services.dev/docs/people/pool.md) and [Eligibility](https://services.dev/docs/people/pool/eligibility.md) cover the keys.

---

- Up: [The tax example](https://services.dev/docs/examples/tax.md)
- Previous: [The rules table](https://services.dev/docs/examples/tax/rules.md)
- Next: [The season](https://services.dev/docs/examples/tax/season.md)
