# Panjaya Dubbing Studio API


## Authentication

To authenticate with the API, you will need to provide your API key in the Authorization header of each request.

It should look like this:

```http
Authorization: Bearer panjaya-{YOUR_API_KEY}
```

## Languages support
Below is a list of supported languages and their corresponding locale codes that are used in Panjaya Dubbing Studio API.
Please note that some languages are marked as source languages only, meaning they can only be used as the source language
of the uploaded videos, while some are marked as target languages only - meaning they can only be translated into.

| Language           | Locale code | Source supported | Target supported |
|--------------------|-------------|------------------|------------------|
| Arabic             | ar-AE       | ✅               | ✅               |
| Bulgarian          | bg-BG       | ✅               | ✅               |
| Chinese            | zh-CN       | ✅               | ✅               |
| Croatian           | hr-HR       | ✅               | ✅               |
| Czech              | cs-CZ       | ✅               | ✅               |
| Danish             | da-DK       | ✅               | ✅               |
| Dutch              | nl-NL       | ✅               | ✅               |
| English            | en-US       | ✅               | ✅               |
| Filipino           | fil-PH      | ✅               | ✅               |
| Finnish            | fi-FI       | ✅               | ✅               |
| French             | fr-FR       | ✅               | ✅               |
| German             | de-DE       | ✅               | ✅               |
| Greek              | el-GR       | ✅               | ✅               |
| Hebrew             | he-IL       | ✅               | 🚫               |
| Hindi              | hi-IN       | ✅               | ✅               |
| Hungarian          | hu-HU       | ✅               | ✅               |
| Indonesian         | id-ID       | ✅               | ✅               |
| Italian            | it-IT       | ✅               | ✅               |
| Japanese           | ja-JP       | ✅               | ✅               |
| Korean             | ko-KR       | ✅               | ✅               |
| Lithuanian         | lt-LT       | ✅               | ✅               |
| Malay              | ms-MY       | ✅               | ✅               |
| Norwegian          | nb-NO       | ✅               | ✅               |
| Polish             | pl-PL       | ✅               | ✅               |
| Portuguese         | pt-BR       | ✅               | ✅               |
| Portuguese         | pt-PT       | ✅               | ✅               |
| Romanian           | ro-RO       | ✅               | ✅               |
| Russian            | ru-RU       | ✅               | ✅               |
| Slovak             | sk-SK       | ✅               | ✅               |
| Spanish            | es-ES       | ✅               | ✅               |
| Spanish            | es-MX       | ✅               | ✅               |
| Swedish            | sv-SE       | ✅               | ✅               |
| Tamil              | ta-IN       | ✅               | ✅               |
| Thai               | th-TH       | 🚫               | ✅               |
| Turkish            | tr-TR       | ✅               | ✅               |
| Ukrainian          | uk-UA       | ✅               | ✅               |
| Urdu               | ur-IN       | ✅               | 🚫               |
| Vietnamese         | vi-VN       | ✅               | ✅               |


## Error codes
Panjaya Dubbing Studio API uses standard HTTP status codes to indicate the success or failure of an API request.
In case of an error, the response body will include a detailed error message to help you identify and resolve the issue.

Here is a list of erroneous HTTP status codes and their general meanings:
- **401 Unauthorized**: The API key could not be validated
- **400 Bad Request**: The request could not be processed due to invalid input
- **403 Forbidden**: The request could not be completed due to account limitations
- **404 Not Found**: The requested resource was not found
- **429 Too Many Requests**: Too many requests
- **500 Internal Server Error**: An internal server error occurred


## Servers

```
https://api.panjaya.ai
```

## Security

### api_key

To access this endpoint, provide your Panjaya API key in the `Authorization` HTTP header when making requests. Use the bearer format as shown below.

Type: http
Scheme: bearer

## Download OpenAPI description

