---
title: "POST /v1/jobs/{jobId}/artifacts/verify"
description: Check output files against their SHA-256
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).

Computes the SHA-256 of each stored file you name and, when you give an `expected_sha256`, reports whether they match. Files are hashed one after another. Requires write access to the job, so a project viewer cannot use it.

Each `results` entry describes one item, in request order, and a problem with one file does not fail the request. A key you cannot read is reported as `error: "not_found"`, the same as a missing file. A file larger than 200 MiB (or the limit the server is configured with) is reported as `error: "object-too-large"` and not hashed. Items without a string `s3_key` are dropped, and a request left with no items returns 400.

Add `persist=true`, as a query parameter or in the body, to also save the results as verification records for the job; read them back with `GET /api/v1/jobs/{job_id}/artifacts/list-verifications`. A failure to save is not reported in the response.

## Request

#### Path parameters

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

#### Query parameters

- `persist` (enum (&quot;true&quot;)) —
Set to `true` to save the results as verification records. May instead be sent as `persist` in the body.

#### Request body

- `items` (object[]) —
The files to hash. Entries without a string `s3_key` are dropped.

- `persist` (enum (&quot;true&quot;)) —
Set to `true` to save the results as verification records. May instead be sent as a query parameter.

## Responses

### `200` OK

One result per submitted item, with a summary

Response shape:

- `ok` (enum (true)) —

- `summary` (object) —

#### summary properties

- `total` (integer) —

- `with_expected` (integer) —
Items that came with an `expected_sha256`

- `matched` (integer) —

- `mismatched` (integer) —

- `errors` (integer) —
Items that carry an `error`

- `results` (object[]) —

### `400` Bad Request

The body is not valid JSON, or no usable items were submitted

Response shape: `object`

### `401` Unauthorized

Authentication required

Response shape: `object`

### `404` Not Found

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

Response shape: `object`

### `429` Too Many Requests

Rate limit exceeded

Response shape: `object`

### `500` Internal Server Error

File storage is not configured, or verification failed unexpectedly

Response shape: `object`

**curl**

```bash
curl -X POST 'https://ivybiosciences.com/api/v1/jobs/{jobId}/artifacts/verify' \
  -H "Authorization: Bearer $IVY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "items": [
    {
      "s3_key": ""
    }
  ]
}'
```

**JavaScript**

```js
const res = await fetch('https://ivybiosciences.com/api/v1/jobs/{jobId}/artifacts/verify', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.IVY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "items": [
    {
      "s3_key": ""
    }
  ]
}),
});
const data = await res.json();
```

**Python**

```python
import os, requests

res = requests.post(
    "https://ivybiosciences.com/api/v1/jobs/{jobId}/artifacts/verify",
    headers={"Authorization": f"Bearer {os.environ['IVY_API_KEY']}"},
    json={
  "items": [
    {
      "s3_key": ""
    }
  ]
},
)
data = res.json()
```
