---
title: "POST /v1/jobs/{jobId}/candidates"
description: Record study candidates for a job
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).

Adds candidates to a job you can write to, or updates the ones already recorded. A row is matched on `molecule_id`, `compound_id` and `source` together. Each row carries a `status` of `selected`, `defer`, `reject` or `retest`, which the route does not check against that list. The response reports how many rows were sent, not how many changed.

A project viewer cannot record candidates. With a project-scoped API key, a job outside the key's projects returns 403.

## Request

#### Path parameters

- `jobId` (string (uuid)) —
Job UUID.

#### Request body

- `rows` (object[]) —

##### Example

```json
{
  "rows": [
    {
      "molecule_id": "mol-123",
      "status": "selected",
      "reason": "Best docking score",
      "source": "manual"
    }
  ]
}
```

## Responses

### `200` OK

The rows were recorded

Response shape:

- `ok` (boolean) —

- `upserted` (integer) —
Number of rows sent

### `400` Bad Request

The job id is empty, or `rows` is missing or empty

Response shape: `object`

### `401` Unauthorized

Authentication required

Response shape: `object`

### `403` Forbidden

You cannot write to the job, or it is outside your API key's project scope

Response shape: `object`

### `429` Too Many Requests

Rate limit exceeded

Response shape: `object`

### `500` Internal Server Error

Recording candidates failed, or the body is not valid JSON

Response shape: `object`

**curl**

```bash
curl -X POST 'https://ivybiosciences.com/api/v1/jobs/{jobId}/candidates' \
  -H "Authorization: Bearer $IVY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "rows": [
    {
      "molecule_id": "mol-123",
      "status": "selected",
      "reason": "Best docking score",
      "source": "manual"
    }
  ]
}'
```

**JavaScript**

```js
const res = await fetch('https://ivybiosciences.com/api/v1/jobs/{jobId}/candidates', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.IVY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "rows": [
    {
      "molecule_id": "mol-123",
      "status": "selected",
      "reason": "Best docking score",
      "source": "manual"
    }
  ]
}),
});
const data = await res.json();
```

**Python**

```python
import os, requests

res = requests.post(
    "https://ivybiosciences.com/api/v1/jobs/{jobId}/candidates",
    headers={"Authorization": f"Bearer {os.environ['IVY_API_KEY']}"},
    json={
  "rows": [
    {
      "molecule_id": "mol-123",
      "status": "selected",
      "reason": "Best docking score",
      "source": "manual"
    }
  ]
},
)
data = res.json()
```
