spicyapiDocumentação
Guias
Conteúdo principal

Tutorial de imagem para vídeo

Comece com uma imagem do seu computador e termine com um arquivo de vídeo baixado. Cada passo mostra a CLI, o SDK para TypeScript e o HTTP puro.

Este tutorial pega uma imagem do seu computador e a transforma num clipe de vídeo curto, que você baixa e guarda. Ele percorre o caminho inteiro, na ordem: escolher um modelo, enviar a imagem, conferir o preço, iniciar a geração, esperar por ela, baixar o resultado e lidar com qualquer coisa que dê errado. Você não precisa juntar as peças a partir das páginas de referência.

Cada passo mostra três jeitos de fazer a mesma coisa. Escolha um e use-o do começo ao fim:

JeitoEscolha seVocê precisa de
CLIVocê quer digitar comandos sem escrever código nenhumNode.js 22.13 ou mais recente
TypeScript SDKVocê está criando um programa em Node.js e quer ver as chamadas que ele fazNode.js 22.13 ou mais recente
HTTP (curl)Você quer ver a API crua, por exemplo para usar outra linguagem de programação mais tardeUm terminal bash com curl e jq (macOS, Linux ou WSL no Windows)

Prefere simplesmente pedir a um assistente de IA que faça isso? Veja Ou peça a um assistente de IA.

O que você vai criar

  • O resultado: um arquivo de vídeo curto, normalmente MP4, que começa na sua imagem e se movimenta do jeito que a sua frase descreve.
  • O seu tempo: conte com uns 20 minutos na primeira vez, a maior parte lendo. A geração em si costuma levar alguns minutos; alguns modelos e configurações demoram mais.
  • Onde roda: na SpicyAPI. O seu computador só envia a imagem e as instruções e depois baixa o arquivo pronto.

Quanto custa e como saber antes de pagar

Os preços são em dólares americanos. Eles dependem do modelo que você escolhe e das suas configurações, como a duração e a resolução do vídeo, por isso esta página não cita nenhum valor. Você pode ver o preço em três lugares, e nenhum deles custa nada:

  1. O catálogo atual (passo 1) lista todos os modelos que a sua conta pode usar, com os preços da sua conta. Vídeos costumam ser cobrados per_second, ou seja, por segundo de vídeo gerado. Quando um modelo lista vários preços, cada um corresponde a uma configuração, como uma resolução.
  2. Uma cotação (passo 3) dá o preço exato da sua requisição exata. Ela não inicia nada nem reserva dinheiro nenhum.
  3. A confirmação: a CLI mostra o preço de novo e espera o seu y antes de iniciar qualquer coisa.

O que acontece com o seu dinheiro:

  • Só o passo 4 custa dinheiro, assim como rodar de novo uma tarefa que falhou. Listar modelos, enviar a imagem, pedir cotação, esperar e baixar são gratuitos.
  • Quando uma geração começa, o valor cotado é separado do seu saldo (uma reserva). Esse valor é também o máximo que o vídeo pode custar.
  • Se o vídeo der certo, você é cobrado pelo que foi produzido, nunca acima da reserva, e o que sobrar volta para o seu saldo.
  • Tarefas que falham ou expiram normalmente liberam toda a reserva. Algumas recusas de conteúdo são cobradas pelo orçamento aceito, somente quando a página do modelo informa explicitamente essa exceção. Confira settled e cost para saber o valor final.
  • Contas novas começam sem nenhum valor gratuito, então primeiro você precisa ter saldo. Veja Cobrança.

Como funciona

sua imagem ──upload──▶ endereço spicy:// (vale por um dia)
                                      │
sua frase + configurações ────────────┴──▶ cotação (grátis) ──▶ iniciar a tarefa (dinheiro reservado)
                                                                         │
                                                queued ──▶ running ──▶ succeeded / failed / expired
                                                                         │
                                                     link de download (cerca de 20 minutos) ──▶ seu arquivo

Uma tarefa é um trabalho de geração. A SpicyAPI trabalha nela em segundo plano, então iniciá-la e buscar o resultado são duas ações separadas. Toda tarefa tem um ID que começa com job_; guarde-o, porque é assim que você encontra a tarefa de novo. As outras palavras usadas nesta página são explicadas no Glossário.

