PopNowAPI
Prendi la chiave API

Video Translator API

di PopNow

Doppia una clip in 28 lingue con sottotitoli, fatturazione al minuto

popnow/video-translator-v1/video-translate
  • Traduttore video

Lo chiami con il nome di modello popnow/video-translator-v1/video-translate su POST /jobs/createTask, da 0,005 USD.

Nome del modellopopnow/video-translator-v1/video-translate
EndpointPOST https://api.popnow.ai/api/v1/jobs/createTask
# 1. Create the task. Keep the Idempotency-Key if you retry after a network error.
export IDEMPOTENCY_KEY="$(uuidgen)"
curl -X POST https://api.popnow.ai/api/v1/jobs/createTask \
  -H "Authorization: Bearer $POPNOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -d '{
  "model": "popnow/video-translator-v1/video-translate",
  "input": {
    "video_url": "https://media.popnow.ai/effects/flower-bloom-1abd6efb.mp4",
    "target_language": "en",
    "source_language": "auto"
  }
}'

# 2. Copy data.taskId from the response, then poll until state is succeeded, failed, canceled or expired.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $POPNOW_API_KEY"

L’input è costruito dallo schema qui sotto, quindi supera la verifica così com’è. Sostituisci prompt e link con i tuoi.

Prezzo

OpzioneUSD al secondo
Standard0,005 USD

Addebiti in USD · Tutte le opzioni e i prezzi: GET /models/popnow/video-translator-v1/video-translate

Parametri

Questi campi vengono dallo stesso schema con cui verifichiamo ogni richiesta. I campi non elencati vengono rifiutati.

  • video_urlstringObbligatorio

    La clip su cui lavorare.

    Intervallo
    Numero di caratteri: 1 – … · video/mp4, video/webm, video/quicktime, video/x-m4v
  • target_languagestringFacoltativo

    La lingua del doppiaggio. Deve essere diversa da quella del clip.

    Predefinito
    "en"
    Valori ammessi
    "en""es""fr""de""it""pt""nl""sv""da""no""fi""el""ru""pl""tr""he""id""ms""vi""th""tl""sw""zh-CN""zh-TW""ja""ko""ar""hi"
  • source_languagestringFacoltativo

    La lingua parlata nel clip. Rilevata in automatico; sceglila se ci sono musica, accento marcato o pause lunghe.

    Predefinito
    "auto"
    Valori ammessi
    "auto""en""zh-CN""zh-TW""yue""es""fr""de""it""pt""ru""ja""ko""ar""hi""tr""vi""th""id""ms""nl""pl""uk""sv""fi""da""no""nn""cs""sk""ro""hu""el""bg""hr""sr""sl""bs""mk""sq"+62
  • clone_voicebooleanFacoltativo

    Ogni parlante viene doppiato con una voce simile alla sua.

    Predefinito
    false
  • keep_background_audiobooleanFacoltativo

    Mantieni musica ed effetti originali sotto il doppiaggio; disattiva per solo voci.

    Predefinito
    true
  • speaker_countintegerFacoltativo

    Quante persone parlano, da 1 a 4. Lascia vuoto per rilevarlo.

    Valori ammessi
    1234
  • glossaryarray<object>Facoltativo

    Nomi e frasi con traduzione fissa, fino a 100 coppie.

    Intervallo
    Numero di elementi: 0 – 100
    Campi interni
    • glossary[].termstringObbligatorio

      Una parola o una breve espressione per aiutare la trascrizione.

      Intervallo
      Numero di caratteri: 1 – 100
    • glossary[].translationstringObbligatorio

      Come deve suonare il termine nel doppiaggio. Ripetilo per lasciarlo non tradotto.

      Intervallo
      Numero di caratteri: 1 – 100
JSON Schema completo
{
  "additionalProperties": false,
  "properties": {
    "clone_voice": {
      "default": false,
      "description": "Re-voice each speaker in a voice modelled on their own.",
      "type": "boolean"
    },
    "glossary": {
      "description": "Names and phrases with a fixed translation, up to 100 pairs.",
      "items": {
        "additionalProperties": false,
        "properties": {
          "term": {
            "description": "The word or phrase as it is spoken in the clip.",
            "maxLength": 100,
            "minLength": 1,
            "pattern": "^[^=]+$",
            "type": "string"
          },
          "translation": {
            "description": "How it should come out in the dub. Repeat the term to keep it untranslated.",
            "maxLength": 100,
            "minLength": 1,
            "pattern": "^[^=]+$",
            "type": "string"
          }
        },
        "required": [
          "term",
          "translation"
        ],
        "type": "object"
      },
      "maxItems": 100,
      "type": "array"
    },
    "keep_background_audio": {
      "default": true,
      "description": "Keep the original music and sound effects under the dub; off returns the translated voices only.",
      "type": "boolean"
    },
    "source_language": {
      "default": "auto",
      "description": "Language spoken in the clip. auto detects it; set it when there is music under the voice, a heavy accent or long pauses.",
      "enum": [
        "auto",
        "en",
        "zh-CN",
        "zh-TW",
        "yue",
        "es",
        "fr",
        "de",
        "it",
        "pt",
        "ru",
        "ja",
        "ko",
        "ar",
        "hi",
        "tr",
        "vi",
        "th",
        "id",
        "ms",
        "nl",
        "pl",
        "uk",
        "sv",
        "fi",
        "da",
        "no",
        "nn",
        "cs",
        "sk",
        "ro",
        "hu",
        "el",
        "bg",
        "hr",
        "sr",
        "sl",
        "bs",
        "mk",
        "sq",
        "lt",
        "lv",
        "et",
        "he",
        "fa",
        "ur",
        "ps",
        "sd",
        "bn",
        "as",
        "pa",
        "gu",
        "mr",
        "ne",
        "sa",
        "ta",
        "te",
        "kn",
        "ml",
        "si",
        "my",
        "km",
        "lo",
        "bo",
        "ka",
        "hy",
        "az",
        "kk",
        "uz",
        "tg",
        "tk",
        "mn",
        "ba",
        "tt",
        "be",
        "is",
        "fo",
        "cy",
        "br",
        "eu",
        "gl",
        "ca",
        "oc",
        "lb",
        "la",
        "mt",
        "af",
        "sw",
        "so",
        "am",
        "ha",
        "yo",
        "ln",
        "sn",
        "mg",
        "tl",
        "jw",
        "su",
        "haw",
        "mi",
        "ht",
        "yi"
      ],
      "type": "string"
    },
    "speaker_count": {
      "description": "Number of people speaking, 1 to 4. Leave it out to detect it.",
      "enum": [
        1,
        2,
        3,
        4
      ],
      "type": "integer"
    },
    "target_language": {
      "default": "en",
      "description": "Language to dub into. It must differ from the language spoken in the clip.",
      "enum": [
        "en",
        "es",
        "fr",
        "de",
        "it",
        "pt",
        "nl",
        "sv",
        "da",
        "no",
        "fi",
        "el",
        "ru",
        "pl",
        "tr",
        "he",
        "id",
        "ms",
        "vi",
        "th",
        "tl",
        "sw",
        "zh-CN",
        "zh-TW",
        "ja",
        "ko",
        "ar",
        "hi"
      ],
      "type": "string"
    },
    "video_url": {
      "contentMediaType": [
        "video/mp4",
        "video/webm",
        "video/quicktime",
        "video/x-m4v"
      ],
      "minLength": 1,
      "type": "string"
    }
  },
  "required": [
    "video_url"
  ],
  "type": "object"
}

