---
title: POST /api/v1/jobs
description: Submit a computation 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).

Queue one tool run as an asynchronous job owned by the caller. The response carries the new job `id` and its initial `status`; read the job back with `GET /api/v1/jobs/{job_id}` until it reaches a terminal status.

## Request

#### Request body

- `tool_name` (string) —
Tool to run, e.g. `esmfold`.

- `tool_input_parameters` (object) —
The tool's input parameters.

- `job_title` (string) —
Human-readable title for the job.

- `project_id` (string (uuid)) —
Project to file the job under. You must have access to it.

- `chat_id` (string) —
Chat to attach the job to. You must own it.

##### Example

```json
{
  "tool_name": "esmfold",
  "tool_input_parameters": {
    "protein_sequence": "MKFLILLFNILCLFPVLAADNH"
  },
  "job_title": "ESMFold test"
}
```

## Responses

### `201` Created

Job successfully created and dispatched

Response shape:

- `id` (string (uuid)) —
Unique identifier for the created job. Use this to poll status or connect to WebSocket.

- `task_id` (string | null) —
Modal task ID. May be null initially if job is queued.

- `job_type` (string) —
Type of computation (echoed from request)

- `job_title` (string | null) —
Human-readable job title (echoed from request)

- `status` (string) —
Initial job status (typically 'pending')

- `created_at` (string (date-time)) —
Job creation timestamp

- `updated_at` (string (date-time)) —
Last update timestamp

- `message` (string) —
Human-readable status message

- `org_id` (string | null) —
Organization ID if provided

- `team_id` (string (uuid) | null) —
Team ID if provided

- `campaign_id` (string (uuid) | null) —
Campaign ID if provided

- `campaign_scope` (enum (&quot;org&quot; | &quot;team&quot; | &quot;user&quot;) | null) —
Campaign scope if provided

- `chat_id` (string | null) —
Chat ID if provided

- `credits_reserved` (number) —
Credits held from your balance for this job when it was submitted. A hold is not the final charge: the job is charged when it finishes, against this hold. Absent when no hold was placed (for example, on an unlimited plan); the job is still charged when it finishes. An `/api/v1/orchestrate` turn reports the holds of the jobs it submitted in `usage.gpu`.

### `400` Bad Request

Invalid job parameters or SMILES string

### `401` Unauthorized

Authentication required

### `402`

Insufficient credits for this job

### `403` Forbidden

Not authorized for this project

### `404` Not Found

Project not found

### `429` Too Many Requests

Rate limit exceeded - too many job submissions

### `500` Internal Server Error

Failed to create or dispatch job

**curl**

```bash
curl -X POST 'https://ivybiosciences.com/api/v1/jobs' \
  -H "Authorization: Bearer $IVY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "tool_name": "esmfold",
  "tool_input_parameters": {
    "protein_sequence": "MKFLILLFNILCLFPVLAADNH"
  },
  "job_title": "ESMFold test"
}'
```

**JavaScript**

```js
const res = await fetch('https://ivybiosciences.com/api/v1/jobs', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.IVY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "tool_name": "esmfold",
  "tool_input_parameters": {
    "protein_sequence": "MKFLILLFNILCLFPVLAADNH"
  },
  "job_title": "ESMFold test"
}),
});
const data = await res.json();
```

**Python**

```python
import os, requests

res = requests.post(
    "https://ivybiosciences.com/api/v1/jobs",
    headers={"Authorization": f"Bearer {os.environ['IVY_API_KEY']}"},
    json={
  "tool_name": "esmfold",
  "tool_input_parameters": {
    "protein_sequence": "MKFLILLFNILCLFPVLAADNH"
  },
  "job_title": "ESMFold test"
},
)
data = res.json()
```