Antes de começar

Tenha uma conta, saldo e uma chave de API

Siga primeiro Prepare sua conta. Quando terminar, você deve ter:

  • uma conta na SpicyAPI com dinheiro no saldo;
  • uma chave de API, que começa com sk-spicy-;
  • essa chave guardada numa variável de ambiente chamada SPICY_API_KEY. Uma variável de ambiente é um valor com nome que o seu terminal entrega aos programas que ele roda; assim, a chave nunca precisa aparecer num comando nem no seu código.

Confira se a chave está definida na janela de terminal que você está usando, sem imprimir a chave inteira:

echo "${SPICY_API_KEY:0:9}"

Deve aparecer sk-spicy-. Se não aparecer nada, ou se aparecer um erro, a chave não está definida nesta janela; volte para Prepare sua conta.

Coloque a sua imagem numa pasta de trabalho

Crie uma pasta para este tutorial e abra o terminal nela. Todos os comandos desta página são rodados a partir dessa pasta, e todos os arquivos que eles criam vão parar ali.

mkdir -p ~/spicy-video
cd ~/spicy-video

Copie a sua imagem para essa pasta e dê a ela o nome start-frame.jpg (ou start-frame.png, se for um PNG; nesse caso, use esse nome em todos os lugares em que esta página diz start-frame.jpg).

O que faz uma boa imagem inicial:

  • Formato e tamanho: JPEG, PNG, WebP ou GIF, com até 10 MiB (cerca de 10 megabytes). Um modelo pode definir limites próprios mais rígidos, que você vai ver no passo 1.
  • O arquivo precisa ser mesmo desse formato. A SpicyAPI confere o conteúdo do arquivo, não só o nome. Fotos de celular muitas vezes são HEIC, e renomear uma delas para .jpg não a converte. Abra a foto e exporte ou salve como JPEG primeiro.
  • Proporção: a imagem vira o primeiro quadro do vídeo. Use uma imagem horizontal para um vídeo horizontal e uma vertical para um vídeo vertical; alguns modelos também oferecem a configuração aspect_ratio.
  • Direitos: use uma imagem que você tenha permissão para usar.

Prepare a ferramenta que você escolheu

A CLI é um programa chamado spicyapi que você roda no terminal. Instale-a uma vez (instruções completas, incluindo o Node.js: CLI: antes de começar):

npm install -g @spicyapi/cli
spicyapi --version

Se a instalação falhar com EACCES, pule-a e digite npx @spicyapi/cli em todos os lugares em que esta página digita spicyapi.

Depois confira se a sua chave funciona e se você tem saldo:

spicyapi balance

Devem aparecer available, held e total, em dólares americanos. available precisa ser maior que zero.

Os sete passos

Troque MODEL_ID_FROM_CATALOG por um ID de modelo real

MODEL_ID_FROM_CATALOG é um marcador, não um modelo. No passo 1, você escolhe um ID de modelo real no catálogo atual (live catalog): spicyapi models list, listModels() no SDK ou GET /api/v1/models. Cole esse ID em todos os lugares em que esta página mostra o marcador. Enviar o próprio marcador só devolve um erro de "não encontrado".

Usa Windows? Escolha a aba CLI ou SDK

A aba HTTP foi escrita para o bash. O Windows PowerShell trata aspas, quebras de linha (\) e $(...) de outro jeito, então esses comandos não rodam lá do jeito que estão escritos. No Windows, use a aba CLI ou SDK, ou rode os comandos HTTP dentro do WSL (Subsistema do Windows para Linux, em inglês Windows Subsystem for Linux).

1. Escolha um modelo e leia as configurações dele

Faça isto: liste os modelos de imagem para vídeo que a sua conta pode usar, escolha um e depois leia quais configurações ele aceita.

Liste os modelos:

spicyapi models list --modality video --task image-to-video --json

Deve aparecer uma lista em JSON. Esta aqui está resumida, e os valores aparecem como …:

