---
title: "Intake and request lists"
url: https://services.dev/docs/service/intake
captured: [intake-tabs.txt, legal-walk.txt, service-intake.txt, tax-check.txt]
codes: [ask_expired, input_invalid, needs_the_party]
---
# Intake and request lists

URL: https://services.dev/docs/service/intake

> Intake is steps at the top of the graph. Consent comes first, then the terms, then a request list your code derives from the job and its subject. Each item is answered, waived with a reason or substituted, and a step can start on one item while the rest are still open.

Intake answers one question: what must the client give before the work can start, and what may start before they have given it all?

## Smallest form

There is no intake key. Preconditions are [ask steps](https://services.dev/docs/service/ask.md) at the top of the graph, and the request list is a function of the job:

```ts title="services/annual-accounts.ts"
    consent: { ask: 'client', to: 'consent' },
    terms: { ask: 'client', to: 'sign', how: 'esign' },
```

```txt
→ POST /annual-accounts {"client":{"name":"Ada Lovelace","email":"ada@example.com"},"company":"acme","kind":"company","max_usd":90,"year":"2025","opened":"payroll","key":"books-2025"}
```

```txt title="captured/service-intake.txt · magic values: none"
← job_7Hq2 · waiting · on party · $90.00 held · consent · consent
```

## Every form

**On an ask step**

| Key | Written | Left out | Does |
|---|---|---|---|
| `ask` | `'buyer' \| <party input>` | required | Who acts: the buyer, or a `party`, `party?` or `party[]` input. |
| `to` | `AskTo` | required | What the party does: `'sign'`, `'consent'`, `'answer'`, `'upload'`, `'decide'`, `'direct'` or `'grant'`. |
| `items` | `(job) => AskItem[]` | none | For `answer` and `upload`: a request list derived from the job. A step can start on one item: `after: '<ask>.<item>'`. |
| `expires` | `Within` | `'7d'` | When the link stops working; a second expiry lapses the job. |
| `remind` | `'${number}d'[]` | [`'1d'`] | Reminders, each this long before the link expires. |

**Each item of a request list**

| Key | Written | Left out | Does |
|---|---|---|---|
| `id` | `string` | required | Its name: a step can start on it with `after: '<ask>.<item>'`. |
| `label` | `string` | required | The question or the document asked for, as the party reads it. |
| `optional` | `true` | none | The ask is done without it. |
| `remind` | `'${number}d'[]` | none | Reminders for this item alone, each this long before the link expires, while the item is still open. |
| `from` | `string` | none | Where it comes from, as the party reads it: `on the 2025 return`. The customer portal shows it beside the item. |

**What the party sends for a list: `POST /asks/:id`, through their link**

| Key | Written | Left out | Does |
|---|---|---|---|
| `items` | `Record` | none | A request list's items: each answered (`answer` or `file`), waived with a reason, or substituted. |
| `decline` | `unknown` | none | The party says no. A decline ends the job at `declined`. |
| `reason` | `unknown` | none | Why, with a decline. |

## Consent first, then the terms

The job waits on the client from the first step. Each ask is their own link, and neither needs an account. Their time on it never counts against your [deadline](https://services.dev/docs/service/within.md).

```txt
→ POST /asks/ask_7Hq3?t=rE5VINsEvPPB93bDQLooDc {}   # terms · sign
```

```txt title="captured/service-intake.txt · magic values: none"
  ask     ask_7Hq4 · organizer · upload · expires 2026-11-01T14:02:11.000Z
  item    bank · Statements for the bank account, 2025 · open · remind 2d
  item    payroll · Statements for the payroll account, 2025 · open · remind 2d · opened this year
```

## The list comes from the subject

`items` is your code, run on the job. Here it reads last year's accounts off the [subject](https://services.dev/docs/service/subject.md) and adds the one the client opened since, so this year's list writes itself. Each item can carry its own reminders and a `from` the client reads beside it:

```txt
→ POST /asks/ask_7Hq6?t=j-Rd4ngI-U2rfgStAvuMN_ {}   # terms · sign
```

```txt title="captured/service-intake.txt · magic values: none"
  ask     ask_7Hq7 · organizer · upload · expires 2026-11-01T14:02:11.000Z · from 2025, job_7Hq2
  item    bank · Statements for the bank account, 2026 · open · remind 2d
  item    payroll · Statements for the payroll account, 2026 · open · remind 2d
  item    card · Statements for the card account, 2026 · open · remind 2d · opened this year
```

A repair can re-ask only some items: a rejection routed `{ to: '<ask>', items }` asks again for just what its code names ([One submission per element](https://services.dev/docs/service/each.md#one-rejects-the-others-stay-filed)).

The open list, on every surface:

**CLI**

```bash title="CLI"
npx services.dev jobs get job_7Hq2 --json   # its wait and its open request list
```

```txt title="captured/intake-tabs.txt · magic values: none"
  "id": "job_7Hq2",
  "status": "waiting",
  "on": "party",
    "id": "ask_7Hq4",
    "step": "organizer",
    "to": "upload",
    "status": "open",
        "id": "bank",
        "status": "open",
        "id": "payroll",
        "status": "open",
        "from": "opened this year"
```

**API**

```bash title="API"
curl http://localhost:8787/jobs/job_7Hq2   # its wait and its open request list
```

```txt title="captured/intake-tabs.txt · 200 · magic values: none"
  "id": "job_7Hq2",
  "status": "waiting",
  "on": "party",
    "id": "ask_7Hq4",
    "step": "organizer",
    "to": "upload",
    "status": "open",
        "id": "bank",
        "status": "open",
        "id": "payroll",
        "status": "open",
        "from": "opened this year"
```

**MCP**

```txt title="MCP"
→ tools/call get_job {"id":"job_7Hq2"}   # its wait and its open request list
```

```txt title="captured/intake-tabs.txt · magic values: none"
  "id": "job_7Hq2",
  "status": "waiting",
  "on": "party",
    "id": "ask_7Hq4",
    "step": "organizer",
    "to": "upload",
    "status": "open",
        "id": "bank",
        "status": "open",
        "id": "payroll",
        "status": "open",
        "from": "opened this year"
```

**SDK**

```ts title="SDK"
await lingua.jobs.get("job_7Hq2")   // its wait and its open request list
```

```txt title="captured/intake-tabs.txt · magic values: none"
  "id": "job_7Hq2",
  "status": "waiting",
  "on": "party",
    "id": "ask_7Hq4",
    "step": "organizer",
    "to": "upload",
    "status": "open",
        "id": "bank",
        "status": "open",
        "id": "payroll",
        "status": "open",
        "from": "opened this year"
```

An agent reads the list and carries the link to the client, who answers through it.

## Start on one item

`after: '<ask>.<item>'` starts a step as soon as that item is in, while the rest are still open:

```ts title="services/annual-accounts.ts"
    reconcile: { by: async (_, job) => ({ accounts: accounts(job) }), after: 'organizer.bank' },
```

```txt
→ POST /asks/ask_7Hq7?t=Veld6gxJn8YTVqzW-IuUdK {"items":{"bank":{"file":"bank-2026.pdf"}}}   # organizer · upload
```

```txt title="captured/service-intake.txt · magic values: none"
← job_7Hq3 · waiting · on party · $90.00 held
  record  consent · client · consent | terms · client · sign · esign | screen · code | organizer.bank · answered | reconcile · code
```

## Waive and substitute

An item the client can't send is waived with a reason, or substituted with what they have. Either way the list is done, and the record says which:

```txt
→ POST /asks/ask_7Hq7?t=Veld6gxJn8YTVqzW-IuUdK {"items":{"payroll":{"waive":"The payroll account closed in March 2025."},"card":{"substitute":"A ledger export of the card account"}}}   # organizer · upload
```

```txt title="captured/service-intake.txt · magic values: none"
← job_7Hq3 · delivered · $90.00 charged
  record  consent · client · consent | terms · client · sign · esign | screen · code | organizer.bank · answered | reconcile · code | organizer.payroll · waived | organizer.card · substituted | organizer · client · upload | summary · ai | review · ai · pass
```

## Screen, then refer out

A step at the top can route the job before any work: here a screen sends a kind of client the brand doesn't take to a declared end that charges $0.

```txt
→ POST /annual-accounts {"client":{"name":"Ada Lovelace","email":"ada@example.com"},"company":"helping-hands","kind":"charity","max_usd":90,"year":"2026","key":"books-charity"}
```

```txt title="captured/service-intake.txt · magic values: none"
← job_7Hq4 · waiting · on party · $90.00 held · consent · consent
→ POST /asks/ask_7Hq8?t=bpNrN7KRd_tVwQ97uaCGlt {}   # consent · consent
→ POST /asks/ask_7Hq9?t=TS_n-HMFWeuUfAgAcvC1gx {}   # terms · sign
← job_7Hq4 · ended · referred_out · $0
  record  consent · client · consent | terms · client · sign · esign | screen · code | referred_out · ended
```

A client who declines consent ends the job at `declined`, and owes nothing.

## Seven surfaces

| Op | API | CLI | MCP | SDK | Site | Docs | App |
|---|---|---|---|---|---|---|---|
| `job.get` | `GET /jobs/:id` | `jobs get <job>` | `get_job` | `jobs.get()` |  | 1 error page | customer portal |
| `ask.get` | `GET /asks/:id` | `asks get <ask>` | never: a person acts | never: a person acts |  | 1 error page | hosted link, owner console |
| `ask.complete` | `POST /asks/:id` |  | never: a person acts | never: a person acts |  | 6 error pages | hosted link |
| `ask.reissue` | `POST /asks/:id/reissue`, `POST /asks/:id/link` | `asks reissue <ask>` | `reissue_ask` | `asks.reissue()` |  | 3 error pages | customer portal, owner console |

Objects: `ask_`.
Events: `ask.opened`, `item.done`, `ask.reminded`, `ask.done`, `ask.expired`, `ask.voided`, `ask.relinked`, `consent.given`, `job.paused`, `job.ended`.

[Operations](https://services.dev/docs/reference/operations.md) has every column of every row.

The customer portal lists every open ask and item across jobs, with each item's source, under Outstanding items ([The customer portal](https://services.dev/docs/app/buyers.md)).

## Refusals

| Code | Category | HTTP | Why |
|---|---|---|---|
| [`ask_expired`](https://services.dev/docs/reference/errors.md#ask_expired) | conflict | 410 | This ask expired. |
| [`needs_the_party`](https://services.dev/docs/reference/errors.md#needs_the_party) | blocked | 403 | Only the party can do this, through their own link. |
| [`input_invalid`](https://services.dev/docs/reference/errors.md#input_invalid) | invalid_request | 422 | The order doesn't match the Service's input. |

## In the example brands

The lines that use it in the example brands, as their files write them, and what `check` read aloud for each file.

```ts title="legal · services/trademark-response.ts · 21 lines"
    evidence: { ask: 'client', to: 'upload', items: () => [{ id: 'specimen', label: 'A specimen showing the mark in use' }] },
```

```txt title="npx services.dev check · captured/legal-walk.txt"
services/trademark-response.ts · 21 lines · $349 per job, within 48 hours, charged on file's receipt.
  steps   consent · client · consent → read · ai · cites source → evidence · client · upload → draft · ai → attack · ai · adversarial · 3 lenses → respond · attorney · * · stamped · 2-item checklist → file · USPTO → fee · USPTO · routed
```

[The legal example](https://services.dev/docs/examples/legal.md) runs every one of its files, captured.

```ts title="tax · services/annual-return.ts · 45 lines"
    organizer: { ask: 'owner', to: 'upload', items: requestList, expires: '180d' },
    file: {
      submit: efile, to: 'IRS and states', receipt: 'receipts', each: { of: 'jurisdictions', lead: j => j === 'US' },
      rejected: { ein_mismatch: { to: 'organizer', items: reask.ein_mismatch }, schedule_missing: { to: 'organizer', items: reask.schedule_missing }, math: 'draft', '*': 'prepare' }, perfect: '10d',
    },
```

```txt title="npx services.dev check · captured/tax-check.txt"
services/annual-return.ts · 45 lines · $1,800 per job, filed 5 days before its deadline, 20% off if late, or we pay the penalty and its interest, up to $5,000, after we ask the IRS to take it off, charged when file is accepted.
  steps   consent · owner · consent · §7216, may disclose to a preparer outside the US and a lender you name → organizer · owner · upload → compute · code · cites depreciation and carryforward schedules → draft · ai · cites the workpapers and the records the organizer took → check · ai · adversarial · 3 lenses → sign · signer · * · stamped in the paid-preparer block · 3-item checklist → authorize · owner · sign · Form 8879-CORP or 8879-PE → file · IRS and states → prepare · preparer · * · 1-item checklist · routed → tentative · code · cites the year as the ledger stands, less the estimates paid · routed → pay · Treasury and states · routed → extend · IRS and states · routed
```

[The tax example](https://services.dev/docs/examples/tax.md) runs every one of its files, captured.

The tax example's organizer builds its list the same way: what last year's return carried, from `job.subject.prior('compute')`; the year's estimates to confirm, from `job.subject.fact('paid', { period, all: true })`; and an account number for each state. [Annual return](https://services.dev/docs/examples/tax/annual-return.md) runs consent, a year's request list and the re-asks a rejection sends back to it.

---

- Up: [Service()](https://services.dev/docs/service.md)
- Previous: [Grants and decisions](https://services.dev/docs/service/grants.md)
- Next: [Sending to outside systems](https://services.dev/docs/service/submit.md)
