---
title: "Another Service as a step"
url: https://services.dev/docs/service/nested
captured: [examples.txt]
---
# Another Service as a step

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

> Import one of your Services and make it a step. It is ordered the way an agent orders it, at its price, and keeps its own job and ledger.

A nested Service answers one question: which part of this work is already a Service you sell?

## Smallest form

```ts title="services/translated-summary.ts"
import translation from './translation.ts'
  deliver: { translate: translation, summarize: 'ai' },
```

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

```txt title="captured"
  steps   translate · Translation → summarize · ai → review · ai · adversarial
```

## Every form

**On the Service**

| Key | Written | Left out | Does |
|---|---|---|---|
| `deliver` | `Deliver` | `'ai'`, briefed by services/&lt;id>.md | Who does the work: `'ai'`, a person or a role word, a URL, your function, or named steps in order. |

Another of your Services, ordered the way an agent orders it: at its price, with this job's id as the key.

## Ordered like any buyer would

The step orders your Translation at its price, with this job's id as the key, so a retry never orders it twice. The nested job keeps its own id, record and ledger, and this job pays it:

```bash
npx services.dev translated-summary document=report.pdf to=fr-CA --max 79
```

```txt title="captured"
job_7Hv5 · working · $79.00 held
job_7Hv5 · delivered · report.fr-CA.pdf · summary.pdf · $79.00 charged
  record  translate · service · job_7Hq6 · $49.00 | summarize · ai | review · ai · pass
  ledger  +$79.00 · AI $0.84 · your Translation $49.00 · you $29.16
  brand   +$79.00 · AI $1.68 · you $77.32 across job_7Hv5 and job_7Hq6
```

The `ledger` line is this job's: it paid $49 to your Translation. The `brand` line adds both jobs up, because the $49 stayed with you.

## The input must fill the order

This job's input must have everything the nested Service needs. TypeScript says so before anything runs, as the refusals below show.

## Margin

`check` counts the nested price as a cost of this Service, so `price_below_cost` fails one priced below what it orders.

## Seven surfaces

| Op | API | CLI | MCP | SDK | Site | Docs | App |
|---|---|---|---|---|---|---|---|
| `service.order` | `POST /jobs`, `POST /:service` | `<service> k=v …` | `order_<service>` | `<service>.order()` | `/<service>`: the order form | 10 error pages | customer portal |

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

## Refusals

| `check` gate | Why |
|---|---|
| [`price_below_cost`](https://services.dev/docs/reference/check/price_below_cost.md) | A delivered job could lose money: payout, nested Services and the AI cap add up to more than the price. |

| Written | What TypeScript says |
|---|---|
| `input: { document: 'file' }, output: { document: 'file' }, deliver: { translate: translation }, price: 99` | `Property 'to' is missing in type '{ readonly document: FileRef; }' but required in type '{ readonly document: FileRef; readonly to: string; }'.` |

---

- Up: [Service()](https://services.dev/docs/service.md)
- Previous: [Sourced output](https://services.dev/docs/service/sourced.md)
- Next: [Propose, then the gate commits](https://services.dev/docs/service/gate.md)