{
  "total": 1,
  "items": [
    {
      "model": "MODEL_ID_FROM_CATALOG",
      "displayName": "Example video model",
      "modality": "video",
      "tasks": ["image-to-video"],
      "enabled": true,
      "available": true,
      "quantityField": "duration_seconds",
      "maxOutputDurationSeconds": 10,
      "taskTimeoutSeconds": 1800,
      "pricing": [
        { "variant": "720p", "unit": "per_second", "price": "…", "currency": "USD" },
        { "variant": "1080p", "unit": "per_second", "price": "…", "currency": "USD" }
      ]
    }
  ]
}

Escolha um modelo que tenha enabled e available iguais a true e copie o valor de model. Depois leia as configurações dele:

spicyapi models get MODEL_ID_FROM_CATALOG --json

A resposta tem os mesmos campos, mais inputSchema (as configurações) e examples (entradas que o servidor já conferiu).

O que olhar na lista:

CampoO que ele diz
modelO ID do modelo que você vai usar em todos os passos seguintes
enabled, availableSó use um modelo quando os dois forem true
pricingUm item por nível de preço: variant (a configuração a que ele se aplica, muitas vezes uma resolução), unit (normalmente per_second para vídeo) e price, em dólares americanos. regularPrice e offerLabel aparecem quando há um desconto
quantityFieldA configuração que decide quantas unidades você paga, normalmente duration_seconds. Vazio quer dizer uma unidade por vídeo
maxOutputDurationSecondsO vídeo mais longo que o modelo permite
taskTimeoutSecondsQuanto tempo uma geração pode rodar antes de parar como expired (e sem cobrança)

Como ler as configurações. inputSchema é a lista de configurações do modelo, escrita em JSON Schema:

  • required lista as configurações que você precisa enviar. Neste tipo de modelo, image_url sempre está entre elas, e a maioria também exige prompt.
  • properties lista todas as configurações que o modelo aceita, cada uma com um type, uma description em inglês simples e, muitas vezes, enum (os únicos valores permitidos), minimum e maximum, e default (usado quando você deixa a configuração de fora).
  • Dentro de cada configuração, x-ui guarda dicas de exibição. x-ui.affects_price: true quer dizer que mudar essa configuração muda o preço.
  • Alguns modelos acrescentam condições no nível mais alto do schema, como "se você enviar A, também precisa enviar B". O Spicy Schema explica como lê-las.
  • examples traz entradas completas que o servidor já conferiu, um ponto de partida seguro.

As configurações que você vai encontrar com mais frequência. Os nomes são os mesmos em todos os modelos, mas cada modelo aceita só algumas delas, com os seus próprios valores permitidos:

ConfiguraçãoO que fazMuda o preço?
image_urlA imagem inicial, usada como primeiro quadro. Aceita o endereço spicy:// do passo 2 ou um link público https://Não
promptO que deve acontecer: o movimento, a câmera, o clima. Descreva o movimento em vez de repetir o que a imagem já mostraNormalmente não
duration_secondsA duração do vídeo em segundos. Os valores permitidos estão em enum ou entre minimum e maximum; alguns modelos aceitam um valor especial, explicado na description da configuraçãoSim na maioria dos modelos: vídeo costuma ser cobrado por segundo, então um clipe mais longo custa mais
resolutionO tamanho da saída, como 720p ou 1080pNormalmente: resoluções mais altas costumam ter um preço próprio, mais alto
aspect_ratioO formato do vídeo, como 16:9, 9:16 ou 1:1. Alguns modelos oferecem adaptive, que segue a imagemConfira x-ui.affects_price
generate_audioGera também uma trilha sonora que combina com a imagemEm alguns modelos
last_image_urlUma imagem para o último quadro; veja Primeiro e último quadroPeça uma cotação para conferir
negative_promptO que o vídeo deve evitarNormalmente não
seedUm número que facilita comparar resultados entre execuções; ele não garante vídeos idênticosNão

Envie só as configurações que este modelo lista

Cada modelo tem a sua própria lista. Uma configuração que não está nas properties desse modelo, um nome digitado errado ou um valor fora do enum fazem a requisição inteira ser recusada com 400. Nada é cobrado, mas não copie a entrada de outro modelo sem conferir.

O que aconteceu: você leu o catálogo atual da sua conta, com os seus preços. Nada foi cobrado. Ler o catálogo conta para o limite de requisições da sua conta, então não é preciso repetir isso antes de cada vídeo; faça de novo quando trocar de modelo ou receber um 400.

