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

# Get a project

> Get project details, editable settings, segment revision, output URLs and translation versions.

Get project details, editable settings, segment revision, output URLs and translation versions.

```http theme={null}
POST https://api.voicecheap.ai/v1/actions/projects_get
```

## Authentication and permissions

<ParamField header="x-api-key" type="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.
</ParamField>

Required permissions: `projects:read`.

An active paid subscription is required. Permissions do not change team roles, resource ownership, media credits, or plan limits.

## Parameters

<ParamField body="projectId" type="string" required>
  Text value.

  Minimum length: 1. Maximum length: 200. Pattern: `^[^/\\]+$`.
</ParamField>

<Accordion title="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.

  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "projectId": {
        "type": "string",
        "minLength": 1,
        "maxLength": 200,
        "pattern": "^[^/\\\\]+$"
      }
    },
    "required": ["projectId"],
    "additionalProperties": false
  }
  ```
</Accordion>

## 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.

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST 'https://api.voicecheap.ai/v1/actions/projects_get' \
    --header "x-api-key: $VOICECHEAP_API_KEY" \
    --header 'Content-Type: application/json' \
    --data '{"projectId":"project_launch_2026"}'
  ```

  ```javascript JavaScript theme={null}
  const input = {
    projectId: 'project_launch_2026',
  };
  const response = await fetch('https://api.voicecheap.ai/v1/actions/projects_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);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.post(
      "https://api.voicecheap.ai/v1/actions/projects_get",
      headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
      json={"projectId": "project_launch_2026"},
      timeout=120,
  )
  body = response.json()
  if not response.ok:
      raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
  print(body)
  ```
</RequestExample>

## 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.

Returns the public project details, customer settings, current source structure revision, and every translated output version.

<ResponseExample>
  ```json HTTP 200 theme={null}
  {
    "data": {
      "projectId": "project_launch_2026",
      "projectName": "Product launch",
      "status": "success",
      "workflow": "translation",
      "originalVideoUrl": "https://media.example.com/launch/original.mp4",
      "originalLanguage": "fr",
      "targetLanguages": [
        "english"
      ],
      "duration": 75,
      "createdAt": 1792152000000,
      "progress": {
        "step": "done",
        "transcriptionProgress": 100,
        "transcriptionStatus": "success"
      },
      "translations": [
        {
          "workId": "5f8423d1-e4c0-4f80-9e3f-eed959389e24",
          "translatedVersionId": "0fa684f3-4997-4d7a-9424-16d1f9ac849c",
          "targetLanguage": "english",
          "status": "completed",
          "currentStep": "done",
          "progress": 100,
          "createdAt": 1792152060000,
          "completedAt": 1792152300000,
          "translatedVideoUrl": "https://media.example.com/launch/english.mp4",
          "translatedAudioUrl": "https://media.example.com/launch/english.mp3",
          "settings": {
            "voiceCloning": true,
            "uploadType": "video",
            "keepBackgroundMusic": true,
            "keepOriginalVoice": false,
            "originalVoiceVolume": 30,
            "subtitles": {
              "isEnable": false,
              "source": "translated"
            },
            "smartSync": true,
            "dubbingMode": "translate",
            "voiceIsolatorOption": "studio"
          }
        }
      ],
      "segmentStructureRevision": 3,
      "numberOfSpeakers": 1,
      "translationInstructions": "",
      "isReadyForDubbing": true,
      "settings": {
        "voiceCloning": true,
        "customVoice": false,
        "customVoiceId": "",
        "keepBackgroundMusic": true,
        "keepOriginalVoice": false,
        "originalVoiceVolume": 30,
        "activeSpeakerDetectionEnabled": false,
        "subtitles": {
          "isEnable": false,
          "source": "translated"
        },
        "smartSync": true,
        "voiceIsolatorOption": "studio",
        "voiceCloningSettings": {
          "stability": 0.5,
          "similarity": 0.75
        }
      }
    }
  }
  ```
</ResponseExample>

## Result fields