[Panjaya Dubbing Studio API](https://docs.panjaya.ai/_bundle/apis/index.yaml)

## Assets

Assets are the core resource in Panjaya Dubbing Studio. An asset represents a source video you want to dub into different languages.
Each asset can be dubbed into multiple languages, and every language is assigned a unique dubbing ID. You can
optionally add SRT files for better accuracy.

### Get assets

 - [GET /v1/assets/](https://docs.panjaya.ai/apis/assets/assets-get_assets.md): Get a paginated list of your assets.

This endpoint allows you to fetch all your assets with basic metadata, including the asset's current status and associated dubbings.

For available versions of each asset use the Get an asset endpoint.

### Creating a new asset

 - [POST /v1/assets/](https://docs.panjaya.ai/apis/assets/assets-create_asset.md): Creating an asset is the first step to dubbing your video with Panjaya Dubbing Studio.
This endpoint allows you to:

- Upload a source video
- Configure the necessary parameters to initiate the dubbing process

### Uploading the Source Video

- Use the media_url parameter to specify the publicly accessible URL of the source video you want to dub.
- Set the locale field to indicate the original language of the source video.
- It is recommended to set the speakers_count field to the number of distinct speakers in the video, to improve
accuracy and quality of the final video.

### Adding Target Languages

Define the languages into which you want to dub the video:

Panjaya's locale codes adhere to the IETF Language Tag standard, combining ISO 639-1 language codes and ISO 3166-1 country codes. Examples: en-US (English - United States), es-ES (Spanish - Spain), zh-CN (Chinese - China).

For each target language, you may optionally provide a valid SRT file, where applicable, in the designated srt field.

### Trimming the Video

You can optionally use the start_time and end_time parameters to trim your video, allowing you to dub a specific
section of your video.

Both parameters accept a number of seconds from the beginning of the video. For example, if you want to dub only the
first 2 minutes of your video, set end_time to 120.

If not specified, start_time defaults to 0 (beginning of the video), and end_time defaults to the end of the video.


### Status Updates via Callbacks

Optionally, you can configure a callback_url to receive real-time status updates about the dubbing process.

When a callback_url is specified, Panjaya will send updates whenever the status of an asset or any of its dubbing versions changes.

For detailed information on implementing callbacks, refer to the Callbacks section of this documentation.

### Models

The lips_model field specifies which lips model to use when generating versions under this asset.
This parameter is only applicable when lip correction is enabled. You can use it to fine-tune the balance between quality and performance.
* real_face (Default): Our highest-quality lips model, suitable for most use cases.
* real_face_turbo: Optimized for speed - up to 4× faster than real_face, while maintaining high quality.

### Voice Anonymization

The voice_anonymization field allows you to control the degree of voice anonymization applied to the dubbed voices. This is a float between 0.0 (no anonymization, default) and 1.0 (maximum anonymization).
This feature is useful for privacy or compliance requirements, or when you want to mask the original speaker's identity.

- 0.0: No anonymization. The cloned voice will closely match the original speaker.
- 1.0: Maximum anonymization. The voice will sound very different from the original.
- Any value between 0.0 and 1.0 will apply a proportional level of anonymization.

### Background Audio
Panjaya uses our SceneAware audio separation model
to separate speech from background audio in the source video.
This preserves the original background audio in the dubbed result, creating a more natural and immersive experience.

If you already have a clean background audio track (e.g., music and sound effects without speech), you can provide a publicly accessible URL to it
via the background_url field. Panjaya will then use this track directly instead of separating background audio from the source video.

### Uploading a new asset

 - [POST /v1/assets/upload](https://docs.panjaya.ai/apis/assets/assets-upload_asset.md): Upload an asset video file directly to Panjaya Dubbing Studio.

This endpoint allows you to upload a video file directly, saving the need to upload to an external storage service.
It accepts the same parameters as the Create Asset endpoint, except for the media_url parameter,
which is replaced by the video file input.

Note that this endpoint is structured as a multipart/form-data request,
where the request form field contains a JSON-serialized object with the asset parameters, and the video form field contains the video file to be uploaded.

You may additionally provide a background file to upload a clean background audio track.
Refer to Background Audio section under create asset endpoint.

### Get an asset

 - [GET /v1/assets/{asset_id}](https://docs.panjaya.ai/apis/assets/assets-get_asset.md): After creating an asset - either through the Panjaya Dubbing Studio API or by uploading it via the
Panjaya Dubbing Studio web interface - you can easily fetch detailed information about the asset by specifying its asset ID.

This endpoint allows you to access key metadata, including the asset's current status, associated dubbings, and
available versions.

### Asset processing failures
In case of an error while processing the asset, the asset status will be Failed, and the error field in this endpoint's response will contain helpful information for identifying the issue.

It contains an error code and a detailed error message to help you understand and resolve the issue. Here is a list of common error codes for assets:
- invalid_input: The input provided is invalid. Ensure all provided fields match the asset's properties.
- unsupported_media: We didnt find a valid video stream in the media file.
- empty_transcript: No spoken content was identified in the uploaded video.
- missing_audio_track: No audio tracks were found in the source video.
- video_duration_limit_reached: The video duration limit for your account has been reached.
- video_size_limit_reached: The file size of the requested video has exceeded the allowed size limit.
- time_out_of_range: The provided start_time or end_time is out of video range. Ensure that the timestamps are within the video duration.

### Add languages to an existing asset

 - [POST /v1/assets/{asset_id}/languages](https://docs.panjaya.ai/apis/assets/assets-add_languages.md): With this endpoint, you can add new languages to an existing asset. Once you make the request, Panjaya will initiate a new dubbing process for each added language.

Once the process is complete, you will be notified via email and the callback URL, if configured.

## Versions

After upload, an initial version of the dub is automatically created for each language. You can create additional
versions for each language to act as snapshots in time as you edit or to edit independently, with each version
identified by a unique version ID.

### Get a dubbing version

 - [GET /v1/versions/{version_id}](https://docs.panjaya.ai/apis/versions/versions-get_version.md): Retrieve detailed information about a specific dubbing version by providing its unique Version ID.

#### Response Details

The response includes metadata about the version, such as its current status and progress in the dubbing process.

The studio_url field provides a link to Panjaya Dubbing Studio, where you can fine-tune the dubs further.
This URL is not signed and requires authentication. Use the /studio_url endpoint (as described below) to pre-sign a
URL.

If the final video has been successfully generated, the response will also include a signed URL in the result_url
field. This URL allows you to securely download the fully synchronized video, complete with lip and body language alignment.

#### Version Status

The status field indicates the current state of the version. Possible values include:

- NotReady: The version is currently being prepared for editing.
- ReadyToEdit: The version is ready for editing and refinement in the Panjaya Dubbing Studio web interface.
- Generating: The version is being processed to generate the final video. Editing is temporarily disabled during this stage.
- Completed: The version has been successfully generated and is ready for download.
- Failed: An error occurred during the version processing.

### Revise version

 - [PATCH /v1/versions/{version_id}/revise](https://docs.panjaya.ai/apis/versions/versions-revise_version.md): Revert a generated dubbing version to editing mode in the Panjaya Dubbing Studio.

Once a dubbing version is successfully generated, its status changes to Completed, allowing only preview access to
 the generated video. If further edits are needed, use this endpoint to restore the version to an editable state.

Note: This action permanently removes the generated video and its associated result_url.

If studio_url_request provided this endpoint will return a URL to the Panjaya Dubbing Studio.
See the Create a signed URL endpoint for more details.

#### Version Status
This operation is only allowed if the version status is either Completed, ReadyToEdit or Failed. Upon execution,
 the version status will be updated to ReadyToEdit, allowing further modifications.

### Generate version

 - [POST /v1/versions/{version_id}/generate](https://docs.panjaya.ai/apis/versions/versions-generate_version.md): Initiate the generation process for a dubbing version. Once the process is complete,
and you'll receive notifications via email or a callback URL, if configured (see below). Your final video will
then be available for download.


#### Version Status
This operation is only allowed if the version status is ReadyToEdit. Upon execution,
 the version status will be updated to Generating, until the generation process is completed,
after which the version status will be updated to Completed.

### Create a signed URL for version

 - [POST /v1/versions/{version_id}/studio_url](https://docs.panjaya.ai/apis/versions/versions-get_studio_url_for_version.md): Create a URL that allows anyone with the link to access the Panjaya Dubbing Studio for a specific dubbing version.

This endpoint is useful for sharing a version with collaborators or reviewers who need to make edits or QC the dubbing,
without requiring them to log in.

The generated URL provides a pre-signed access to the Panjaya Dubbing Studio, where users can view the dubbing version, adjust the
text, and fine-tune the dubbing. The access is limited to the specific version and does not allow access to other
versions or assets.

Adjust the expiration_minutes parameter to specify the duration in minutes for which the URL will remain valid.
The default expiration time is 3 hours.

### Get a version's subtitles

 - [GET /v1/versions/{version_id}/srt](https://docs.panjaya.ai/apis/versions/versions-get_version_srt.md): Fetch the current version's source transcript or target translation, formatted as an SRT file.

Use the locality query parameter to indicate the desired subtitles - Set to source for fetching the transcript in the asset's source language,
or target for fetching the current translation in the version's target language.

## Callbacks

Learn how to use a callback URL to receive real-time status updates about the dubbing process.

### Receiving Status Updates

 - [POST /callback](https://docs.panjaya.ai/apis/callbacks/callback_callback_post.md): To stay informed about the progress of dubbing processes, you can configure a callback URL.

For every status update related to an asset or its versions, Panjaya will send an HTTP POST request to the specified URL.

Each update includes the following details:

* Asset ID: The unique identifier for the asset. This field is always included.
* Version ID: The unique identifier for the version. This field is optional and is included only for
version-related events.
* Version locale: The target language of the version. This field is optional and is included only for version-related events.
* Event type specifies the type of event that occurred. Possible values are:
  * asset_failed: An error occurred while processing the asset. In this case, version_id field will be null.
  * version_ready: The version is ready for QC and additional editing in the workspace
  * version_failed An error occurred during the dubbing process for this version.
  * version_generating The version final video generation process has started.
  * version_generated: The version has been successfully generated. A URL to download the final video will be
  provided in the result_url field in Get Version endpoint.
  * version_generate_failed: An error occurred during the video generation process.

### Signature verification
To ensure the authenticity of our callback requests, each request will include a signature in the X-Signature header.

The signature is calculated on the raw HTTP request's body, using the ES256 algorithm.

Optionally, you may use the X-Signature header to verify the authenticity of our request in your server.

Below is Panjaya's public key, to be used for verifying our callback's content:
text
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZbUzbbuVyzSv7zVmH6rKypr6ojSS
/86W9dU6mwbdfAtUAx+QI7GNxl/4H1QV2BuBrysabh56O/YXhnFJMh7Lng==
-----END PUBLIC KEY-----


And here's an example of how to verify the signature in Python:
python
import binascii
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.exceptions import InvalidSignature

PANJAYA_PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZbUzbbuVyzSv7zVmH6rKypr6ojSS\n/86W9dU6mwbdfAtUAx+QI7GNxl/4H1QV2BuBrysabh56O/YXhnFJMh7Lng==\n-----END PUBLIC KEY-----'
public_key = serialization.load_pem_public_key(PANJAYA_PUBLIC_KEY.encode())

def validate_panjaya_signature(request: Request) -> bool:
    raw_body = request.body()
    signature = request.headers.get("X-Signature")
    try:
        signature_bytes = binascii.unhexlify(signature)
        public_key.verify(signature_bytes, raw_body, ec.ECDSA(hashes.SHA256()))
        print("Signature is valid ✅")
        return True
    except InvalidSignature:
        print("Signature is invalid ❌")
        return False


Here's an example of the payload you can expect:

