Pular para o conteúdo

Documentaçãoda chave ao primeiro clipe

Tudo o que você precisa para uma primeira geração: uma chave, uma requisição, a tarefa e o webhook.

O acesso à API para desenvolvedores é por solicitação.

Visão geral

REST sobre HTTPS, com JSON na entrada e na saída. Toda geração é assíncrona.

URL base
https://api.pershot.app/v1
Autenticação
Authorization: Bearer seguido da sua chave. As chaves começam com sk_test_ ou sk_live_ e são exibidas uma única vez; armazenamos apenas um hash.
Permissões da chave
Cada chave tem escopos e, se você configurar no estúdio, uma lista de permissões de modelos e ferramentas. Uma chave com lista de permissões só pode usar o que está nela, inclusive as ferramentas: aumento de resolução de imagens, remoção de fundo, Aprimorar, sincronização labial, expansão de imagens e o editor de imagens. Qualquer outra coisa retorna 403 forbidden_model. 1080p ou 4K com Aprimorar exige tanto o modelo de vídeo quanto o Aprimorar.
Formato do erro
{ "error": { "code", "message", "param", "request_id" } }
IDs
Com prefixo conforme o tipo: job_, qt_, key_, up_.
Para agentes de IA
Texto simples para agentes de IA: entradas, valores aceitos, cada preço e um exemplo de requisiçãoseedance-2.0-fastseedance-2.0-miniqwen-image-2512-lightningqwen-image-2512qwen-image-edit-2511-lightningqwen-image-edit-2511

As gerações reais ainda não estão disponíveis. Deixe seu e-mail na página de um modelo e avisaremos uma única vez, quando estiverem disponíveis.

Início rápido

Quatro etapas, cada uma com a resposta que você deve ver.

  1. 01

    Obtenha uma chave

    O acesso à API para desenvolvedores é por solicitação: peça no estúdio, em Chaves de API. Quando estiver liberado, crie uma chave ali e copie: a chave completa é exibida uma única vez.

    Shell
    export API_KEY="sk_test_…"
  2. 02

    Envie uma requisição

    Envie a tomada por POST com um Idempotency-Key e um limite max_credits. Você recebe 202 e uma tarefa na fila na hora, e os créditos ficam reservados.

    POST /videos/generations
    curl https://api.pershot.app/v1/videos/generations \
      -H "Authorization: Bearer $API_KEY" \
      -H "Idempotency-Key: $(uuidgen)" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "seedance-2.0-fast",
        "prompt": "Perfume mist in hard side light. Slow push-in, black background, grain.",
        "duration": 5,
        "resolution": "720p",
        "aspect_ratio": "16:9",
        "generate_audio": true,
        "max_credits": 34
      }'
    Você deve ver
    {
      "id": "job_01J9ZK4T8W",
      "object": "job",
      "kind": "video",
      "status": "queued",
      "money_status": "reserved",
      "queue_position": 2,
      "requested_model": "seedance-2.0-fast",
      "credits_quoted": 34,
      "credits_charged": null
    }
  3. 03

    Consulte a tarefa

    Consulte a tarefa com GET até o status ser succeeded. A URL de saída é assinada e expira; baixe o que quiser guardar.

    GET /jobs/{id}
    curl https://api.pershot.app/v1/jobs/job_01J9ZK4T8W \
      -H "Authorization: Bearer $API_KEY"
    Você deve ver
    {
      "id": "job_01J9ZK4T8W",
      "object": "job",
      "kind": "video",
      "status": "succeeded",
      "money_status": "settled",
      "requested_model": "seedance-2.0-fast",
      "resolved_model": "seedance-2.0-fast",
      "credits_quoted": 34,
      "credits_charged": 34,
      "outputs": [
        {
          "kind": "video",
          "url": "https://…/job_01J9ZK4T8W.mp4?sig=…",
          "width": 1280,
          "height": 720,
          "duration_s": 5
        }
      ],
      "error": null
    }
  4. 04

    Receba o webhook

    Passe webhook_url e enviaremos cada mudança de estado por POST para ele, assinada com um carimbo de data/hora. Responda 2xx; entregas com falha são repetidas com intervalos crescentes.

    POST → webhook_url
    {
      "id": "evt_01J9ZKB1QX",
      "type": "job.succeeded",
      "created_at": "2026-09-29T14:02:31Z",
      "data": {
        "job": {
          "id": "job_01J9ZK4T8W",
          "object": "job",
          "status": "succeeded",
          "money_status": "settled",
          "credits_charged": 34,
          "outputs": [
            {
              "kind": "video",
              "url": "https://…/job_01J9ZK4T8W.mp4?sig=…",
              "width": 1280,
              "height": 720,
              "duration_s": 5
            }
          ]
        }
      }
    }

