Aqua API reference

Aqua API creates Aqua dictations and voice edits, reads stored dictations, manages transcript customizations and supported app settings, and transcribes audio with Avalon.

The API has two route families. Product routes use Aqua object shapes, the ErrorEnvelope error format, and X-RateLimit-* response headers. Transcription routes are OpenAI-compatible: they keep OpenAI request, response, and error shapes so the official OpenAI SDKs work unchanged, which is why some field names (for example duration) and the free-form language string differ from the product routes.

Base URL

https://api.aquavoice.com/v1

Authentication

API key as Bearer token on every route

Specification

OpenAPI YAML

Authentication

Send your API key as a Bearer token on every route. Create keys in the API dashboard at https://app.aquavoice.com/api-dashboard. A key has full access: dictation, transcription, sessions, customizations, settings, and MCP. Legacy ava_ keys keep working. OAuth tokens carry read and write scopes; the scope shown on an operation applies to OAuth only. An OAuth token works on the product routes when it was issued for the resource https://api.aquavoice.com/v1, and on MCP when it was issued for https://api.aquavoice.com/mcp. One token can have both resources.

A key that belongs to an organization acts as one member on the product and dictation routes. Send the header Aqua-User: usr_<id> with the member's user id, the same id GET /me returns. A missing header returns 400 user_required. A user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header. A disabled account returns 403 account_disabled.

Aqua staff can set an API account to a platform account. A platform account is one company that puts Aqua dictation into its own product. Its end users are not Aqua users. A platform key does not act as an Aqua user, and it uses no stored settings or customizations. Each dictation uses only the personalization in the request. A platform key can call only POST /dictations. All other routes return 403 platform_not_supported: the other product routes, the transcription routes, /models, meetings, and MCP. A platform key that sends Aqua-User returns 400 user_not_allowed.

Billing

Your account activates when you create your first key. The first $1.00 of usage is free. After that, add a payment method in the API dashboard. Usage bills per second at $0.49 per hour of dictation and $0.39 per hour of transcription, with a 10-second minimum. Stripe invoices monthly, or when usage reaches $200. Failed requests and idempotent replays are not billed.

Billing errors are 402 payment_method_required, 402 billing_past_due, and 403 subscription_required. Their bodies carry billing_url, which opens the API dashboard billing page.

Data handling

Aqua processes API requests in the United States.

Aqua staff can set an API account to zero data retention (ZDR). Contact Aqua to set it. On a ZDR account, each dictation uses privacy mode and only ZDR providers. The settings of the user cannot change this. A platform account is always a ZDR account.

For a dictation on a ZDR account, Aqua does not keep the audio or the text. Aqua keeps only metadata: the audio duration, the models, the latency, and the billing record. When you send an Idempotency-Key, Aqua keeps the encrypted response for approximately 10 minutes after the request starts, so that a retry gets the same result. Then Aqua deletes it. For a dictation on a platform account, Aqua also keeps no session.

On a ZDR account, only these subprocessors can see the content of a dictation while Aqua processes it: Baseten for speech recognition and text formatting, and, as fallback providers, Groq, OpenRouter, Google, Speechmatics, and Aqua servers at RunPod.

Connect with MCP

Use Aqua sessions, transcript customizations, and settings from an AI assistant.

  1. 01Copy the connection URL: https://api.aquavoice.com/mcp
  2. 02Add it as a remote MCP server. Claude: Customize > Connectors > Add > Add custom connector , then Continue, Add, and Connect. ChatGPT: Plugins > Add > Create custom MCP server , select the checkbox, then Create as a plugin.
  3. 03Sign in to Aqua, approve access, and enable Aqua in your conversation.

MCP endpoint

https://api.aquavoice.com/mcp

Your AI provider must support remote MCP and may require workspace admin approval. Review the permissions before you connect; some clients request read and write access together.

Account

Current user, credential, and history availability.

Get the current user

GET/me