| Field | Description |
| - | - |
| `data.projectId` | Accessible project identifier. |
| `data.projectName` | Customer-visible project name. |
| `data.status` | Project summary: processing, success, or failed. |
| `data.workflow` | transcription for transcription-only projects; translation for dubbing projects. |
| `data.originalVideoUrl` | Original stored media URL, including audio projects; empty string when absent. |
| `data.originalLanguage` | Detected or selected source language; unknown when unavailable. |
| `data.targetLanguages` | Array of target language names. |
| `data.duration` | Original media duration in seconds. |
| `data.createdAt` | Project creation time in Unix milliseconds. |
| `data.progress` | Public transcription step, optional transcriptionProgress, and transcriptionStatus. |
| `data.translations` | All translated versions across all language works, sorted newest first by normalized createdAt. |
| `data.segmentStructureRevision` | Current source segment structure revision, default 0. Pass this value as expectedSegmentStructureRevision to segments\_delete or segments\_merge. |
| `data.numberOfSpeakers` | Stored source speaker count, when present. |
| `data.translationInstructions` | Current project translation instructions; empty string when none are stored. |
| `data.isReadyForDubbing` | True only when the stored project is marked ready for dubbing. |
| `data.settings` | Optional customer settings selected from the project dubbing settings or legacy settings. Only stored fields are returned; absent optional values are omitted. |
| `data.settings.voiceCloning` | Optional project voice cloning preference. |
| `data.settings.customVoice` | Optional custom voice preference. |
| `data.settings.customVoiceId` | Optional custom voice identifier. |
| `data.settings.keepBackgroundMusic` | Optional background audio preference. |
| `data.settings.keepOriginalVoice` | Optional original speech preference. |
| `data.settings.originalVoiceVolume` | Optional original speech volume. |
| `data.settings.activeSpeakerDetectionEnabled` | Optional active speaker detection preference. |
| `data.settings.subtitles` | Optional \{isEnable,source} subtitle preference. |
| `data.settings.smartSync` | Optional SmartSync preference. |
| `data.settings.voiceIsolatorOption` | Optional studio or realistic voice isolation preference. |
| `data.settings.voiceCloningSettings` | Optional \{stability,similarity} voice cloning preferences. |
| `data.error` | Optional public \{code,message} for a project-level processing failure. |
| `data.translations[].workId` | Language-work identifier containing this version. |
| `data.translations[].translatedVersionId` | Identifier for a particular dubbing output version. |
| `data.translations[].targetLanguage` | The version target language, falling back to its language work. |
| `data.translations[].status` | Stored version state: not-started, in-progress, completed, or failed. |
| `data.translations[].currentStep` | Optional dubbing pipeline step; progress is an optional numeric progress value. |
| `data.translations[].progress` | Optional dubbing progress value. |
| `data.translations[].createdAt` | Creation time normalized to Unix milliseconds; falls back to language-work creation time. |
| `data.translations[].completedAt` | Optional completion time in Unix milliseconds. |
| `data.translations[].failedAt` | Optional failure time in Unix milliseconds. |
| `data.translations[].timedOutAt` | Optional timeout time in Unix milliseconds. |
| `data.translations[].translatedVideoUrl` | Stored translated video URL, or an empty string when unavailable. |
| `data.translations[].translatedAudioUrl` | Stored translated audio URL, or an empty string when unavailable. |
| `data.translations[].error` | Optional \{code,message} when the version failed. |
| `data.translations[].settings` | Public version settings: voiceCloning, uploadType, keepBackgroundMusic, keepOriginalVoice, originalVoiceVolume, subtitles, smartSync, dubbingMode, voiceIsolatorOption, and optional translationQualityMode, cutBecauseFreeUser, originalDurationSeconds, cutDurationSeconds, voiceCloningSettings. |
| `data.translations[].settings.dubbingMode` | translate or dub-only. SmartSync is false for dub-only versions. |
| `data.translations[].lipSync` | Optional \{latest,history}; each entry has jobId, status, videoUrl, errorMessage, type, createdAt, and optional requestedAt, retryRequestedAt, completedAt, failedAt, timedOutAt, activeSpeakerDetectionEnabled, isRetried. Lip-sync times are stored ISO strings. |
| `data.translations[].dynamicSubtitles` | Optional object with used, inProgress, magicZooms, magicBrolls, magicBrollsPercentage, videoUrl, errorMessage, and optional removeSilencePace, removeBadTakes, templateName, requestedAt, rerunCount. requestedAt is Unix milliseconds. |
| `data.translations[].publicationAttempts` | Optional array of public publication attempts: id, status, origin, plus optional scheduledAt, processingStartedAt, publishedAt, failedAt, privacyStatus, url, videoId, errorMessage. |
| `data.translations[].publishedVideos` | Optional array with type, videoId, privacyStatus and optional url, datePublished, origin, scheduledAt, plannedPublicationId. |

## Operation notes

* This action does not return transcript text or raw segment documents. Use transcripts\_get for transcript content and translations\_list for language-work metadata.
* Missing optional nested fields are omitted from serialized JSON. Output URLs are empty strings until the corresponding output is available.
* The project status summarizes the workflow and newest translated version; inspect individual translations\[] entries when managing several languages.
* The error field describes a stored processing failure; a successfully retrieved failed project still returns a normal result.
* Stored failures return VoiceCheap error codes and fixed messages. Use the code and current resource state to decide how to recover.

## 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` | Correct the input using the schema. Invalid or inconsistent values are rejected before execution. |
| 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 | `FORBIDDEN` | The authenticated actor cannot access this project. |
| 403 | `INSUFFICIENT_SCOPE` | Grant every required permission or choose another credential. |
| 403 | `INTEGRATION_PLAN_UNSUPPORTED` | The account's integration limits could not be verified. |
| 403 | `SUBSCRIPTION_REQUIRED` | Use an active paid subscription. |
| 403 | `TEAM_OWNER_NOT_FOUND` | The effective team owner account could not be found. |
| 404 | `PROJECT_NOT_FOUND` | The project does not exist in the accessible account. |
| 429 | `INTEGRATION_MONTHLY_LIMIT_REACHED` | Wait for the monthly reset or change plan. |
| 429 | `INTEGRATION_RATE_LIMIT_REACHED` | Wait for Retry-After when present and use backoff. |
| 500 | `INTERNAL_ERROR` | Check saved request state and resource history before deciding to retry a mutation. |
| 503 | `SERVER_RESTARTING` | The server is restarting. Retry shortly and keep the same request identifier for a mutation. |

```json theme={null}
{
  "code": "INSUFFICIENT_SCOPE",
  "message": "This credential does not permit the requested action.",
  "status": 403,
  "details": {
    "requiredScopes": ["projects:read"]
  }
}
```


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