Endpoints

Todos os caminhos são relativos à URL base.

MétodoCaminhoO que faz
GET/v1/modelsModelos, recursos e status disponíveis para a sua conta
GET/v1/pricingPreços públicos; com autenticação, os preços da sua conta
POST/v1/quotesPlano, itens da cotação, cobrança máxima e validade (10 minutos)
POST/v1/videos/generationsGerar um vídeo; 202 e uma tarefa
POST/v1/images/generationsGerar ou editar uma imagem; 202 e uma tarefa
GET/v1/jobs/{id}Status, saídas como links assinados, custo real
GET/v1/jobsSuas tarefas, mais recentes primeiro
POST/v1/jobs/{id}/cancelPedir o cancelamento; os créditos reservados são reembolsados, a menos que o modelo já tenha aceitado a tarefa
GET/v1/balanceCréditos disponíveis e reservados, por categoria
GET/v1/usageUso por dia ou modelo, em JSON ou CSV
POST/v1/uploadsEnviar um JPEG, PNG ou WebP de até 10 MB

Cotações e limites de gastos

Toda geração precisa de um quote_id ou de um limite max_credits, nunca dos dois. Com um quote_id, a tarefa é executada por aquela cotação; com max_credits, ela só é executada se o preço for igual ou menor que o limite.

model: "auto" sempre exige max_credits. Uma cotação vale por 10 minutos; depois disso, você recebe quote_expired.

Idempotência

Envie um cabeçalho Idempotency-Key (de 1 a 255 caracteres ASCII visíveis) em toda requisição de geração.

A mesma chave dentro de 24 horas retorna a mesma tarefa com HTTP 200 em vez de 202, então tentar de novo após um timeout nunca cria nem cobra uma segunda tarefa.

Webhooks

Passe webhook_url em uma geração (ou em um lote) para receber as mudanças de estado dela. Cada evento é um POST cujo corpo JSON tem id, type, created_at e data: data.job para eventos de tarefa, data.batch para batch.completed.

Eventos

  • job.queued
  • job.processing
  • job.succeeded
  • job.failed
  • job.cancelled
  • batch.completed
  • Cada entrega tem um ID de evento, um carimbo de data/hora e uma assinatura. Verifique a assinatura antes de confiar no corpo.
  • Uma entrega conta quando o seu endpoint responde 2xx em até 10 segundos. Caso contrário, ela é tentada de novo após 1 min, 5 min, 30 min, 2 h e 6 h e depois marcada como falha; o suporte pode reenviá-la. Redirecionamentos não são seguidos.
  • As URLs de webhook precisam ser https. Hosts em endereços privados, de loopback ou reservados são recusados, tanto no envio quanto quando nos conectamos.

Cabeçalhos

X-Signature
t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>
X-Event-Id
O ID do evento, que também vem no corpo. Novas tentativas e reenvios mantêm o mesmo ID, então guarde-o e ignore um ID que você já processou.
Segredo de assinatura
Um segredo whsec_… por conta, no estúdio, em Chaves de API. A chave do HMAC é o segredo inteiro, com o prefixo.
Rotação
Depois da rotação, o segredo antigo continua assinando por 24 horas como uma segunda entrada v1. Aceite a entrega se qualquer v1 corresponder.

Calcule o HMAC sobre o corpo bruto, e não sobre uma cópia serializada de novo, compare em tempo constante e recuse carimbos de data/hora com mais de cinco minutos.

Verificar X-Signature
import { createHmac, timingSafeEqual } from "node:crypto";

// rawBody: the request body exactly as received, before any JSON parsing.
export function verifyWebhook(header, rawBody, secret, toleranceSec = 300) {
  let t = null;
  const signatures = [];
  for (const item of (header ?? "").split(",")) {
    const [key, value] = item.split("=", 2);
    if (key === "t") t = Number(value);
    if (key === "v1") signatures.push(Buffer.from(value, "hex"));
  }
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
  return signatures.some((s) => s.length === expected.length && timingSafeEqual(s, expected));
}

// verifyWebhook(req.headers["x-signature"], rawBody, process.env.WEBHOOK_SECRET)
// Answer 2xx quickly, and skip an X-Event-Id you have already handled.

Erros

Os códigos e os status HTTP são fixos; a mensagem é feita para pessoas.

