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

# Chat audio inputs

> Prepare reusable audio files or a selected voice and script in a Chat draft.

Authenticate these GraphQL operations with
`Authorization: Bearer <APOB_API_KEY>` as described in
[authentication](https://developers.apob.ai/api-reference/authentication.md). Every selection is checked against
the authenticated account and its Chat session.

> [!NOTE]
>
> The Chat capabilities `talking_avatar`, `lip_sync`, and `generate_audio` currently
> prepare inputs only. Their schema returns `preparationOnly: true` and
> `submissionSupported: false`. Input readiness does not create a task, produce a
> quote, or charge credits. Existing direct
> [speech and avatar mutations](https://developers.apob.ai/api-reference/speech-and-avatars.md) retain their
> own generation contracts. Local implementation does not establish hosted availability.

You can prepare, edit, and validate these inputs while generation is unavailable.
A saved voice selection remains selected during follow-up requests; preparation
checks its current availability again. Explicit discussion and settings queries
do not validate or submit a draft.

Settings replies show the audio input mode and, for voice-script inputs, the
selected voice name and original script. Voice names are checked for current
access and readiness before display. A settings query does not change the saved
inputs or create a quote.

## Upload or select audio

Use the existing Chat upload sequence:

1. Create a session with `createChatSession(input: CreateChatSessionInput!)` if
   needed. The input requires a unique `clientRequestId`; `title` is optional.
2. Call `initChatUpload(input: InitChatUploadInput!)`. Supply `sessionId`, a unique
   `clientRequestId`, `fileName`, `mimeType`, the file's hexadecimal SHA-256, and
   `fileSize` in bytes. `runId` is optional before the first message.
3. Upload the bytes to the returned `uploadUrl` using HTTP PUT and the returned
   `headers`, before `expiresAt`.
4. Call `completeChatUpload(uploadId: ID!, runId: ID)` and read `chatUpload(uploadId: ID!)`.

Supported audio MIME types are `audio/mpeg`, `audio/mp4`, `audio/wav`,
`audio/x-wav`, `audio/vnd.wave`, `audio/ogg`, and `audio/flac`. The existing
200 MiB file-size limit applies. **Audio uploads have no duration limit.**
Completion validates the uploaded object and probes its actual duration. A failed
probe leaves the upload unusable; retry completion while the upload is available.
Generation-specific duration limits belong to the generation service when that
workflow is connected.

A ready `chatUpload` response is a JSON object with `fileType: "audio"`,
`fileName`, `durationMs`, `playbackUrl`, and an identity-only `asset`. Playback URLs
expire; read the metadata again to refresh them. Never persist signed URLs as an
input identity. `chatReferences(sessionId: ID!, references: [ChatAssetReferenceInput!]!)`
restores authorized attachment metadata, including audio playback and duration.

Existing generated audio remains a `MEDIA` resource. Query `chatAssets` with
`fileType: "audio"`, a session or run, and `source: "LIBRARY"`, `"HISTORY"`, or
`"COMMUNITY"`. Select the result explicitly before binding it to a draft.

## Select a voice

```graphql ChatVoiceModels theme={"system"}
query ChatVoiceModels($sessionId: ID!, $search: String) {
  chatVoiceModels(sessionId: $sessionId, source: "PERSONAL", search: $search)
}
```

The result is a `ChatJSON` object, so it has no GraphQL selection set.

| Argument | Type | Meaning |
| - | - | - |
| `sessionId` | `ID!` | An owned Chat session; a run is not required. |
| `runId` | `ID` | Optional owned run in that session. |
| `source` | `String!` | `PERSONAL` (default) or `COMMUNITY`. |
| `search` | `String` | Optional name search, at most 128 characters. |
| `pageNumber` | `Int!` | One-based page, default `1`. |
| `limit` | `Int!` | Page size from 1 to 50, default `20`. |

`pageNumber * limit` must not exceed 1,000. The response includes `items`,
`hasMore`, `pageNumber`, `limit`, and `source`. Items contain `modelId`, `name`,
`selectable`, and `unavailableReason`; an existing audio preview may also provide
`playbackUrl`. Browsing never generates a preview. Selection readiness is checked
again during input preparation, including whether the voice has a usable reference.

`items` contains at most `limit` voices. Availability filtering can produce a
shorter page even when `hasMore` is `true`; continue with the next `pageNumber`
using the same `limit`. The lookahead record used to determine `hasMore` is not
included in the current page.

## Save a draft

Use the existing `sendChatMessage.input.parameterPatch` or
`answerChatRun.input.parameterPatch` and `assetBindings`. Send the actual speech
as `voiceScript`, preserving its wording. The script must be nonblank and no more
than 8,000 characters. A voice model must be selected explicitly.

```json Voice-script parameter patch theme={"system"}
{
  "audioInputMode": "VOICE_SCRIPT",
  "voiceModelId": "<SELECTED_VOICE_MODEL_ID>",
  "voiceScript": "Welcome to our studio."
}
```

For file input, set `audioInputMode: "AUDIO_FILE"` and supply this binding:

```json Audio asset binding theme={"system"}
{
  "slotId": "inputAudio",
  "asset": { "source": "UPLOAD", "resourceType": "UPLOAD", "resourceId": "<UPLOAD_ID>" }
}
```

Talking Avatar also requires `inputImage`; Lip Sync also requires `inputVideo`.
Generate Audio accepts only the voice-script path and requires no visual input.
`chatWorkflowSchema(sessionId: ID!, workflowId: String!, runId: ID, parameters: ChatJSON,
assetBindings: [ChatAssetBindingInput!])` describes the current required fields,
slots, and preparation-only status.

Partial inputs remain editable. Missing or conflicting inputs return to the input
step. An explicit mode switch clears the previous mode's active inputs; uploaded
files and historical attachments are retained. Concurrently supplied conflicting
inputs still require correction: validation returns field `audioInputMode` with
reason `AUDIO_INPUT_CONFLICT`, including when a mode or visual input is missing.
Edits and undo retain the draft's exact script;
ordinary image-to-video, text-to-video, and Extend continue using dialogue in
their prompt fields.

## Create a reusable voice model

The separate `create_voice_model` Chat workflow creates one independent voice
model from **one** ready audio upload or authorized audio `MEDIA`. It supports a
complete confirmation and creation flow, including an audio preview. This does
not change the preparation-only limits of the three workflows described above.
Check `chatWorkflowSchema` on your deployment before offering the action.

| Parameter | Contract |
| - | - |
| `name` | Required, nonblank, at most 32 characters. |
| `description` | Optional preview speech, at most 512 characters. Whitespace is preserved in the draft. If omitted or blank, a self-introduction is generated. This is not a transcript of the reference recording. |
| `isPublic` | Boolean, defaults to `true`. Private creation requires an eligible account. Display the effective value for confirmation. |
| `gender` | Optional integer: `0` unspecified, `1` male, `2` female. |
| `language` | Optional nonblank language string, at most 128 characters. |

Bind the sample to `inputAudio`. Creating a voice does not require an existing
`voiceModelId`, `voiceScript`, or `audioInputMode`. Portrait association, multiple
samples, custom avatars, tags, and creating a voice from a text-only description
are not supported in this Chat workflow.

Example `sendChatMessage` input (the sample must already be ready):

```json theme={"system"}
{
  "sessionId": "<SESSION_ID>",
  "clientRequestId": "<UNIQUE_REQUEST_ID>",
  "text": "Prepare this voice model for my review.",
  "workflowId": "create_voice_model",
  "parameterPatch": {
    "name": "Studio narrator",
    "description": "Welcome to our studio.\nLet us begin.",
    "isPublic": false,
    "gender": 0,
    "language": "English"
  },
  "assetBindings": [{
    "slotId": "inputAudio",
    "asset": {
      "source": "UPLOAD",
      "resourceType": "UPLOAD",
      "resourceId": "<UPLOAD_ID>"
    }
  }]
}
```

For an existing recording, use the authorized `MEDIA` identity returned by the
asset picker. Keep that identity; do not substitute its temporary playback URL.

Incomplete input returns to the existing Chat input step. Continue with
`answerChatRun`, using the current `interruptId` and `baseVersion`. Schema
`uiHints.modelConstraints` contains advisory `used`, `maximum`, `remaining`, and
`privateAllowed` values. Permissions, quota, concurrency, and sample availability
are checked again at submission.

The current native creation and internal preview use a **0 Credit** quote.
Explicit confirmation is still required because creation occupies a model slot
and starts preview generation. Submit `confirmChatPlan` with the exact
`planId`, `version`, and `quoteId` from the current card and a unique
`clientRequestId`. Edits require a new quote and confirmation. Repeated
confirmation or a lost response must reuse the original submission; inspect its
status instead of starting another model.

The accepted result carries `resourceType: "MODEL"` and `modelId`. Completion
waits for the preview, not just reference upload. A successful output includes
`type: "AUDIO"`, `modelUsage: "VOICE"`, `name`, `description`, `isPublic`,
`viewUrl`, and `playbackUrl`. There is no synthetic `mediaId`. Playback URLs expire
and should be refreshed through an authorized result read. Failed or incomplete
models are not selectable as ready voices.

After completion, find the voice through `chatVoiceModels(source: "PERSONAL")`.
Follow-up actions create a new draft for Generate Audio, Talking Avatar, or Lip
Sync using `voiceModelId` and `audioInputMode: "VOICE_SCRIPT"`. They do not
submit generation automatically; the remaining script and visual inputs still
need to be supplied and validated.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.