Risposte, polling e callback

Tutti i modelli funzionano allo stesso modo: crei un task, poi lo interroghi o aspetti la callback.

Prima il prezzo

cURL
curl -X POST https://api.popnow.ai/api/v1/jobs/quote \
  -H "Authorization: Bearer $POPNOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "popnow/video-translator-v1/video-translate",
  "input": {
    "video_url": "https://media.popnow.ai/effects/flower-bloom-1abd6efb.mp4",
    "target_language": "en",
    "source_language": "auto"
  }
}'

Prima di eseguire, invia lo stesso corpo della richiesta a POST /jobs/quote per vedere il costo stimato e quello massimo in USD. Il preventivo non esegue alcuna richiesta né addebita il saldo.

Accettata

HTTP
HTTP/1.1 202 Accepted

{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "queued"
  },
  "request_id": "req_example_create"
}

HTTP 202 indica che la richiesta è stata accettata: il massimo in USD resta riservato fino al conteggio finale. Quando una richiesta viene accettata, riserviamo l’importo massimo del preventivo sul tuo saldo API. Al termine addebitiamo l’uso effettivo, senza superare la riserva, e liberiamo il resto. Se la richiesta fallisce, l’importo riservato viene sbloccato.

Controlla lo stato

cURL
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $POPNOW_API_KEY"

Controlla ogni pochi secondi allungando via via l’intervallo e fermati quando state è succeeded, failed, canceled o expired.

Task completato

JSON
{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "model": "popnow/video-translator-v1/video-translate",
    "state": "succeeded",
    "output": {
      "assets": [
        {
          "url": "https://cdn.popnow.ai/tasks/task_01k3m8x9q2z4v7n5p6r8s0t1w3/output.mp4?signature=FROM_RESPONSE",
          "expiresAt": "2026-10-17T12:20:00Z",
          "mime": "video/mp4",
          "width": 1280,
          "height": 720,
          "durationSeconds": 5
        }
      ]
    },
    "settled": true
  },
  "request_id": "req_example_record"
}

Scarica dall’url prima di expiresAt. Ti serve un link nuovo più tardi? Chiedilo con POST /common/download-url.

Verifica una callback

Node.js
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
// express.raw keeps the exact bytes that were signed; express.json would not match.
app.post("/hooks/popnow", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.header("X-Webhook-Timestamp");
  const signature = req.header("X-Webhook-Signature") ?? "";
  const body = JSON.parse(req.body.toString("utf8"));
  const taskId = body.data?.taskId ?? body.task_id;
  const digest = createHash("sha256").update(req.body).digest("hex");
  const expected = createHmac("sha256", process.env.POPNOW_WEBHOOK_SECRET)
    .update(`${taskId}.${timestamp}.${digest}`)
    .digest("base64");
  const ok = expected.length === signature.length && timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
  // Check the signature first, then reject anything older than five minutes.
  if (!ok || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.status(401).end();
  res.status(200).end(); // answer fast, then fetch the task and store its files
});

Con callBackUrl impostata ti inviamo il task completato. Verifica la firma sul corpo originale della richiesta prima di elaborarlo.

Invia un file locale

cURL
curl -X POST https://api.popnow.ai/api/v1/common/upload-url \
  -H "Authorization: Bearer $POPNOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contentType": "image/png", "bytes": 482113}'

# PUT the file bytes to data.uploadUrl with every header in data.headers, then commit it:
curl -X POST https://api.popnow.ai/api/v1/files/$FILE_ID/commit \
  -H "Authorization: Bearer $POPNOW_API_KEY"
# The commit returns a popnow://f/... reference. Put it in any image, video or
# audio field of the task input instead of a public https URL.

I link https pubblici funzionano così come sono. I file locali passano prima da upload-url e commit.