---
title: "The job lifecycle"
url: https://services.dev/docs/service/lifecycle
---
# The job lifecycle

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

> Every status a job can be in, what it waits on, and every move between them the engine made in a captured run.

A job is always in one of six statuses, replayed from its [record](https://services.dev/docs/service/record.md) and never stored beside it. Each is entered by a record event, and the event's own line in the catalog says what it means.

| Status | Entered by | Means | Reached in a captured run |
|---|---|---|---|
| `working` | `job.ordered`, `step.committed`, `receipt.timed_out`, `signal.raised`, `job.sent_back` | A buyer, or another of your Services, ordered the job at its pinned price, with their metadata. | yes |
| `waiting` | `job.paused` | The work paused on a person: an approval, a signature or their step; or on a party's ask, its clock paused. | yes |
| `delivered` | `job.delivered` | The output is ready for the buyer. | yes |
| `accepted` | `job.accepted` | The buyer accepted, or 7 days passed after delivery. Final. | yes |
| `canceled` | `job.canceled` | The job stopped: the buyer canceled, the AI cap ran out, or a step failed. The buyer pays $0. | yes |
| `ended` | `job.ended` | The job reached an end: lapsed, or one the Service declared, with what it owes there. An end is forever. | yes |

`ended`: at `lapsed`, `declined`, or an end the Service declared. Accepted and canceled are statuses of their own.

## Waiting

What a waiting job waits on: a person's approval, signature or step, a Task's claim, a party's ask, an outside system, or the client's direction.

| `on` | Reached in a captured run |
|---|---|
| `approval` | yes |
| `signature` | yes |
| `person` | yes |
| `claim` | no |
| `party` | yes |
| `outside` | yes |
| `direction` | no |

## Ends

The ends every job has. 'accepted' ends the work, so the job is delivered for the buyer to accept; 'canceled' stops it at $0; 'lapsed' is the clock's, after an ask expires twice; and 'declined' is where a party's decline ends it. Both charge only the paid acts committed: a person who attested is never unpaid. Declare `declined` in `ends` to charge it otherwise. A Service's own [ends](https://services.dev/docs/service/ends.md) join them.

| End | Reached in a captured run |
|---|---|
| `accepted` | yes |
| `canceled` | yes |
| `lapsed` | yes |
| `declined` | yes |

A canceled job's reason is one of `buyer`, `ai_cap`, `step_failed`, `ended`, `declined`, `unfilled`. `ended`: a step's `next` sent it to the `canceled` end. `declined`: a party declined an ask. `unfilled`: no member claimed its Task before the ladder's end.

## Every move a captured run made

Each line is a status, the record event that moved it, and the status after.

```txt title="magic values: client.email = declines@example.test, client.email = silent@example.test, metadata.sandbox.outside = never"
new → job.ordered → working
working → job.delivered → delivered
working → job.ended → ended · declined
working → job.paused → waiting · approval
working → job.paused → waiting · outside
working → job.paused → waiting · party
working → job.paused → waiting · person
working → job.paused → waiting · signature
waiting · approval → step.committed → working
waiting · outside → receipt.timed_out → working
waiting · party → job.ended → ended · lapsed
waiting · party → step.committed → working
waiting · person → job.canceled → canceled
waiting · person → job.ended → ended · unreadable
waiting · person → job.ended → ended · withdrawn
waiting · person → signal.raised → working
waiting · person → step.committed → working
waiting · signature → step.committed → working
delivered → job.accepted → accepted
delivered → job.sent_back → working
```

---

- Up: [Service()](https://services.dev/docs/service.md)
- Previous: [How a job ends](https://services.dev/docs/service/ends.md)
- Next: [Keeping time](https://services.dev/docs/service/time.md)
