> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coval.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload Conversation Data

> Transcript and audio formats for uploading conversations to Coval for evaluation.

This reference covers the transcript and audio formats Coval accepts when you submit an [uploaded conversation](/concepts/uploaded-conversations/overview) for evaluation.

### Required Fields

<Info>
  **Essential transcript fields:**

  * **`role`**: Must be one of `"user"`, `"assistant"`, `"system"`, or `"tool"`
  * **`content`**: The actual message content (string)
  * **`beginning`**: Index position in the conversation (number)
  * **`end`**: End position in the conversation (number)
</Info>

### Optional Fields

* **`start_timestamp`**: Unix timestamp for when the message started (number)
* **`end_timestamp`**: Unix timestamp for when the message ended (number)
* **`error`**: Error message if transcription failed (string)
* **`transcriptionError`**: Boolean flag indicating transcription error
* **`name`**: Name identifier for the message (string)

## Supported Formats

<Tabs>
  <Tab title="OpenAI Format (Recommended)">
    The system primarily expects transcripts in OpenAI's chat completion format:

    ```json theme={null}
    [
      {
        "role": "user",
        "content": "Hello, I would like assistance.",
        "start_time": 0.0,
        "end_time": 3.2
      },
      {
        "role": "assistant", 
        "content": "Of course! How can I help you today?",
        "start_time": 3.2,
        "end_time": 6.8
      },
      {
        "role": "user",
        "content": "I'm having an issue with my recent order.",
        "start_time": 6.8,
        "end_time": 10.5
      },
      {
        "role": "assistant",
        "content": "I'm sorry to hear that. Could you provide me with your order number?",
        "start_time": 10.5,
        "end_time": 14.2
      }
    ]
    ```
  </Tab>

  <Tab title="Extended Studio Format">
    For detailed transcripts with timing information:

    ```json theme={null}
    [
      {
        "role": "user",
        "content": "Hello, I would like assistance.",
        "start_time": 0.0,
        "end_time": 3.2,
        "beginning": 0,
        "end": 1,
        "start_timestamp": 1640995200,
        "end_timestamp": 1640995210
      },
      {
        "role": "assistant",
        "content": "Of course! How can I help you today?",
        "start_time": 3.2,
        "end_time": 6.8,
        "beginning": 1,
        "end": 2,
        "start_timestamp": 1640995210,
        "end_timestamp": 1640995220
      }
    ]
    ```
  </Tab>

  <Tab title="Raw Text Format">
    The system can also accept raw text, which will be automatically converted:

    ```
    User: Hello, I would like assistance.
    Assistant: Of course! How can I help you today?
    User: I'm having an issue with my recent order.
    Assistant: I'm sorry to hear that. Could you provide me with your order number?
    ```
  </Tab>
</Tabs>

## Tool Call Messages

For tool call messages, the `content` field should contain a JSON string that can be parsed to extract tool information.

### Tool Call Content Examples

<CodeGroup>
  ```json Simple Tool Call theme={null}
  {
    "role": "tool",
    "content": "{\"tool\": \"waiting_on_customer\"}",
    "start_time": 12.0,
    "end_time": 12.5,
    "beginning": 3,
    "end": 4
  }
  ```

  ```json Tool Call with Arguments theme={null}
  {
    "role": "tool", 
    "content": "{\"query\": \"search term\", \"tool\": \"query_knowledge\"}",
    "start_time": 15.2,
    "end_time": 15.8,
    "beginning": 4,
    "end": 5
  }
  ```

  ```json Standard Tool Call Format theme={null}
  {
    "role": "tool",
    "content": "{\"tool_call\": \"function_name\", \"arguments\": {\"param1\": \"value1\"}}",
    "start_time": 18.5,
    "end_time": 19.1,
    "beginning": 5,
    "end": 6,
    "name": "function_name"
  }
  ```

  ```json System Role with Tool Call theme={null}
  {
    "role": "system",
    "content": "{\"tool_call\": \"database_query\", \"arguments\": {\"table\": \"users\"}}",
    "start_time": 22.0,
    "end_time": 22.3,
    "beginning": 6,
    "end": 7
  }
  ```
