# Runs

Run history and control. Every run, from any key in your organization, is on record with its attempts, charges and routing reason.

## List runs

```text
GET /v1/runs
```

```bash
curl "https://api.jell.run/v1/runs?status=succeeded&capability=contact.find&limit=50" \
  -H "Authorization: Bearer $JELL_API_KEY"
```

| Query param | Notes |
| --- | --- |
| `status` | filter by lifecycle status (`succeeded`, `failed`, `no_match`, ...) |
| `capability` | filter by capability slug |
| `provider` | filter by the provider that served the run |
| `endpoint` | filter raw endpoint runs by endpoint path |
| `limit` | default 50, max 200; newest first |

Returns `{"items": [run, ...]}` where each run has the same shape as the [run response](/docs/api/run) minus `result`: a listing is the receipts (status, provider, charge, timing, attempts), and the payload of any one run comes from its `poll_url` (`GET /v1/runs/{run_id}`). That keeps a 200-row page small whatever the runs returned.

## Get one run

```text
GET /v1/runs/{run_id}
```

Poll this for runs that returned `202`; add `?wait=60` (max 120) to long-poll until the run finishes. `POST /v1/runs/{run_id}/cancel` stops a run that is still queued (`stoppable: true`); a run already at the provider cannot be stopped. A run that does not exist (or belongs to another organization) returns `invalid_request`.

## Cancel a run

```text
POST /v1/runs/{run_id}/cancel
```

Only runs that have not started executing (`created`, `reserved`, `queued`) can be cancelled. A run already `running` or finished returns `invalid_request` with the current status.

## History for a subject

```text
GET /v1/history?q=<subject>
```

Everything your organization has already done to one subject through Jell, derived from the run log: no second store, nothing to write. Pass an email, a domain, a LinkedIn URL, any URL, a social handle, a phone number or a name. The kind is detected from the value; force it with `kind` (`email`, `domain`, `linkedin`, `url`, `handle`, `phone`, `text`). Free.

```bash
curl "https://api.jell.run/v1/history?q=alex.rivera@example.com" \
  -H "Authorization: Bearer $JELL_API_KEY"
```

A run matches when the subject appears in its input or its result: the `contact.find` that produced the email, the `contact.verify` that checked it, the `email.send` that wrote to it. A domain query also matches emails at that domain and URLs on it; a LinkedIn query matches on the profile slug, whatever the URL's form.

| Field | Notes |
| --- | --- |
| `subject` | `query`, the detected `kind`, and the `normalized` form that was matched |
| `items` | matching runs, newest first: status, capability or raw endpoint, provider, charge, the run's `input`, and `matched` (where the subject was found: `in` input or result, the JSON `path`, `exact` when the value names the subject itself) |
| `touches` | the outbound runs among them (`email.send`, `linkedin.invite`, `linkedin.message`) with their `channel`; `last_touch` is the latest one that succeeded |
| `reusable` | successful paid lookups whose input named the subject: read their result with `GET /v1/runs/{id}` instead of buying it again |
| `by_status`, `by_capability`, `charged`, `first_seen`, `last_seen` | the summary |
| `hints` | what an agent should conclude: already contacted, a result to reuse, nothing on record |

`limit` (default 50, max 200) caps `items`; `truncated: true` says there were more. Only calls made through Jell by your organization are on record; anything done elsewhere is invisible here.

### Many subjects at once

```text
POST /v1/history
```

```bash
curl -X POST https://api.jell.run/v1/history \
  -H "Authorization: Bearer $JELL_API_KEY" -H "Content-Type: application/json" \
  -d '{"subjects": ["alex.rivera@example.com", "sam.lee@example.org"], "kind": "email"}'
```

The dedupe pass before a batch: for 1 to 200 subjects, one compact row each (`seen`, `count`, `last_seen`, `contacted`, `last_touch`, the first `reusable` result) plus `seen`, `unseen` and `contacted` totals. A subject that does not read as the given kind gets an `error` row instead of failing the batch.