This operation remains available when privacy or enterprise retention policy blocks stored history; in that case history_available is false.

Parameters

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

bash
curl https://api.aquavoice.com/v1/me \
  -H "Authorization: Bearer <api-key>"
json
{
  "id": "usr_1daef426873f44baaf2096903dc7283e",
  "object": "user",
  "email": "maya@northstar.studio",
  "name": "Maya Chen",
  "created_at": "2026-08-11T17:03:00Z",
  "credential": {
    "id": "key_7d4d4d5ad69942fe9ceef628f5ba7bdd",
    "method": "api_key",
    "scopes": [
      "read"
    ]
  },
  "plan": "pro",
  "privacy_mode": false,
  "history_available": true
}

Sessions

Stored dictations, including transcripts.

List or search stored sessions

GET/sessions

OAuth scope: read

Returns the user's visible stored dictations, newest first. Redacted and deleted sessions and history cleared by the user are excluded. Privacy mode stops future storage but does not hide earlier history. Enterprise zero-data-retention policy blocks product history. Search requires all meaningful query words to occur in one transcript. Results identify the matching source and include a centered snippet. Reads never start new AI work.

Parameters

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

cursor

string

Query parameter. Opaque next_cursor from the previous page. Cursors expire after 30 days and are bound to the original filters. A changed or expired cursor returns invalid_cursor.

Length: 0–2048

limit

integer

Query parameter.

Default: 25 · Range: 1–100

query

string

Query parameter.

Length: 1–500

since

string

Query parameter.

until

string

Query parameter.

bash
curl https://api.aquavoice.com/v1/sessions \
  -H "Authorization: Bearer <api-key>"