</CodeGroup>

### Alternative Tool Call Formats

The system supports these formats in the `content` field:

1. **Function format**: `{"function": "name", "arguments": {...}}`
2. **Tool format**: `{"tool": "name", ...}` (other fields become arguments)
3. **Custom backend format**: `{tool_call: name, arguments: {...}}`

## Validation Rules

### Content Limits

The request body is capped at **10 MB**, covering the transcript, any inline base64 `audio`, and the rest of the payload together. Individual messages and message counts are not capped separately.

Audio sent out of band — `upload_id`, `audio_url`, or `audio_reference` — is bounded by the [audio limits](#audio-requirements) rather than by the request body.

### Role Validation

* Only `"user"`, `"assistant"`, `"system"`, and `"tool"` roles are accepted
* Each message must have `role`, `content`, `start_time`, and `end_time` fields
* `start_time` and `end_time` must be float values representing seconds

### Role Normalization

For evaluation purposes, roles may be normalized:

* `"system"` messages with tool call content may be treated as `"tool"` for display purposes
* Tool calls in `"system"` role are automatically detected and parsed
* The UI will display tool calls with appropriate icons and formatting regardless of the original role

### Timing Validation

* `beginning` and `end` values should be sequential integers
* `start_timestamp` and `end_timestamp` should be valid Unix timestamps
* If timestamps are provided, `end_timestamp` should be greater than `start_timestamp`

### Audio Requirements

| Limit             | Value      |
| ----------------- | ---------- |
| Maximum file size | 250 MB     |
| Maximum duration  | 60 minutes |
| Minimum duration  | 5 seconds  |
| Formats           | WAV, MP3   |

Whichever limit binds first applies. An hour of 16 kHz stereo audio is roughly 230 MB, so a full-length call fits within the size limit; narrowband telephony recordings are considerably smaller.

Endpoints that issue an upload URL report the size limit as `max_size_bytes`, so you can check a file before transferring it rather than finding out from a rejected upload.

Both stereo and mono audio files are supported. Stereo is recommended when available because speaker roles are assigned deterministically from channel position; mono roles are inferred from transcript content.

**Stereo (recommended):** Upload audio with the agent and user on separate channels. Channel position determines role:

| Channel   | Position | Role  |
| --------- | -------- | ----- |
| Channel 0 | Left     | Agent |
| Channel 1 | Right    | User  |

**Mono:** Upload a single-channel file. Roles are assigned by classifying the transcript content with an LLM — typically accurate, but less reliable than channel-based stereo mapping for short or ambiguous conversations.

## Filtering out Coval simulation calls

If your pipeline uploads every call your agent handles, it also uploads the calls Coval's simulator placed to your agent. Those simulations are already evaluated inside their runs, so you may not want them duplicated in your conversations.

Coval can drop these uploads for you at submit time:

1. Read the `X-Coval-Simulation-Id` header that Coval delivers with every inbound simulation call. See [Identifying simulation calls](/concepts/agents/connections/inbound-voice#identifying-simulation-calls) for how the header reaches your agent on different connection types.
2. Store the header value with the call record, and pass it as `metadata.coval_simulation_id` when you submit the conversation.
3. Ask Coval to enable the simulation filter for your organization.

Once enabled, a submit whose `coval_simulation_id` matches a simulation in your organization returns HTTP 200 without creating a conversation:

```json theme={null}
{
  "filtered": true,
  "reason": "coval_simulation",
  "simulation_id": "CbnW6XcVKTv4gAZGRrXbut"
}
```

<Note>
  Filtered uploads are not billed and do not count against your conversation allowance. Submits without the metadata key, or whose value does not match a simulation, are processed normally, so the filter is safe to add to a pipeline that uploads simulation and production calls together.
</Note>
