---
title: "POST /v1/jobs/{jobId}/lineage"
description: "Record a job's lineage"
full: true
---

**Auth:** required. Send an `ivy_` API key (`Authorization: Bearer ivy_…` or `X-Ivy-Api-Key`), a Clerk session JWT (`Authorization: Bearer …`) or the Clerk `__session` cookie (browser sessions). See [Authentication](/docs/api/authentication).

Records which outputs of other jobs fed a job you can write to. Each source names a producer job, one of its outputs (`producer_output_id`) and the input slot it filled.

Every producer job must be one you can read, and every `producer_output_id` must be an output of its producer job; otherwise the request returns 403 and nothing is recorded. A source without `producer_output_id` is skipped, and a request where every source lacks one returns 202 with a warning. A project viewer can read lineage but not record it; recording returns 404 for them, the same as for a job that does not exist.

With a project-scoped API key, the job and every producer job must be in one of the key's projects.

## Request

#### Path parameters

- `jobId` (string (uuid)) —
UUID of the consuming job.

#### Request body

- `sources` (object[]) —

##### Example

```json
{
  "sources": [
    {
      "producer_job_id": "00000000-0000-0000-0000-000000000001",
      "producer_output_id": "00000000-0000-0000-0000-000000000002",
      "input_slot": "protein_structure"
    }
  ]
}
```

## Responses

### `201` Created

Lineage recorded

Response shape:

- `success` (enum (true)) —

- `inserted` (integer) —
Rows recorded

### `202` Accepted

Accepted, but nothing was recorded; `warning` says why (no source carried `producer_output_id`, or lineage storage is unavailable)

Response shape:

- `accepted` (enum (true)) —

- `warning` (string) —

### `400` Bad Request

The job id is empty; the body has no `sources`; or a source is missing `producer_job_id` or `input_slot`, or has a `producer_output_id` that is `null` or empty

Response shape: `object`

### `401` Unauthorized

Authentication required

Response shape: `object`

### `403` Forbidden

A producer job is not one you can read (or is outside your API key's project scope), or an output is not an output of its producer job. Nothing is recorded.

Response shape: `object`

### `404` Not Found

The job does not exist, you cannot write to it, it is outside your API key's project scope, or the id is not a job UUID. All of these return the same body.

Response shape: `object`

### `429` Too Many Requests

Rate limit exceeded

Response shape: `object`

### `500` Internal Server Error

Recording lineage failed

Response shape: `object`

**curl**

```bash
curl -X POST 'https://ivybiosciences.com/api/v1/jobs/{jobId}/lineage' \
  -H "Authorization: Bearer $IVY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "sources": [
    {
      "producer_job_id": "00000000-0000-0000-0000-000000000001",
      "producer_output_id": "00000000-0000-0000-0000-000000000002",
      "input_slot": "protein_structure"
    }
  ]
}'
```

**JavaScript**

```js
const res = await fetch('https://ivybiosciences.com/api/v1/jobs/{jobId}/lineage', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.IVY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "sources": [
    {
      "producer_job_id": "00000000-0000-0000-0000-000000000001",
      "producer_output_id": "00000000-0000-0000-0000-000000000002",
      "input_slot": "protein_structure"
    }
  ]
}),
});
const data = await res.json();
```

**Python**

```python
import os, requests

res = requests.post(
    "https://ivybiosciences.com/api/v1/jobs/{jobId}/lineage",
    headers={"Authorization": f"Bearer {os.environ['IVY_API_KEY']}"},
    json={
  "sources": [
    {
      "producer_job_id": "00000000-0000-0000-0000-000000000001",
      "producer_output_id": "00000000-0000-0000-0000-000000000002",
      "input_slot": "protein_structure"
    }
  ]
},
)
data = res.json()
```