CódigoHTTPQuando
invalid_request400Um campo está faltando ou fora do intervalo
unauthorized401Sem chave, chave revogada ou assinatura inválida
insufficient_credits402O saldo não cobre a reserva
forbidden_model403A lista de permissões da chave não inclui este modelo ou ferramenta
region_not_supported403O modelo não é oferecido na sua região
developer_api_closed403Uma chave de desenvolvedor enquanto a API para desenvolvedores está fechada; o acesso é por solicitação
member_connections_paused403Um login de membro (MCP, código de conexão ou linha de comando) enquanto a conexão do seu próprio agente de IA está pausada
not_found404Essa tarefa, cotação ou arquivo enviado não existe na sua conta
quote_expired409A cotação tem mais de 10 minutos
price_changed409O preço subiu acima do seu limite
content_rejected422O conteúdo foi recusado; nada é cobrado
rate_limited429Requisições demais para esta chave
concurrency_limited429Tarefas demais em execução nesta conta
internal_error500Algo falhou do nosso lado
upstream_unavailable503O modelo está indisponível; tente de novo mais tarde

Um resultado incerto do modelo não é um erro: a tarefa informa o status unknown e é verificada antes de qualquer reenvio.

Limites

Requisições
60 por minuto por chave, por padrão.
Simultaneidade
3 tarefas ao mesmo tempo por conta, por padrão; peça para aumentar.
Teto
A capacidade do modelo é um teto rígido. Mais chaves não aumentam a simultaneidade.

Imagens

POST /v1/images/generations aceita os mesmos cabeçalhos. Escolha um ID de modelo por nível e operação; os modelos de edição também precisam de image_url, e os modelos de geração o rejeitam.

Nívelgerareditar
Image MiniEconômico · rascunhoqwen-image-2512-lightningqwen-image-edit-2511-lightning
Image FastRecomendadoqwen-image-2512qwen-image-edit-2511

Limites por modelo

A página da API de cada modelo tem a tabela completa: o valor, a unidade, quem verifica e o que acontece acima do limite. GET /v1/models retorna os mesmos limites em JSON.

  • Validado por nósVerificamos e respondemos 400 antes de qualquer cotação ou reserva.
  • Validado pelo fornecedorO fornecedor verifica. Uma tarefa recusada por ele falha, e nada é cobrado.
  • RecomendadoNinguém verifica. Ficar dentro do limite dá resultados melhores.
ModeloPrincipais limitesTabela completa
seedance-2.0-fastSeedance 2.0 FastPrompt de 2 a 2.000 caracteres · 4 a 15 s · até 9 imagens de referência · imagens de 300 a 6.000 px por ladoAbrir a tabela
seedance-2.0-miniSeedance 2.0 MiniPrompt de 2 a 2.000 caracteres · 4 a 15 s · até 9 imagens de referência · imagens de 300 a 6.000 px por ladoAbrir a tabela
qwen-image-2512Qwen-Image-2512Prompt de 2 a 2.000 caracteres · 1K ou 2K · sem imagem de origemAbrir a tabela
qwen-image-2512-lightningQwen-Image-2512 · Lightning 4-stepPrompt de 2 a 2.000 caracteres · 1K ou 2K · sem imagem de origemAbrir a tabela
qwen-image-edit-2511Qwen-Image-Edit-2511Prompt de 2 a 2.000 caracteres · 1K ou 2K · uma imagem de origem, JPEG, PNG ou WebP de até 10 MBAbrir a tabela
qwen-image-edit-2511-lightningQwen-Image-Edit-2511 · LightningPrompt de 2 a 2.000 caracteres · 1K ou 2K · uma imagem de origem, JPEG, PNG ou WebP de até 10 MBAbrir a tabela

Envios

POST /v1/uploads identifica o tipo pelo próprio arquivo. Os links de envio duram 7 dias.

ArquivoFormatosTamanho máximoDuração máxima
Imagem: primeiro quadro, referência ou imagem a editarJPEG, PNG, WebP10 MB–
Vídeo: sincronização labialMP450 MB60 s
Áudio: sincronização labialMP3, WAV, M4A10 MB60 s

Nunca buscamos imagens em outros sites, então, nesses links, quem verifica o tamanho é o fornecedor, e uma tarefa que ele recusa não é cobrada. Os mesmos limites também vêm em JSON: GET /v1/models retorna um objeto limits para cada modelo.

Vindo do fal, do Replicate ou do WaveSpeed

Trocar a URL base e a chave não basta: toda requisição também precisa do ID do modelo no corpo, de um cabeçalho Idempotency-Key e de um limite de preço (max_credits ou um quote_id). O guia de migração mapeia cada campo do Seedance 2.0 e do Qwen-Image e lista o que não se transfere.