# Check a voice clip

Send a voice clip to a check, follow its job, then read its verdict and each window's reading.

## How a voice check runs

A voice clip is a job, as a video is. `POST /audit` answers 202 at once with its `id` and `media: "audio"`, and you poll [`GET /audit/{id}`](/docs/api-reference/get-check) until its `status` is `succeeded` or `failed`. The statuses and the polling rhythm are a video's, as [Check and optimize a video](/docs/guides/check-and-optimize-a-video) describes.

Send exactly one of `audio_url` or `audio_upload_id`, as an MP3, WAV or M4A. A clip on disk goes through [an upload](/docs/guides/upload-a-local-file) with its audio `content_type`. A voice clip is only checked. `POST /optimize` refuses one with `unsupported_media`.

## Send the length

Pass `seconds`, the clip's length, when you know it. Credits are held for that length, and only that much of a longer clip is read. Without it, credits for the longest clip are held, and what was read is charged once the job finishes. A voice clip takes the [video limits](/docs/credits-and-limits#video-limits) and costs what a video check costs.

## Check a voice clip

**Check a voice clip by URL**

```bash title="cURL"
curl -X POST "https://realpng.com/api/v1/audit" \
  -H "X-API-Key: $REALPNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "https://audio.example.com/voice-note.mp3",
    "seconds": 18
  }'
```

```javascript title="JavaScript"
const res = await fetch("https://realpng.com/api/v1/audit", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.REALPNG_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "audio_url": "https://audio.example.com/voice-note.mp3",
    "seconds": 18
  }),
});
const data = await res.json();
```

```python title="Python"
import os

import requests

res = requests.post(
    "https://realpng.com/api/v1/audit",
    headers={"X-API-Key": os.environ["REALPNG_API_KEY"]},
    json={
        "audio_url": "https://audio.example.com/voice-note.mp3",
        "seconds": 18,
    },
)
data = res.json()
```

Response `202 Accepted`

```json
{
  "id": "9a4c2e7f-1b6d-4e8a-b3f5-0d7c9e2a6b18",
  "status": "queued",
  "media": "audio"
}
```

Then poll the check until it finishes.

**Get the voice clip's check**

```bash title="cURL"
curl "https://realpng.com/api/v1/audit/9a4c2e7f-1b6d-4e8a-b3f5-0d7c9e2a6b18" \
  -H "X-API-Key: $REALPNG_API_KEY"
```

```javascript title="JavaScript"
const res = await fetch("https://realpng.com/api/v1/audit/9a4c2e7f-1b6d-4e8a-b3f5-0d7c9e2a6b18", {
  headers: {
    "X-API-Key": process.env.REALPNG_API_KEY,
  },
});
const data = await res.json();
```

```python title="Python"
import os

import requests

res = requests.get(
    "https://realpng.com/api/v1/audit/9a4c2e7f-1b6d-4e8a-b3f5-0d7c9e2a6b18",
    headers={"X-API-Key": os.environ["REALPNG_API_KEY"]},
)
data = res.json()
```

Response `200 OK`

```json
{
  "id": "9a4c2e7f-1b6d-4e8a-b3f5-0d7c9e2a6b18",
  "status": "succeeded",
  "verdict": "ai",
  "score": 91,
  "decided_by": "voice",
  "lanes": {
    "voice": {
      "verdict": "ai",
      "score": 91
    },
    "provenance": {
      "verdict": "nothing",
      "issuer": null
    }
  },
  "media": "audio",
  "audio": {
    "seconds": 18,
    "scored_seconds": 18,
    "readings": [
      {
        "t": 0,
        "score": 89
      },
      {
        "t": 4.038,
        "score": 92
      },
      {
        "t": 8.075,
        "score": 91
      },
      {
        "t": 12.113,
        "score": 90
      }
    ]
  }
}
```

One voice detector reads the clip in 4 second windows, and the clip's reading is the median of the windows'. A `score` under 30 reads `real`, from 50 it reads `ai`, and between them `uncertain`. A valid C2PA claim decides first: a signed recording reads `real` and a signed AI claim reads `ai`, whatever the detector reads.

`decided_by` is `voice` when the detector decides and `provenance` when a signature does. `lanes` has `voice`, the detector's reading, and `provenance`, with no watermark lane. `audio` adds the clip's length and each window's reading.

| Field                  | Description                                         |
| ---------------------- | --------------------------------------------------- |
| `audio.seconds`        | The clip's length in seconds.                       |
| `audio.scored_seconds` | How much of it was read, from the start.            |
| `audio.readings`       | Each window's start `t` in seconds and its `score`. |

## What a voice check cannot tell

- A clip played through a speaker and recorded again can read as a real voice.
- Edited real audio, such as a pitch shift or heavy noise, can read as AI.
- Voices from Google and Microsoft are not in our test sets yet.
- The detector was built for speech. Music and silence get a reading it was never tested on.