2. Envie a sua imagem

Faça isto: envie start-frame.jpg e copie o endereço spicy:// que voltar. O upload é gratuito.

spicyapi files upload start-frame.jpg

Deve aparecer:

fileId: fil_01k3m8x9q2z4v7n5p6r8s0t1w3
status: ready
bytes: 402118
contentType: image/jpeg
sha256: a91f4c2e5b7d16809e3f2a4c8d0b61e7c4a890e5d2f71b3c609ae8427d15f0c6
uri: spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3
expiresAt: 2026-09-18T09:12:11Z

Copie o valor de uri exatamente como aparece.

O que aconteceu: a sua imagem foi guardada de forma privada para a sua conta, conferida (o formato real dela precisa corresponder ao tipo informado) e recebeu um endereço spicy://. Esse endereço não é um link da web: só a sua conta pode usá-lo, e só dentro da entrada de uma tarefa. Ele pode ser usado por um dia (veja expiresAt); depois disso, envie a imagem de novo.

A imagem já está na internet?

Se a imagem já está num endereço público https:// que abre sem login, você pode pular este passo e colocar esse endereço em image_url. Ele precisa continuar acessível enquanto o vídeo está sendo gerado.

Se o upload falhar:

O que apareceO que quer dizerO que fazer
Unsupported file type, ou a CLI ou o SDK diz que não consegue identificar o tipoO arquivo não é JPEG, PNG, WebP nem GIFConverta a imagem ou dê a ela a extensão certa
File exceeds the 10 MB limitA imagem tem mais de 10 MiBExporte uma versão menor
The uploaded file does not match the upload ticketO conteúdo do arquivo não é do tipo que o nome ou a declaração indicam, por exemplo uma foto HEIC renomeada para .jpgExporte a imagem como JPEG ou PNG de verdade e envie de novo
The upload ticket has expiredPassaram-se mais de uns 20 minutos entre o ticket e a confirmaçãoComece o upload de novo

3. Descreva o vídeo e confira o preço

Faça isto: escreva as suas configurações num arquivo chamado input.json e depois peça uma cotação.

Escreva o input.json. Comece com as duas configurações que todo modelo de imagem para vídeo aceita. Coloque a sua própria frase em prompt e troque o valor de image_url pelo uri que você copiou no passo 2:

input.json
{
  "prompt": "The camera slowly pushes in while rain runs down the window and neon light flickers",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"
}

As configurações que você deixar de fora usam o default do modelo. Para escolhê-las você mesmo, acrescente só configurações que as properties do seu modelo listam, com valores que ele permite. Por exemplo, se o seu modelo lista duration_seconds e resolution e permite estes valores:

{
  "prompt": "The camera slowly pushes in while rain runs down the window and neon light flickers",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "duration_seconds": 5,
  "resolution": "720p"
}

Salve o arquivo na sua pasta de trabalho:

Cole todas as linhas de uma vez, depois de colocar nelas o seu próprio texto e o seu uri:

cat > input.json <<'EOF'
{
  "prompt": "The camera slowly pushes in while rain runs down the window and neon light flickers",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"
}
EOF