json
{
  "object": "list",
  "data": [
    {
      "object": "session",
      "id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
      "created_at": "2026-08-11T17:03:00Z",
      "updated_at": "2026-08-11T17:03:00Z",
      "status": "stopped",
      "title": "The beta is stable enough to expand next week.",
      "app": "Zoom",
      "duration_seconds": 1842.7,
      "word_count": 4218,
      "preview": "The beta is stable enough to expand next week."
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Get a stored session

GET/sessions/{session_id}

OAuth scope: read

Parameters

session_id

stringrequired

Path parameter. A missing session and a session owned by another user both return 404 session_not_found.

Pattern: ^ses_[0-9a-f]{32}$

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

bash
curl https://api.aquavoice.com/v1/sessions/ses_a1e2c85b1cbf43af9dc678a1a7423dcc \
  -H "Authorization: Bearer <api-key>"
json
{
  "object": "session",
  "id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "created_at": "2026-08-11T17:03:00Z",
  "updated_at": "2026-08-11T17:03:00Z",
  "status": "stopped",
  "title": "The beta is stable enough to expand next week.",
  "app": "Zoom",
  "duration_seconds": 1842.7,
  "word_count": 4218,
  "preview": "The beta is stable enough to expand next week."
}

Get a stored session transcript

GET/sessions/{session_id}/transcript

OAuth scope: read

Returns the complete final text and, when stored, the complete raw ASR text.

Parameters

session_id

stringrequired

Path parameter. A missing session and a session owned by another user both return 404 session_not_found.

Pattern: ^ses_[0-9a-f]{32}$

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

bash
curl https://api.aquavoice.com/v1/sessions/ses_a1e2c85b1cbf43af9dc678a1a7423dcc/transcript \
  -H "Authorization: Bearer <api-key>"
json
{
  "object": "transcript",
  "session_id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "final_text": "The beta is stable enough to expand next week.",
  "raw_text": "the beta is stable enough to expand next week"
}

Set session feedback

POST/sessions/{session_id}/feedback

OAuth scope: write

Creates or replaces feedback for one owned session. corrected_text is the exact text the user wanted instead of Aqua's output.

Parameters

session_id

stringrequired

Path parameter. A missing session and a session owned by another user both return 404 session_not_found.

Pattern: ^ses_[0-9a-f]{32}$

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

Body

feedback_type

string enumrequired

One of: positive negative

message

string

What Aqua got right or wrong.

Length: 0–5000

corrected_text

string

Exact corrected output.

Length: 0–40000

bash
curl -X POST https://api.aquavoice.com/v1/sessions/ses_a1e2c85b1cbf43af9dc678a1a7423dcc/feedback \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{"feedback_type":"positive","message":"...","corrected_text":"..."}'
json
{
  "object": "session_feedback",
  "session_id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "feedback_type": "positive",
  "message": "Keep the product name capitalized.",
  "corrected_text": "Send this from Aqua Voice.",
  "updated_at": "2026-08-11T17:03:00Z"
}

Clear session feedback

DELETE/sessions/{session_id}/feedback

OAuth scope: write

Removes any feedback stored for the session.

Parameters

session_id

stringrequired

Path parameter. A missing session and a session owned by another user both return 404 session_not_found.

Pattern: ^ses_[0-9a-f]{32}$

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

bash
curl -X DELETE https://api.aquavoice.com/v1/sessions/ses_a1e2c85b1cbf43af9dc678a1a7423dcc/feedback \
  -H "Authorization: Bearer <api-key>"

Dictation

Aqua dictation and voice editing with the user's preferences and customizations.

Dictate or edit text

POST/dictations

OAuth scope: write

Runs Aqua's normal dictation pipeline and returns when the text is ready. The request stays open while Aqua transcribes and formats the audio, for up to 210 seconds. It does not create a public background job. Send an Idempotency-Key and retry the same request with the same key if the connection closes. A terminal result replays for 24 hours without another inference or charge. On a zero-data-retention account, it replays for 10 minutes. After Aqua dispatches the audio, an uncertain upstream failure is terminal for that key so a retry cannot create a second dictation.

Aqua applies the user's language setting, dictionary, replacements, custom instructions, and casual messaging preference. A request language overrides the saved language for this dictation. The returned session_id identifies the session stored in Aqua history. Privacy and zero-data-retention settings still apply: the text is returned to the caller but is not stored when retention is off. A zero-data-retention account always applies them; see Data handling.

An organization key acts as one member: send Aqua-User with the member's user id. The dictation is billed to the account that owns the key.

A platform key uses no stored personalization. Send dictionary, replacements, instructions, and casual_messaging with each dictation; Aqua uses them for that dictation only and does not store them. Aqua keeps no session for the dictation, so session_id is null. Send Aqua-End-User to identify your end user. One end user can have 2 dictations in progress at the same time; more return 429 end_user_concurrency_limit_exceeded. Other accounts that send these fields or this header get 400 platform_only_parameter.

Use operation=edit with selected_text to run Edit Mode. The optional text and app fields give Aqua the same surrounding context it uses when dictating into an app.

Dictate and Edit Mode bill at the same rate; see Billing.

Parameters

Idempotency-Key

string

Header. Optional idempotency value. Use the same value of 1–255 printable ASCII characters for retries of one logical request. Terminal results replay for 24 hours, or 10 minutes for a dictation on a zero-data-retention account; different request content returns 409 idempotency_conflict.

Length: 1–255

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

Aqua-End-User

string

Header. Platform keys only. An opaque value that identifies your end user, for example a hashed user id. Aqua uses it only to limit each end user to 2 dictations in progress and does not store it.

Length: 1–256

Body (multipart/form-data)

audio

filerequired

A canonical 16 kHz mono PCM16 WAV file, or a mono or stereo Ogg Opus file. Aqua decodes Opus audio to 16 kHz mono PCM16. The 10-minute limit and billing use the decoded duration. The maximum size of an Opus file is 19.2 MB. Use an Opus bitrate of more than 48 kbps, because short clips at lower bitrates can give empty text.

operation

string enum

Use edit to apply the spoken instruction to selected_text.

One of: dictate edit

Default: dictate

selected_text

string

Required when operation is edit.

Length: 0–6000

language

LanguageCode

One of: auto ar be bn bg yue ca hr cs da nl en et fi fr gl de el he hi hu id ga it ja ko lv lt ms mt cmn mr mn no fa pl pt ro ru sl es sw sv ta th tr uk ur vi cy yi

app

string

Name of the app where the text will be used.

Length: 0–255

app_bundle_id

string

Bundle ID or package name for the app.

Length: 0–255

text_before

string

Text immediately before the insertion or selection.

Length: 0–6000

text_after

string

Text immediately after the insertion or selection.

Length: 0–6000

focused_element_description

string

Accessible description of the target text field.

Length: 0–1000

dictionary

string

Platform keys only. A JSON array of up to 1,000 terms that speech recognition and formatting must spell correctly. Each term has 1–100 characters.

Length: 0–32768

replacements

string

Platform keys only. A JSON array of up to 200 {"from", "to"} pairs. Aqua replaces each from phrase with its to text in a dictation. Each value has 1–100 characters.

Length: 0–32768

instructions

string

Platform keys only. Custom instructions for the formatting of the text.

Length: 0–4096

casual_messaging

string enum

Platform keys only. Writes short messages in a casual style, as the casual messaging setting does in the Aqua app.

One of: true false

bash
curl -X POST https://api.aquavoice.com/v1/dictations \
  -H "Authorization: Bearer <api-key>" \
  -F "audio=@audio.wav" \
  -F "operation=dictate" \
  -F "language=auto"
json
{
  "object": "dictation",
  "session_id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "operation": "dictate",
  "raw_text": "hello aqua can you send the update",
  "text": "Hello, Aqua! Can you send the update?",
  "language": "auto",
  "duration_seconds": 2.84,
  "edit_unclear": false,
  "edit_deleted": false
}

Customizations

Dictionary terms, text replacements, and custom transcript instructions.

Get transcript customizations

GET/customizations

OAuth scope: read

Parameters

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

bash
curl https://api.aquavoice.com/v1/customizations \
  -H "Authorization: Bearer <api-key>"
json
{
  "object": "customizations",
  "revision": 12,
  "updated_at": "2026-08-11T17:03:00Z",
  "dictionary": [
    "Aquaphone"
  ],
  "replacements": [
    {
      "from": "AV",
      "to": "Aqua Voice"
    }
  ],
  "custom_instructions": "Keep issue keys such as AQUA-142 in uppercase."
}

Apply transcript customization operations

PATCH/customizations

OAuth scope: write

Applies all operations atomically against the latest state. Each operation says what to want, not what to change, so no read is needed first. Send expected_revision to refuse a write over a newer change (409 transcript_customizations_conflict). Send dry_run: true to get the would-be state and results without saving.

Parameters

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

Body

expected_revision

integer

Optional. When present, the write fails with 409 unless this is the current revision.

Range: 0–…

dry_run

boolean

Validate and compute the response without saving.

Default: false

operations

array of CustomizationOperationrequired

Items: 1–100

bash
curl -X PATCH https://api.aquavoice.com/v1/customizations \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{"expected_revision":42,"dry_run":true,"operations":[{"type":"dictionary_add","word":"..."}]}'
json
null

Settings

Aqua app preferences supported by the public API.

Get app settings

GET/settings

OAuth scope: read

Parameters

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

bash
curl https://api.aquavoice.com/v1/settings \
  -H "Authorization: Bearer <api-key>"
json
{
  "object": "settings",
  "language": "auto",
  "casual_messaging": true
}

Update app settings

PATCH/settings

OAuth scope: write

Only fields present in the request change. Null values and unknown fields are rejected.

Parameters

Aqua-User

string

Header. Required with an organization key on product and dictation routes: the member's user id, the same id GET /me returns. A missing header returns 400 user_required; a user who is not an active member returns 403 user_not_member. Transcription routes and personal keys ignore the header.

Pattern: ^usr_[0-9a-f]{32}$

Body

language

LanguageCode

One of: auto ar be bn bg yue ca hr cs da nl en et fi fr gl de el he hi hu id ga it ja ko lv lt ms mt cmn mr mn no fa pl pt ro ru sl es sw sv ta th tr uk ur vi cy yi

casual_messaging

boolean

bash
curl -X PATCH https://api.aquavoice.com/v1/settings \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{"language":"auto","casual_messaging":true}'
json
{
  "object": "settings",
  "language": "auto",
  "casual_messaging": true
}

Transcription (Avalon)

Avalon batch speech-to-text. OpenAI-compatible.

Compatibility
Use the official OpenAI Python or JavaScript SDK with the base URL https://api.aquavoice.com/v1 and model avalon-v1.5.
Timeouts
Synchronous requests wait up to 210 seconds. If a stored job returns 504 request_timeout, its body carries error.job_id; poll that job to follow its status.
Retries
Send a 1–255-character Idempotency-Key with retries. Matching results replay for 24 hours without another inference or charge. Different request content with the same key returns 409.
Limits
Responses include x-should-retry and, when applicable, Retry-After and x-ratelimit-* headers. Rates are listed under Billing .

Transcribe audio synchronously

POST/audio/transcriptions

Uses a 210-second overall deadline. If the wait times out after the job is stored, processing continues and the 504 request_timeout error body carries error.job_id; poll that job to follow its status. The x-request-id response header carries the same value.

Parameters

Idempotency-Key

string

Header. Optional idempotency value. Use the same value of 1–255 printable ASCII characters for retries of one logical request. Terminal results replay for 24 hours, or 10 minutes for a dictation on a zero-data-retention account; different request content returns 409 idempotency_conflict.

Length: 1–255

X-Client-Request-Id

string

Header. Optional printable ASCII correlation value of up to 512 characters. It does not provide idempotency.

Length: 0–512

Body (multipart/form-data)

file

filerequired

Audio in flac, mp3, mp4, mpeg, mpga, m4a, ogg, opus, wav, or webm format. Maximum 256 MiB and four hours of decoded audio.

model

string enumrequired

The Avalon model to use.

One of: avalon-v1.5

language

string

ISO 639-1 language code. Omit it or use auto to detect the language.

prompt

string

Context or vocabulary hints for the transcription.

response_format

string enum

Response format. Defaults to json, or to diarized_json when diarize is true. A diarized transcription supports only diarized_json, srt, and vtt.

One of: json text srt vtt verbose_json diarized_json

Default: json

diarize

boolean

Labels who speaks each word. The result has speaker turns with word timings. Speaker IDs (spk_0, spk_1, ...) are in order of first speech. A transcription has a maximum of 8 speakers.

Default: false

max_speakers

integer

The maximum number of speaker labels. Only with diarize. The speakers with the most detected speech keep their labels; words of other speakers go to the closest kept speaker. It does not change how many speakers the model detects.

Range: 1–8

temperature

number enum

Compatibility no-op. Nonzero values are unsupported.

One of: 0

stream

boolean enum

Avalon is batch-only, so only false is accepted.

One of: false

Default: false

timestamp_granularities

array of string enum

Only segment is supported, and only with verbose_json.

bash
curl -X POST https://api.aquavoice.com/v1/audio/transcriptions \
  -H "Authorization: Bearer <api-key>" \
  -F "file=@audio.mp3" \
  -F "model=avalon-v1.5" \
  -F "language=auto"
json
{
  "text": "The beta is stable enough to expand next week.",
  "usage": {
    "type": "duration",
    "seconds": 17.8
  }
}

Start an asynchronous transcription

POST/audio/transcription-jobs

Returns after the audio is validated and the job is stored. Poll the returned job ID or fetch its result when result_url is present.

Parameters

Idempotency-Key

string

Header. Optional idempotency value. Use the same value of 1–255 printable ASCII characters for retries of one logical request. Terminal results replay for 24 hours, or 10 minutes for a dictation on a zero-data-retention account; different request content returns 409 idempotency_conflict.

Length: 1–255

X-Client-Request-Id

string

Header. Optional printable ASCII correlation value of up to 512 characters. It does not provide idempotency.

Length: 0–512

Body (multipart/form-data)

file

filerequired

Audio in flac, mp3, mp4, mpeg, mpga, m4a, ogg, opus, wav, or webm format. Maximum 256 MiB and four hours of decoded audio.

model

string enumrequired

The Avalon model to use.

One of: avalon-v1.5

language

string

ISO 639-1 language code. Omit it or use auto to detect the language.

prompt

string

Context or vocabulary hints for the transcription.

response_format

string enum

Response format. Defaults to json, or to diarized_json when diarize is true. A diarized transcription supports only diarized_json, srt, and vtt.

One of: json text srt vtt verbose_json diarized_json

Default: json

diarize

boolean

Labels who speaks each word. The result has speaker turns with word timings. Speaker IDs (spk_0, spk_1, ...) are in order of first speech. A transcription has a maximum of 8 speakers.

Default: false

max_speakers

integer

The maximum number of speaker labels. Only with diarize. The speakers with the most detected speech keep their labels; words of other speakers go to the closest kept speaker. It does not change how many speakers the model detects.

Range: 1–8

temperature

number enum

Compatibility no-op. Nonzero values are unsupported.

One of: 0

stream

boolean enum

Avalon is batch-only, so only false is accepted.

One of: false

Default: false

timestamp_granularities

array of string enum

Only segment is supported, and only with verbose_json.

bash
curl -X POST https://api.aquavoice.com/v1/audio/transcription-jobs \
  -H "Authorization: Bearer <api-key>" \
  -F "file=@audio.mp3" \
  -F "model=avalon-v1.5" \
  -F "language=auto"
json
{
  "id": "req_01k2j4wr1ns8h4f7s2ckm6h1p9",
  "object": "transcription.job",
  "status": "queued",
  "created_at": "2026-08-11T17:03:00Z",
  "completed_at": null,
  "audio_duration_seconds": 17.8,
  "error_code": null,
  "result_url": null
}

Get an asynchronous transcription job

GET/audio/transcription-jobs/{job_id}

Parameters

job_id

stringrequired

Path parameter.

bash
curl https://api.aquavoice.com/v1/audio/transcription-jobs/... \
  -H "Authorization: Bearer <api-key>"
json
{
  "id": "req_01k2j4wr1ns8h4f7s2ckm6h1p9",
  "object": "transcription.job",
  "status": "queued",
  "created_at": "2026-08-11T17:03:00Z",
  "completed_at": null,
  "audio_duration_seconds": 17.8,
  "error_code": null,
  "result_url": null
}

Get a completed transcription result

GET/audio/transcription-jobs/{job_id}/result

Returns 409 job_not_complete while the job is queued. The error is retryable and includes the standard retry headers.

Parameters

job_id

stringrequired

Path parameter.

bash
curl https://api.aquavoice.com/v1/audio/transcription-jobs/.../result \
  -H "Authorization: Bearer <api-key>"
json
{
  "text": "The beta is stable enough to expand next week.",
  "usage": {
    "type": "duration",
    "seconds": 17.8
  }
}

List transcription models

GET/models
bash
curl https://api.aquavoice.com/v1/models \
  -H "Authorization: Bearer <api-key>"
json
{
  "object": "list",
  "data": [
    {
      "id": "avalon-v1.5",
      "object": "model",
      "created": 1754870400,
      "owned_by": "aqua"
    }
  ]
}

Get a transcription model

GET/models/{model}

Parameters

model

stringrequired

Path parameter.

bash
curl https://api.aquavoice.com/v1/models/avalon-v1.5 \
  -H "Authorization: Bearer <api-key>"
json
{
  "id": "avalon-v1.5",
  "object": "model",
  "created": 1754870400,
  "owned_by": "aqua"
}

Objects

Request and response objects. Treat enum values as open sets.

Principal

id

stringrequired

Pattern: ^usr_[0-9a-f]{32}$

object

"user"required

email

stringrequired

name

string, nullablerequired

created_at

string, nullablerequired

credential

Credentialrequired

plan

string enumrequired

One of: free pro max team enterprise

privacy_mode

booleanrequired

history_available

booleanrequired

True when enterprise policy permits stored history.

json
{
  "id": "usr_1daef426873f44baaf2096903dc7283e",
  "object": "user",
  "email": "maya@northstar.studio",
  "name": "Maya Chen",
  "created_at": "2026-08-11T17:03:00Z",
  "credential": {
    "id": "key_7d4d4d5ad69942fe9ceef628f5ba7bdd",
    "method": "api_key",
    "scopes": [
      "read"
    ]
  },
  "plan": "pro",
  "privacy_mode": false,
  "history_available": true
}

SessionSummary

object

"session"required

id

stringrequired

Pattern: ^ses_[0-9a-f]{32}$

created_at

stringrequired

updated_at

stringrequired

status

stringrequired

title

stringrequired

app

string, nullablerequired

duration_seconds

number, nullablerequired

word_count

integerrequired

preview

stringrequired

match

SessionSearchMatch

json
{
  "object": "session",
  "id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "created_at": "2026-08-11T17:03:00Z",
  "updated_at": "2026-08-11T17:03:00Z",
  "status": "stopped",
  "title": "The beta is stable enough to expand next week.",
  "app": "Zoom",
  "duration_seconds": 1842.7,
  "word_count": 4218,
  "preview": "The beta is stable enough to expand next week.",
  "match": {
    "source": "final_text",
    "snippet": "The team approved a wider beta for Tuesday."
  }
}

SessionDetail

object

"session"required

id

stringrequired

Pattern: ^ses_[0-9a-f]{32}$

created_at

stringrequired

updated_at

stringrequired

status

stringrequired

title

stringrequired

app

string, nullablerequired

duration_seconds

number, nullablerequired

word_count

integerrequired

preview

stringrequired

json
{
  "object": "session",
  "id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "created_at": "2026-08-11T17:03:00Z",
  "updated_at": "2026-08-11T17:03:00Z",
  "status": "stopped",
  "title": "The beta is stable enough to expand next week.",
  "app": "Zoom",
  "duration_seconds": 1842.7,
  "word_count": 4218,
  "preview": "The beta is stable enough to expand next week."
}

SessionTranscript

object

"transcript"required

session_id

stringrequired

Pattern: ^ses_[0-9a-f]{32}$

final_text

stringrequired

raw_text

string, nullablerequired

json
{
  "object": "transcript",
  "session_id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "final_text": "The beta is stable enough to expand next week.",
  "raw_text": "the beta is stable enough to expand next week"
}

DictationResult

object

"dictation"required

session_id

string, nullablerequired

The session that Aqua stored in history. It is null for a platform account, because Aqua keeps no session for its dictations.

Pattern: ^ses_[0-9a-f]{32}$

operation

string enumrequired

One of: dictate edit

raw_text

stringrequired

Speech recognition output before Aqua formatting.

text

stringrequired

Final Aqua text, ready to insert or use as the edit replacement.

language

LanguageCoderequired

One of: auto ar be bn bg yue ca hr cs da nl en et fi fr gl de el he hi hu id ga it ja ko lv lt ms mt cmn mr mn no fa pl pt ro ru sl es sw sv ta th tr uk ur vi cy yi

duration_seconds

numberrequired

Range: 0–…

edit_unclear

booleanrequired

True when Edit Mode could not determine the requested change.

edit_deleted

booleanrequired

True when Edit Mode intentionally removed the selected text.

json
{
  "object": "dictation",
  "session_id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "operation": "dictate",
  "raw_text": "hello aqua can you send the update",
  "text": "Hello, Aqua! Can you send the update?",
  "language": "auto",
  "duration_seconds": 2.84,
  "edit_unclear": false,
  "edit_deleted": false
}

SessionFeedback

object

"session_feedback"required

session_id

stringrequired

Pattern: ^ses_[0-9a-f]{32}$

feedback_type

string enumrequired

One of: positive negative

message

string, nullablerequired

corrected_text

string, nullablerequired

updated_at

stringrequired

json
{
  "object": "session_feedback",
  "session_id": "ses_a1e2c85b1cbf43af9dc678a1a7423dcc",
  "feedback_type": "positive",
  "message": "Keep the product name capitalized.",
  "corrected_text": "Send this from Aqua Voice.",
  "updated_at": "2026-08-11T17:03:00Z"
}

Customizations

object

"customizations"required

revision

integerrequired

Range: 0–…

updated_at

string, nullablerequired

dictionary

array of stringrequired

replacements

array of Replacementrequired

custom_instructions

stringrequired

warning

string

Only in an update result. Present when the dictionary is longer than speech recognition reads.

json
{
  "object": "customizations",
  "revision": 12,
  "updated_at": "2026-08-11T17:03:00Z",
  "dictionary": [
    "Aquaphone"
  ],
  "replacements": [
    {
      "from": "AV",
      "to": "Aqua Voice"
    }
  ],
  "custom_instructions": "Keep issue keys such as AQUA-142 in uppercase.",
  "warning": "..."
}

Settings

object

"settings"required

language

LanguageCode | nullrequired

casual_messaging

boolean, nullablerequired

json
{
  "object": "settings",
  "language": "auto",
  "casual_messaging": true
}

ErrorEnvelope

error

ErrorDetailrequired

json
{
  "error": {
    "code": "payment_method_required",
    "message": "Add a payment method to continue",
    "details": {},
    "docs_url": "https://aquavoice.com/docs/api#billing",
    "billing_url": "https://app.aquavoice.com/api-dashboard?tab=billing"
  }
}

Transcription

task

"transcribe"

text

stringrequired

language

string

duration

number

segments

array of object

usage

objectrequired

json
{
  "task": "transcribe",
  "text": "The beta is stable enough to expand next week.",
  "language": "en",
  "duration": 17.8,
  "segments": [
    {
      "start": 0,
      "end": 4.2,
      "text": "The beta is stable enough to expand next week."
    }
  ],
  "usage": {
    "type": "duration",
    "seconds": 17.8
  }
}

TranscriptionJob

id

stringrequired

object

"transcription.job"required

status

string enumrequired

One of: queued succeeded failed cancelled abandoned

created_at

stringrequired

completed_at

string, nullablerequired

audio_duration_seconds

number, nullablerequired

error_code

string, nullablerequired

result_url

string, nullablerequired

json
{
  "id": "req_01k2j4wr1ns8h4f7s2ckm6h1p9",
  "object": "transcription.job",
  "status": "queued",
  "created_at": "2026-08-11T17:03:00Z",
  "completed_at": null,
  "audio_duration_seconds": 17.8,
  "error_code": null,
  "result_url": null
}

Model

id

stringrequired

object

"model"required

created

integerrequired

owned_by

"aqua"required

json
{
  "id": "avalon-v1.5",
  "object": "model",
  "created": 1754870400,
  "owned_by": "aqua"
}

AvalonError

error

objectrequired

json
{
  "error": {
    "message": "The uploaded file exceeds the size limit.",
    "type": "invalid_request_error",
    "param": "file",
    "code": "file_too_large",
    "job_id": "req_01k2j4wr1ns8h4f7s2ckm6h1p9",
    "docs_url": "...",
    "billing_url": "..."
  }
}