> For AI agents: the documentation index is at https://platform.detectif.ai/llms.txt. Every page is also available as Markdown by adding `.md` to its path.

# Analyse a call recording

`POST /v1/detect/file`

Analyses a recorded call as if it were live and returns the answer. Send a WAV file (PCM, float or G.711; 1 second to 15 minutes, at most 50 MB) as multipart/form-data in the `file` field, or as the request body. Options as query parameters or form fields: `call_id`, `language`, `remote_channel` (stereo files), `transcripts` (default true), `record` (`false` to not keep the recording). The file is replayed in real time, so the answer takes about as long as the recording: the response (200) starts at once, sends a newline every few seconds to keep the connection open, and ends with one JSON object, the result (`type: result`) or `{"type":"error",...}` if the analysis failed (then nothing is charged). File analyses use your account balance. Send an `Idempotency-Key` to make retries safe (24 h). Requires scope `noesis:detect`.

## Authentication

Send your API key as `Authorization: Bearer <your API key>`.

## Headers

| Name | Type | Required | Description |
|---|---|---|---|
| `Authorization` | string | yes | `Bearer <your API key>`. Keys are created in the dashboard; see [Authentication](https://platform.detectif.ai/docs/noesis/authentication/). |
| `Idempotency-Key` | string or null | no | Optional (recommended) key that makes retries safe for 24 h: a retry with the same key and the same request returns the stored response without charging again. (1 to 128 characters) |

## Request body

Send the request as `multipart/form-data`. Upload the recording as a WAV file in the `file` field (up to 50 MB and 15 minutes); send the other fields as form fields.

| Field | Type | Required | Description |
|---|---|---|---|
| `file` | file | yes | The WAV file (PCM, float or G.711; 1 s to 15 min; at most 50 MB). |
| `call_id` | string | no | Your id for the call. (at most 200 characters) |
| `language` | string | no | Language hint, e.g. en or hi. (at most 16 characters) |
| `remote_channel` | integer | no | Stereo files: the channel of the person called. (default `0`; one of `0`, `1`) |
| `transcripts` | boolean | no | Include the transcript. (default `true`) |
| `record` | boolean | no | Keep the recording and transcript for 30 days; false to not keep them. (default `true`) |

## Response

`200`: The analysis runs: newlines while it works, then one JSON object (this result, or {"type":"error","code","error","status"}).

| Field | Type | Required | Description |
|---|---|---|---|
| `type` | string | yes | (always `"result"`) |
| `session_id` | string | yes |  |
| `call_id` | string or null | no |  |
| `file` | object | yes |  |
| `first` | object or null | yes |  |
| `final` | object or null | yes |  |
| `timeline` | array of object | yes |  |
| `transcript` | array of object or null | no |  |
| `usage` | object or null | no |  |
| `operation_id` | string | yes |  |
| `billed_seconds` | number | yes |  |
| `credits` | object or null | no | What the analysis used from your balance. |
| `idempotent_replay` | boolean | yes |  |

### Example response

```json
{
  "type": "result",
  "session_id": "5b2f0c9e8d7a4b6c9e1f2a3b4c5d6e7f",
  "call_id": "crm-4711",
  "file": {
    "name": "call.wav",
    "duration_s": 42.5,
    "format": "pcm_s16le",
    "sample_rate": 8000,
    "channels": 1
  },
  "first": {
    "label": "voicemail",
    "category": "machine",
    "confidence": 0.88,
    "t": 3.1
  },
  "final": {
    "label": "voicemail",
    "category": "machine",
    "confidence": 0.95
  },
  "timeline": [
    {
      "seq": 1,
      "t": 3.1,
      "label": "voicemail",
      "category": "machine",
      "confidence": 0.88,
      "change": "initial",
      "reason": "A greeting asks to leave a message."
    }
  ],
  "transcript": [
    {
      "t": 0.8,
      "text": "Hi, you've reached Ada. Leave a message."
    }
  ],
  "usage": {
    "audio_s": 42.5,
    "transcribed_s": 42.5,
    "checks": 3
  },
  "operation_id": "op_6f1ed002ab5595859014ebf0951522d9",
  "billed_seconds": 42.5,
  "idempotent_replay": false
}
```

## Errors

| Status | Meaning |
|---|---|
| `400` | The request is invalid, for example an API key in the URL or an unsupported parameter. |
| `401` | The API key is missing, invalid or revoked. |
| `402` | Your balance is too low for this call or file. |
| `403` | The key lacks the required scope, the e-mail address is not verified, or the account is suspended. |
| `408` | The upload did not arrive in time. |
| `409` | A request with the same Idempotency-Key is still running. |
| `413` | The file is larger than 50 MB. |
| `415` | Not a WAV file. |
| `422` | The recording is too short or too long, or the Idempotency-Key was used for a different request. |
| `429` | Too many requests, or too many calls and file analyses at the same time. Wait for Retry-After seconds. |
| `500` | Something went wrong on our side. |
| `503` | Noesis is busy or temporarily unavailable. Retry after the Retry-After seconds. |

Error bodies use the shape described in [Errors](https://platform.detectif.ai/docs/noesis/errors/), with a stable `error.code`.

## Code samples

```bash
curl "https://api.noesis.detectif.ai/v1/detect/file" \
  -H "Authorization: Bearer $DETECTIF_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@call.wav"
```

```python
import os
import uuid

import requests

with open("call.wav", "rb") as f:
    resp = requests.post(
        "https://api.noesis.detectif.ai/v1/detect/file",
        headers={"Authorization": f"Bearer {os.environ['DETECTIF_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
        files={"file": f},
        timeout=300,
    )
print(resp.status_code, resp.json())
```

```javascript
import { readFile } from "node:fs/promises";
import { randomUUID } from "node:crypto";

const form = new FormData();
form.append("file", new Blob([await readFile("call.wav")]), "call.wav");

const res = await fetch("https://api.noesis.detectif.ai/v1/detect/file", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DETECTIF_API_KEY}`,
    "Idempotency-Key": randomUUID(),
  },
  body: form,
});
console.log(res.status, await res.json());
```
