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:
| Jeito | Escolha se | Você precisa de |
|---|---|---|
| CLI | Você quer digitar comandos sem escrever código nenhum | Node.js 22.13 ou mais recente |
| TypeScript SDK | Você está criando um programa em Node.js e quer ver as chamadas que ele faz | Node.js 22.13 ou mais recente |
| HTTP (curl) | Você quer ver a API crua, por exemplo para usar outra linguagem de programação mais tarde | Um 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:
- 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. - Uma cotação (passo 3) dá o preço exato da sua requisição exata. Ela não inicia nada nem reserva dinheiro nenhum.
- A confirmação: a CLI mostra o preço de novo e espera o seu
yantes 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
settledecostpara 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 arquivoUma 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-videoCopie 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
.jpgnã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 --versionSe 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 balanceDevem 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 --jsonDeve 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 --jsonA resposta tem os mesmos campos, mais inputSchema (as configurações) e examples (entradas que o servidor já conferiu).
O que olhar na lista:
| Campo | O que ele diz |
|---|---|
model | O ID do modelo que você vai usar em todos os passos seguintes |
enabled, available | Só use um modelo quando os dois forem true |
pricing | Um 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 |
quantityField | A configuração que decide quantas unidades você paga, normalmente duration_seconds. Vazio quer dizer uma unidade por vídeo |
maxOutputDurationSeconds | O vídeo mais longo que o modelo permite |
taskTimeoutSeconds | Quanto 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:
requiredlista as configurações que você precisa enviar. Neste tipo de modelo,image_urlsempre está entre elas, e a maioria também exigeprompt.propertieslista todas as configurações que o modelo aceita, cada uma com umtype, umadescriptionem inglês simples e, muitas vezes,enum(os únicos valores permitidos),minimumemaximum, edefault(usado quando você deixa a configuração de fora).- Dentro de cada configuração,
x-uiguarda dicas de exibição.x-ui.affects_price: truequer 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.
examplestraz 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ção | O que faz | Muda o preço? |
|---|---|---|
image_url | A imagem inicial, usada como primeiro quadro. Aceita o endereço spicy:// do passo 2 ou um link público https:// | Não |
prompt | O que deve acontecer: o movimento, a câmera, o clima. Descreva o movimento em vez de repetir o que a imagem já mostra | Normalmente não |
duration_seconds | A 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ção | Sim na maioria dos modelos: vídeo costuma ser cobrado por segundo, então um clipe mais longo custa mais |
resolution | O tamanho da saída, como 720p ou 1080p | Normalmente: resoluções mais altas costumam ter um preço próprio, mais alto |
aspect_ratio | O formato do vídeo, como 16:9, 9:16 ou 1:1. Alguns modelos oferecem adaptive, que segue a imagem | Confira x-ui.affects_price |
generate_audio | Gera também uma trilha sonora que combina com a imagem | Em alguns modelos |
last_image_url | Uma imagem para o último quadro; veja Primeiro e último quadro | Peça uma cotação para conferir |
negative_prompt | O que o vídeo deve evitar | Normalmente não |
seed | Um número que facilita comparar resultados entre execuções; ele não garante vídeos idênticos | Nã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.jpgDeve aparecer:
fileId: fil_01k3m8x9q2z4v7n5p6r8s0t1w3
status: ready
bytes: 402118
contentType: image/jpeg
sha256: a91f4c2e5b7d16809e3f2a4c8d0b61e7c4a890e5d2f71b3c609ae8427d15f0c6
uri: spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3
expiresAt: 2026-09-18T09:12:11ZCopie 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 aparece | O que quer dizer | O que fazer |
|---|---|---|
Unsupported file type, ou a CLI ou o SDK diz que não consegue identificar o tipo | O arquivo não é JPEG, PNG, WebP nem GIF | Converta a imagem ou dê a ela a extensão certa |
File exceeds the 10 MB limit | A imagem tem mais de 10 MiB | Exporte uma versão menor |
The uploaded file does not match the upload ticket | O conteúdo do arquivo não é do tipo que o nome ou a declaração indicam, por exemplo uma foto HEIC renomeada para .jpg | Exporte a imagem como JPEG ou PNG de verdade e envie de novo |
The upload ticket has expired | Passaram-se mais de uns 20 minutos entre o ticket e a confirmação | Comece 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:
{
"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"
}
EOFUse 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.jsonDeve 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:00ZO 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.jsonA 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:00ZCopie 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 --yesde novo; ele reaproveita oidempotency-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 --jsonUse 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_01k3m8x9q2z4v7n5p6r8s0t1w3key: tasks/2026/09/17/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.mp4
url: https://…
expiresAt: 2026-09-17T08:52:00ZCole 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ódigo | O que quer dizer | O que fazer |
|---|---|---|
400, ou um código mais específico que começa com 400 | A 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álido | Compare o input.json com as configurações do passo 1 e corrija. Se o endereço expirou, envie a imagem de novo |
401 | A chave de API está faltando, foi digitada errado ou foi revogada | Confira a SPICY_API_KEY como em Antes de começar |
40201 | O seu saldo não cobre o valor a ser reservado | Adicione saldo em Faturamento, no console |
40202 | Um limite de gasto da sua chave (diário, mensal ou acumulado) foi atingido | Aumente o limite na página Chaves de API ou espere ele recomeçar |
403, 40301 | Esta chave não pode usar este modelo, ou a requisição veio de um lugar de onde ela não é permitida | Confira os Modelos permitidos e os IPs permitidos da chave na página Chaves de API |
404 | Nã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 chave | Copie o ID exato de novo; use a mesma chave que criou a tarefa |
409 | Esta chave de idempotência já foi usada para uma requisição diferente | Use um rótulo novo para um vídeo novo |
40901 | A cotação expirou (cinco minutos) ou o preço mudou | Peça uma nova cotação e inicie de novo |
429 | Requisições demais em pouco tempo | Espere o número de segundos que o erro informa e continue mais devagar |
50301 | O modelo não pode receber trabalho novo agora | Tente 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_01k3m8x9q2z4v7n5p6r8s0t1w3Olhe state, errorCode e errorMessage.
Depois decida o que fazer pelo errorCode, não pela redação da mensagem:
errorCode | O que quer dizer | O que fazer |
|---|---|---|
rate_limited, upstream_unavailable, upstream_failed | A geração estava ocupada ou temporariamente indisponível | Rode de novo depois de uma pausa curta |
timeout (ou o estado é expired) | O vídeo não ficou pronto a tempo | Tente mais uma vez; se acontecer de novo, escolha uma duração menor ou uma resolução mais baixa e inicie uma tarefa nova |
generation_failed | A geração rodou, mas não produziu nada | A mesma entrada costuma falhar do mesmo jeito. Mude o prompt ou a imagem e inicie uma tarefa nova |
invalid_asset | A imagem não pôde ser usada, por exemplo porque o upload expirou ou o arquivo não pôde ser lido | Envie a imagem de novo e inicie uma tarefa nova com o endereço novo |
invalid_request, unsupported_combination | As configurações não foram aceitas | Mude as configurações e inicie uma tarefa nova |
content_rejected | O modelo escolhido recusou esta requisição pelas regras dele | Mude 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 1800000Ele 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:
spicyapi_upload_fileenvia a imagem e obtém o endereçospicy://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.spicyapi_models_listespicyapi_model_getencontram um modelo e as configurações dele, espicyapi_task_quotecalcula o preço das opções. Tudo gratuito.spicyapi_task_createpara 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ê.spicyapi_task_waitespera 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é oexpiresAtdele, 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-1ecampaign-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
40202as 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/spicyA CLI inclui o endereço na própria cotação, então a conferência de preço continua batendo.
Próximos passos
Catálogo de modelos e schemas
Como funcionam o catálogo atual e as configurações de cada modelo
Mídia
Uploads em detalhe, inclusive uploads feitos a partir de um navegador
Webhooks
Receba um aviso quando uma tarefa terminar e confira cada chamada
Erros
Todos os códigos de erro e se uma nova tentativa pode ajudar
Cobrança
Reservas, cobranças finais, limites de gasto e o seu saldo
Retenção e destruição
Por quanto tempo arquivos e prompts são guardados e como apagá-los antes
Integração em produção
O que acrescentar antes que usuários reais dependam disso
Perguntas frequentes
Respostas curtas para as perguntas mais comuns
Migrar de OpenAI ou OpenRouter
Adapte seu código com as bibliotecas OpenAI à SpicyAPI: URL base, chave, ID do modelo, diferenças nos campos e ajustes para quem usa OpenRouter.
Guia: gerar e editar imagens
Como os endpoints de imagem se comportam como categoria — as duas formas de requisição, as três maneiras de escrever o tamanho da saída, o que uma imagem de referência acrescenta à conta, pesos de adaptação e como ler uma recusa.