Use aspas retas comuns ("), não aspas curvas, e não coloque vírgula depois da última configuração.

Peça a cotação:

spicyapi tasks quote --model MODEL_ID_FROM_CATALOG --input-file input.json

Deve aparecer (os valores aparecem como …):

quoteId: eyJ2IjoxLCJtIjoi…
model: MODEL_ID_FROM_CATALOG
estimatedCost: …
maxCharge: …
currency: USD
quantity: 5
unit: per_second
expiresAt: 2026-09-17T08:05:00Z

O que aconteceu: a SpicyAPI conferiu a sua entrada com as configurações do modelo e calculou o preço desta requisição exata. Nada foi iniciado e nada foi cobrado. estimatedCost é o valor que vai ser reservado se você iniciar agora, e maxCharge é o máximo que pode custar. quantity e unit mostram pelo que você paga, como 5 segundos.

Uma cotação vale por cinco minutos e só para esta entrada exata. Mude a duração ou a resolução e peça outra cotação para comparar preços. A cotação faz as mesmas verificações que iniciar a tarefa, então os problemas aparecem aqui sem custo: um 400 quer dizer que a entrada não corresponde às configurações do modelo (corrija o input.json com base no passo 1), e um 40201 quer dizer que o seu saldo não cobriria o valor. O passo 7 lista os outros códigos.

Quer fazer um teste sem a sua própria imagem?

Os examples do modelo, vistos no passo 1, são entradas completas que o servidor já conferiu. Você pode colocar um deles no input.json do jeito que está, pedir a cotação e gerar, para ver o fluxo inteiro funcionando antes de usar a sua própria imagem.

4. Inicie a geração

Este passo custa dinheiro

Iniciar a geração separa o valor cotado do seu saldo. Depois que a SpicyAPI aceita, a tarefa não pode ser cancelada: ela roda até o fim e é cobrada se der certo. Tarefas que falham ou expiram normalmente liberam toda a reserva. Algumas recusas de conteúdo são cobradas pelo orçamento aceito, somente quando a página do modelo informa explicitamente essa exceção. Confira settled e cost para saber o valor final.

A chave de idempotência, em palavras simples. É um rótulo para um vídeo, como um número de pedido. Se a sua conexão cair e você não tiver certeza de que o vídeo começou, envie a mesma requisição de novo com o mesmo rótulo: a SpicyAPI devolve a tarefa que já tinha iniciado em vez de iniciar, e cobrar, uma segunda. Um rótulo vale por 24 horas com a mesma chave de API. Use um rótulo novo para outro vídeo: o mesmo rótulo com uma entrada diferente é recusado com 409. Mais em Idempotência.

Faça isto:

spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json

A CLI pede a cotação de novo, mostra o preço e espera por você:

Estimated charge: USD …; maximum charge: USD …. Quote expires: 2026-09-17T08:05:00Z.
Idempotency-Key: 4f6755a5-0d72-4420-9f6b-9faf0e2b0241
Create a billable task with model MODEL_ID_FROM_CATALOG? … Continue? [y/N]

Digite y e aperte Enter. Qualquer outra resposta cancela, e nada é cobrado. Copie o valor de Idempotency-Key para algum lugar antes de responder: a CLI cria um rótulo novo a cada execução, e você vai precisar deste se a conexão cair.

Deve aparecer:

idempotencyKey: 4f6755a5-0d72-4420-9f6b-9faf0e2b0241
taskId: job_01k3m8x9q2z4v7n5p6r8s0t1w3
state: queued
estimatedCost: …
deadlineAt: 2026-09-17T08:35:00Z

Copie o taskId.

O que aconteceu: a SpicyAPI aceitou a geração, que agora é uma tarefa, e separou estimatedCost do seu saldo. Esse é também o máximo que este vídeo pode custar. state: queued quer dizer que a tarefa está esperando a vez dela. deadlineAt é o horário limite para ela terminar; se não estiver pronta até lá, ela acaba como expired, e nada é cobrado. deadlineAt não é quando os seus arquivos expiram.

Passar a cotação adiante quer dizer "só aceite isto pelo preço que me mostraram". Se o preço ou a entrada tiverem mudado nesse meio-tempo, a requisição é recusada com 40901 em vez de reservar outro valor. A CLI faz isso por você.

Se a conexão caiu e você nunca viu um ID de tarefa, não comece simplesmente de novo com um rótulo novo: isso criaria, e cobraria, um segundo vídeo. Repita a requisição com o mesmo rótulo:

  • CLI: spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json --idempotency-key <the value you copied>, trocando <the value you copied> pelo valor que você copiou. Veja Retomar uma tarefa depois que a espera foi interrompida.
  • SDK: rode node generate.mjs --yes de novo; ele reaproveita o idempotency-key.txt.
  • HTTP: rode de novo o bloco "Iniciar o vídeo"; ele reaproveita o idempotency-key.txt.

Se o passo 4 foi recusado, nada foi criado e nada foi cobrado; o motivo e a solução estão no passo 7.

5. Espere o vídeo ficar pronto

Faça isto: consulte a tarefa até ela terminar. Vídeos costumam levar alguns minutos.

spicyapi tasks wait job_01k3m8x9q2z4v7n5p6r8s0t1w3 --wait-timeout-ms 1800000 --json

Use o seu próprio ID de tarefa. --wait-timeout-ms 1800000 espera até 30 minutos em vez dos 10 padrão.

Deve aparecer, quando a tarefa terminar (resumido):

{
  "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "model": "MODEL_ID_FROM_CATALOG",
  "state": "succeeded",
  "output": {
    "assets": [
      {
        "key": "tasks/2026/09/17/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.mp4",
        "url": "https://…",
        "expiresAt": "2026-09-17T08:40:00Z",
        "mime": "video/mp4",
        "durationSeconds": 5,
        "width": 1280,
        "height": 720,
        "bytes": 4839211
      }
    ]
  },
  "cost": "…",
  "settled": true
}

Da próxima vez, você pode juntar os passos 4 e 5 acrescentando --wait ao tasks create.

O que aconteceu: a sua ferramenta perguntou à SpicyAPI sobre a tarefa a cada poucos segundos. Os estados são queued (esperando), running (sendo gerada) e depois um estado final: succeeded, failed ou expired. Depois do sucesso, o arquivo é copiado para o armazenamento da própria SpicyAPI, o que leva mais alguns segundos; até lá, o resultado mostra pending: true. cost é definitivo quando settled é true.

  • Fechar o terminal ou apertar Ctrl + C não cancela a tarefa. Só interrompe a espera. Guarde o ID da tarefa e rode este passo de novo mais tarde.
  • Não consulte com mais frequência do que a cada poucos segundos. Consultar uma tarefa usa a capacidade de leitura da conta, independentemente do envio de tarefas; veja Limites de requisição.
  • Para um aplicativo ou um servidor, deixe a SpicyAPI avisar você quando a tarefa terminar, em vez de ficar perguntando: veja Receba um aviso em vez de esperar.

6. Baixe e guarde o vídeo

Faça isto: obtenha um link de download novo e salve o arquivo no seu computador.

Obtenha um link novo:

spicyapi files download-url job_01k3m8x9q2z4v7n5p6r8s0t1w3
key: tasks/2026/09/17/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.mp4
url: https://…
expiresAt: 2026-09-17T08:52:00Z

Cole a url num navegador para baixar o vídeo, ou salve pelo terminal (mantenha as aspas, porque o link contém caracteres &):

curl -L -o my-video.mp4 "PASTE_THE_URL_HERE"

No Windows PowerShell, digite curl.exe em vez de curl. Se uma tarefa produziu vários arquivos, spicyapi tasks get <task-id> --json lista todos, e --key escolhe um deles.

O que aconteceu: todo resultado vem com um link de download direto. O link funciona por cerca de 20 minutos e não precisa de chave de API; nunca acrescente a sua chave a ele. Quando ele expirar, consulte a tarefa de novo (ou use files download-url) para obter um link novo.

Guarde a sua própria cópia

A SpicyAPI guarda os arquivos gerados por no máximo cerca de 14 dias, menos se a configuração de retenção da sua conta for mais curta, e depois os apaga para sempre. A imagem que você enviou pode ser usada por um dia, e o texto do seu prompt é apagado depois de 30 dias, por padrão. O registro da tarefa e do custo dela é mantido. Para apagar antes os arquivos e o prompt de uma tarefa concluída, use spicyapi tasks purge, purgeTask() ou POST /api/v1/jobs/purge; isso apaga só o conteúdo e não é reembolso. Veja Retenção e destruição.

7. Quando algo dá errado

Os problemas são de dois tipos, e cada um é tratado de um jeito.

Uma requisição é recusada. O seu comando ou a sua chamada recebe um erro na hora. Nada foi criado e nada foi cobrado. A mensagem diz o motivo, e o erro traz um code e um ID de requisição (req_…) para você informar se falar com o suporte.

CódigoO que quer dizerO que fazer
400, ou um código mais específico que começa com 400A entrada não corresponde às configurações do modelo: falta uma configuração obrigatória; há uma configuração desconhecida ou digitada errado; um valor não é permitido; um endereço spicy:// expirou ou pertence a outra conta; o modelo não consegue atender agora essa combinação de configurações; ou o endereço de callback é inválidoCompare o input.json com as configurações do passo 1 e corrija. Se o endereço expirou, envie a imagem de novo
401A chave de API está faltando, foi digitada errado ou foi revogadaConfira a SPICY_API_KEY como em Antes de começar
40201O seu saldo não cobre o valor a ser reservadoAdicione saldo em Faturamento, no console
40202Um limite de gasto da sua chave (diário, mensal ou acumulado) foi atingidoAumente o limite na página Chaves de API ou espere ele recomeçar
403, 40301Esta chave não pode usar este modelo, ou a requisição veio de um lugar de onde ela não é permitidaConfira os Modelos permitidos e os IPs permitidos da chave na página Chaves de API
404Não existe modelo com esse ID para a sua conta (ou você enviou o marcador), ou não existe tarefa com esse ID para esta chaveCopie o ID exato de novo; use a mesma chave que criou a tarefa
409Esta chave de idempotência já foi usada para uma requisição diferenteUse um rótulo novo para um vídeo novo
40901A cotação expirou (cinco minutos) ou o preço mudouPeça uma nova cotação e inicie de novo
429Requisições demais em pouco tempoEspere o número de segundos que o erro informa e continue mais devagar
50301O modelo não pode receber trabalho novo agoraTente de novo mais tarde ou escolha outro modelo

A tarefa falha. A tarefa foi aceita, mas termina como failed ou expired em vez de succeeded. A tarefa mostra um errorCode, que diz o motivo, e uma errorMessage, com mais detalhes em palavras. Tarefas que falham ou expiram normalmente liberam toda a reserva. Algumas recusas de conteúdo são cobradas pelo orçamento aceito, somente quando a página do modelo informa explicitamente essa exceção. Confira settled e cost para saber o valor final.

Para lê-los:

spicyapi tasks get job_01k3m8x9q2z4v7n5p6r8s0t1w3

Olhe state, errorCode e errorMessage.

Depois decida o que fazer pelo errorCode, não pela redação da mensagem:

errorCodeO que quer dizerO que fazer
rate_limited, upstream_unavailable, upstream_failedA geração estava ocupada ou temporariamente indisponívelRode de novo depois de uma pausa curta
timeout (ou o estado é expired)O vídeo não ficou pronto a tempoTente mais uma vez; se acontecer de novo, escolha uma duração menor ou uma resolução mais baixa e inicie uma tarefa nova
generation_failedA geração rodou, mas não produziu nadaA mesma entrada costuma falhar do mesmo jeito. Mude o prompt ou a imagem e inicie uma tarefa nova
invalid_assetA imagem não pôde ser usada, por exemplo porque o upload expirou ou o arquivo não pôde ser lidoEnvie a imagem de novo e inicie uma tarefa nova com o endereço novo
invalid_request, unsupported_combinationAs configurações não foram aceitasMude as configurações e inicie uma tarefa nova
content_rejectedO modelo escolhido recusou esta requisição pelas regras deleMude o prompt ou a imagem, ou escolha outro modelo

Qualquer outro valor deve ser tratado como upstream_failed. A lista completa está em Erros.

Rode de novo uma tarefa que falhou. Uma nova tentativa cria uma tarefa nova, com o mesmo modelo e a mesma entrada, pelo preço atual do modelo. Ela custa dinheiro, como o passo 4, e mantém a entrada original: se essa entrada usava um upload que já expirou, envie o arquivo de novo e inicie uma tarefa nova.

spicyapi tasks retry job_01k3m8x9q2z4v7n5p6r8s0t1w3 --wait --wait-timeout-ms 1800000

Ele pede confirmação, mas, ao contrário do tasks create, não mostra o preço antes. Para ver o preço, rode o comando tasks quote do passo 3.

Só tarefas failed e expired podem ser repetidas. Para ter outra versão de um vídeo que deu certo, volte ao passo 3 com um rótulo novo. Não existe jeito de cancelar uma tarefa depois que ela foi aceita. Mais em Execução e novas tentativas.

Ou peça a um assistente de IA

Se você usa um assistente de IA com suporte a MCP, como Claude Code, Cursor ou Codex, o servidor MCP da SpicyAPI permite que ele faça os sete passos por você. Configure-o uma vez seguindo Servidor MCP: configure o seu cliente e depois peça com as suas próprias palavras, por exemplo:

Envie para a SpicyAPI a imagem que está em /Users/me/spicy-video/start-frame.jpg. Encontre os modelos de imagem para vídeo que a minha chave pode usar e peça uma cotação de um clipe de 5 segundos nos dois mais baratos. Depois, quando eu confirmar, gere o vídeo com o mais barato, espere ele ficar pronto e me passe o link de download.

No Windows, informe o caminho como C:\Users\me\spicy-video\start-frame.jpg.

O que acontece:

  1. spicyapi_upload_file envia a imagem e obtém o endereço spicy:// dela. É gratuito, mas o arquivo é enviado de verdade, então diga exatamente qual arquivo você quer. Por padrão, só arquivos dentro da sua pasta pessoal podem ser lidos; veja Arquivos locais.
  2. spicyapi_models_list e spicyapi_model_get encontram um modelo e as configurações dele, e spicyapi_task_quote calcula o preço das opções. Tudo gratuito.
  3. spicyapi_task_create para e pergunta a você, mostrando o modelo, o custo estimado, a cobrança máxima e quando a cotação expira. Nada é cobrado até você confirmar, e o assistente não pode confirmar por você.
  4. spicyapi_task_wait espera até cinco minutos por vez, então, num vídeo mais longo, o assistente pode precisar esperar mais de uma vez. Depois ele entrega o link de download, que funciona por cerca de 20 minutos.

Mais exemplos e todas as ferramentas: Servidor MCP.

Para ir além

Primeiro e último quadro

Alguns modelos de imagem para vídeo também aceitam last_image_url: uma segunda imagem, na qual o vídeo termina. Para saber se o seu aceita, procure last_image_url nas properties do passo 1. Se ela não estiver lá, o modelo não tem suporte a isso, e enviá-la faz a requisição ser recusada com 400.

Envie as duas imagens como no passo 2 e depois coloque os dois endereços no input.json:

{
  "prompt": "The flower slowly opens as morning light spreads across the table",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "last_image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w4"
}

A description da configuração explica como esse modelo usa a imagem final. Peça uma nova cotação antes de iniciar, para ver se a segunda imagem muda o preço.

Vários vídeos

  • Reaproveite o upload. Um endereço spicy:// pode ser usado em várias tarefas até o expiresAt dele, a menos que a retenção de uploads da sua conta esteja configurada para apagá-los assim que uma tarefa termina.
  • Um rótulo por vídeo. Dê a cada vídeo a sua própria chave de idempotência, como campaign-clip-1 e campaign-clip-2. Assim, rodar o seu script de novo devolve os vídeos já iniciados em vez de pagar por eles duas vezes.
  • Não inicie tudo de uma vez. Cada tarefa em andamento tem dinheiro reservado, um limite de gasto recusa com 40202 as tarefas que passarem dele, e cada consulta de status conta para o seu limite de requisições. Comece com duas por vez.

Scripts prontos: Rodar um lote com concorrência limitada (SDK) e Rodar a CLI a partir de um script.

Receba um aviso em vez de esperar

Para um site ou um serviço que roda em segundo plano, manter um programa ligado só para perguntar "já terminou?" é desperdício. Em vez disso, dê à tarefa um endereço de callback: um endereço web público, no seu próprio servidor, que a SpicyAPI chama uma vez, quando a tarefa termina, com os mesmos detalhes da tarefa que o passo 5 mostra.

Do que você precisa:

  • um servidor acessível pela internet num endereço https://, na porta padrão (localhost é recusado);
  • a sua chave de assinatura de webhook, que fica no console, para que o seu servidor possa conferir se cada chamada veio mesmo da SpicyAPI;
  • código que confira a assinatura, responda rápido e saiba lidar com a mesma notificação chegando duas vezes.

Webhooks explica o formato, a assinatura e o calendário de novas tentativas, e o SDK tem um receptor mínimo. Tenha um plano B: de vez em quando, consulte as tarefas que já passaram bastante do deadlineAt sem que nenhuma notificação tenha chegado.

Acrescente o endereço de callback quando pedir a cotação e iniciar a tarefa:

spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json --callback-url https://your-app.example.com/hooks/spicy

A CLI inclui o endereço na própria cotação, então a conferência de preço continua batendo.

Próximos passos

Nesta página