curl --request POST 'https://api.voicecheap.ai/v1/actions/subtitles_result_get' \
--header "x-api-key: $VOICECHEAP_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"resultId":"b3caf96f-5f2a-4619-832c-a12c0d57f78b","includeContent":true}'
const input = {
resultId: 'b3caf96f-5f2a-4619-832c-a12c0d57f78b',
includeContent: true,
};
const response = await fetch('https://api.voicecheap.ai/v1/actions/subtitles_result_get', {
method: 'POST',
headers: {
'x-api-key': process.env.VOICECHEAP_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
const body = await response.json();
if (!response.ok) throw new Error(body.code + ': ' + body.message);
console.log(body);
import os
import requests
response = requests.post(
"https://api.voicecheap.ai/v1/actions/subtitles_result_get",
headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
json={"resultId": "b3caf96f-5f2a-4619-832c-a12c0d57f78b", "includeContent": True},
timeout=120,
)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
print(body)
{
"data": {
"resultId": "b3caf96f-5f2a-4619-832c-a12c0d57f78b",
"operation": "captions_transcribe",
"createdAt": 1792152000000,
"fileName": "voicecheap-captions_transcribe-b3caf96f-5f2a-4619-832c-a12c0d57f78b.json",
"byteLength": 190,
"contentType": "application/json; charset=utf-8",
"status": "completed",
"requestId": "13579bdf-2468-4ace-8bdf-0123456789ab",
"getAction": "subtitles_result_get",
"downloadAction": "subtitles_result_download",
"listAction": "subtitles_result_list",
"result": {
"words": [
{
"text": "Hello",
"startMs": 0,
"endMs": 500,
"speakerId": "speaker_0"
},
{
"text": "world.",
"startMs": 500,
"endMs": 1500,
"speakerId": "speaker_0"
}
],
"detectedLanguage": "en",
"durationSeconds": 60
}
}
}
Subtitles and captions
Read a saved subtitles action result
Read metadata for your saved output. Set includeContent=true to retrieve the complete structured JSON, including all caption words or transcript text.
POST
/
v1
/
actions
/
subtitles_result_get
curl --request POST 'https://api.voicecheap.ai/v1/actions/subtitles_result_get' \
--header "x-api-key: $VOICECHEAP_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"resultId":"b3caf96f-5f2a-4619-832c-a12c0d57f78b","includeContent":true}'
const input = {
resultId: 'b3caf96f-5f2a-4619-832c-a12c0d57f78b',
includeContent: true,
};
const response = await fetch('https://api.voicecheap.ai/v1/actions/subtitles_result_get', {
method: 'POST',
headers: {
'x-api-key': process.env.VOICECHEAP_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
const body = await response.json();
if (!response.ok) throw new Error(body.code + ': ' + body.message);
console.log(body);
import os
import requests
response = requests.post(
"https://api.voicecheap.ai/v1/actions/subtitles_result_get",
headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
json={"resultId": "b3caf96f-5f2a-4619-832c-a12c0d57f78b", "includeContent": True},
timeout=120,
)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
print(body)
{
"data": {
"resultId": "b3caf96f-5f2a-4619-832c-a12c0d57f78b",
"operation": "captions_transcribe",
"createdAt": 1792152000000,
"fileName": "voicecheap-captions_transcribe-b3caf96f-5f2a-4619-832c-a12c0d57f78b.json",
"byteLength": 190,
"contentType": "application/json; charset=utf-8",
"status": "completed",
"requestId": "13579bdf-2468-4ace-8bdf-0123456789ab",
"getAction": "subtitles_result_get",
"downloadAction": "subtitles_result_download",
"listAction": "subtitles_result_list",
"result": {
"words": [
{
"text": "Hello",
"startMs": 0,
"endMs": 500,
"speakerId": "speaker_0"
},
{
"text": "world.",
"startMs": 500,
"endMs": 1500,
"speakerId": "speaker_0"
}
],
"detectedLanguage": "en",
"durationSeconds": 60
}
}
}
Read metadata for your saved output. Set includeContent=true to retrieve the complete structured JSON, including all caption words or transcript text.
Required permissions:
POST https://api.voicecheap.ai/v1/actions/subtitles_result_get
Authentication and permissions
string
required
Send a VoiceCheap API key in this header. Authorization: Bearer with the same API key is also supported. OAuth access tokens are accepted only by
MCP, not by this REST endpoint.
subtitles:read.
An active paid subscription is required. Permissions do not change team roles, resource ownership, media credits, or plan limits.
Parameters
string
required
Text value.Format: “uuid”. Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$.boolean
Boolean value.Default: false.
Complete input schema
Complete input schema
The JSON Schema below preserves the exact field names, nested types, defaults, bounds, and accepted values exposed by discovery. Additional cross-field rules are listed in the operation notes.
{
"type": "object",
"properties": {
"resultId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"includeContent": {
"default": false,
"type": "boolean"
}
},
"required": ["resultId"],
"additionalProperties": false
}
Request examples
Replace example resource identifiers and media keys with values returned for your account. Keep the request identifier stable when retrying the same mutation.curl --request POST 'https://api.voicecheap.ai/v1/actions/subtitles_result_get' \
--header "x-api-key: $VOICECHEAP_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"resultId":"b3caf96f-5f2a-4619-832c-a12c0d57f78b","includeContent":true}'
const input = {
resultId: 'b3caf96f-5f2a-4619-832c-a12c0d57f78b',
includeContent: true,
};
const response = await fetch('https://api.voicecheap.ai/v1/actions/subtitles_result_get', {
method: 'POST',
headers: {
'x-api-key': process.env.VOICECHEAP_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
const body = await response.json();
if (!response.ok) throw new Error(body.code + ': ' + body.message);
console.log(body);
import os
import requests
response = requests.post(
"https://api.voicecheap.ai/v1/actions/subtitles_result_get",
headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
json={"resultId": "b3caf96f-5f2a-4619-832c-a12c0d57f78b", "includeContent": True},
timeout=120,
)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
print(body)
Response
A successful first execution returns HTTP 200 with the operation result under data. A replay may return saved request state instead. The example shows one supported response, not every optional field. Saved output metadata, plus the complete structured result when includeContent is true. Omitting includeContent returns metadata only.{
"data": {
"resultId": "b3caf96f-5f2a-4619-832c-a12c0d57f78b",
"operation": "captions_transcribe",
"createdAt": 1792152000000,
"fileName": "voicecheap-captions_transcribe-b3caf96f-5f2a-4619-832c-a12c0d57f78b.json",
"byteLength": 190,
"contentType": "application/json; charset=utf-8",
"status": "completed",
"requestId": "13579bdf-2468-4ace-8bdf-0123456789ab",
"getAction": "subtitles_result_get",
"downloadAction": "subtitles_result_download",
"listAction": "subtitles_result_list",
"result": {
"words": [
{
"text": "Hello",
"startMs": 0,
"endMs": 500,
"speakerId": "speaker_0"
},
{
"text": "world.",
"startMs": 500,
"endMs": 1500,
"speakerId": "speaker_0"
}
],
"detectedLanguage": "en",
"durationSeconds": 60
}
}
}
Result fields
| Field | Description |
|---|---|
data.resultId | Owned saved-output UUID. Use it with getAction or downloadAction; it is distinct from requestId and any historyId. |
data.operation | Generation action that produced this saved JSON. |
data.createdAt | Unix timestamp in milliseconds when the saved output was prepared. |
data.fileName | Suggested filename for a JSON export. |
data.byteLength | UTF-8 bytes of the complete serialized output, not the compact metadata. |
data.contentType | application/json; charset=utf-8. |
data.status | completed on successful generation. Result history can also expose pending recovery entries. |
data.requestId | Original action request UUID when recorded. |
data.getAction | Owned retrieval action; includeContent defaults to false and must be true for complete structured output. |
data.downloadAction | Authenticated export action returning full JSON as a content string. |
data.listAction | Owned saved-output listing action for this permission domain. |
data.result | Complete original public generation body; present only with includeContent: true. |
Operation notes
- Requires a paid subscription and the action permission. The actor’s personal tool plan is rechecked at execution; saved tools and upload references belong to that actor, including when the credential is associated with a team.
- A successful action uses one shared monthly API/MCP call. Beginner allows 500, Starter 5,000 and Creator 25,000 calls/month; Pro, Scale and Enterprise have no monthly ceiling. Per-minute limits still apply: 30, 60, 120, 180, 300 and 600 respectively. Tool generation allowances are separate.
- resultId is a UUID from a completed generation reference or this domain’s result_list. It is different from the action requestId and web-tool historyId.
- Results are owned by the authenticated actor and permission domain. A subtitles result cannot be read through transcription actions, or the reverse.
- Complete saved JSON is encrypted at rest and retained independently of the bounded action polling cache. Retrieval remains authenticated; no public transcript or caption JSON URL is issued.
- These actions retrieve existing output and do not generate media or use a daily allowance. Each successful retrieval still uses one monthly integration call.
- Pending metadata means output persistence needs recovery. Reading content or downloading attempts recovery of an already saved encrypted object; check it before starting another generation.
- includeContent defaults to false. true decrypts and returns the complete generated JSON under result. This example shows the content-returning form.
- The nested result shape follows its original operation. Transcription outputs contain transcript text, subtitle outputs can contain SRT/rendered-video data, and captions contain word text, startMs/endMs, nullable speakerId and durationSeconds.
Usage
Each successful invocation consumes one monthly API/MCP call. Media credits and the operation’s own generation allowances also apply.Errors
| HTTP status | Code | Meaning or recovery |
|---|---|---|
| 400 | CREDENTIAL_IN_QUERY | Credentials were supplied in an access_token or api_key query parameter. Send credentials in headers. |
| 400 | VALIDATION_ERROR | Arguments do not satisfy the action schema, or an unknown argument was supplied. |
| 401 | API_KEY_EXPIRED | The API key has expired. |
| 401 | INVALID_API_KEY | Provide a valid, unexpired API key. |
| 401 | INVALID_CREDENTIAL | The Authorization header is malformed or conflicts with x-api-key. |
| 401 | MISSING_CREDENTIAL | No usable header credential was supplied, or it exceeded 4096 characters. |
| 401 | USER_NOT_FOUND | The credential’s account no longer exists. |
| 403 | AMBIGUOUS_TEAM_API_KEY | The credential’s user belongs to more than one team, so the billing context is ambiguous. |
| 403 | INSUFFICIENT_SCOPE | The API key or MCP connection lacks the required action permission. |
| 403 | INTEGRATION_PLAN_UNSUPPORTED | The account’s integration limits could not be verified. |
| 403 | PAID_SUBSCRIPTION_REQUIRED | The authenticated actor no longer has a paid subscription when this tool action executes. |
| 403 | SUBSCRIPTION_REQUIRED | Use an active paid subscription. |
| 403 | TEAM_OWNER_NOT_FOUND | The effective team owner account could not be found. |
| 404 | TOOL_RESULT_NOT_FOUND | The result is absent, belongs to another actor or belongs to the other permission domain. |
| 410 | TOOL_RESULT_ACCOUNT_UNAVAILABLE | The actor account is being deleted or no longer exists during recovery. |
| 429 | INTEGRATION_MONTHLY_LIMIT_REACHED | Used and pending calls have reached the shared monthly API/MCP allowance. |
| 429 | INTEGRATION_RATE_LIMIT_REACHED | The account has reached its per-minute integration limit; inspect retryAfterSeconds. |
| 500 | INTERNAL_ERROR | The saved completed result could not be read or its integrity validation failed. |
| 503 | INTERNAL_ERROR | A pending saved result needs recovery and cannot yet be confirmed; check the same result again before regenerating. |
| 503 | SERVER_RESTARTING | The server is restarting. Retry shortly and keep the same request identifier for a mutation. |
{
"code": "INSUFFICIENT_SCOPE",
"message": "This credential does not permit the requested action.",
"status": 403,
"details": {
"requiredScopes": ["subtitles:read"]
}
}
Was this page helpful?

