spicyapiDocumentação
Referência
Conteúdo principal

Contrato Spicy Schema

Envelope compartilhado de solicitações, campos canônicos, schema de formulário, ciclo assíncrono, erros, armazenamento e regras de compatibilidade.

Spicy Schema é o contrato público de todos os novos modelos de mídia. Adicionar um modelo muda seu model, seu inputSchema e o preço para o cliente; autenticação, tarefas, resultados, erros e downloads permanecem iguais.

Esta é uma página de referência. A maioria das integrações só precisa de Catálogo de modelos e schemas. Continue se você está criando um formulário, um validador ou um gerador de código a partir de inputSchema e quer saber exatamente com o que pode contar.

Somente o catálogo em tempo real comprova que um modelo pode ser chamado

Esta página define o formato do contrato; ela não afirma que algum modelo esteja disponível. Antes de operações pagas, consulte a resposta autenticada de GET /api/v1/models e exija tanto enabled: true quanto available: true. Entradas planejadas ou desativadas não podem ser chamadas.

Limites do contrato público

Um ID público de modelo identifica uma capacidade estável no formato <publisher>/<model>/<task>. O criador é o autor ou a organização de pesquisa responsável pelo modelo. A edição de imagem sempre usa o sufixo edit, e identificadores publicados anteriormente continuam sendo aceitos. Sempre copie um ID real do catálogo em tempo real; MODEL_ID_FROM_CATALOG nesta página é um marcador.

Respostas públicas, webhooks, erros e downloads usam somente identificadores, códigos de erro e URLs da própria SpicyAPI. Nunca incluem detalhes internos de processamento, respostas brutas, erros brutos ou dados comerciais internos. Os resultados são copiados para o armazenamento da própria SpicyAPI antes de serem retornados.

Envelope unificado de criação

{
  "model": "MODEL_ID_FROM_CATALOG",
  "input": {
    "prompt": "slow camera push-in",
    "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "duration_seconds": 8,
    "resolution": "1080p",
    "generate_audio": true
  },
  "callBackUrl": "https://your-app.example.com/hooks/spicy"
}
CampoRegra
modelValor exato e disponível para chamadas no catálogo autenticado em tempo real
inputPrecisa atender ao inputSchema atual do mesmo item; campos desconhecidos são recusados
callBackUrlEndereço público HTTPS opcional que recebe a tarefa concluída; mantenha exatamente estas maiúsculas e minúsculas. Veja Webhooks

O input acima é ilustrativo: somente o inputSchema do próprio modelo define quais desses campos ele aceita.

Campos canônicos

O mesmo conceito usa um único nome em snake_case em todos os novos endpoints. Esta tabela reúne campos comuns, não todos eles; a lista completa sempre está no inputSchema do modelo.

ConceitoCampoTipo
Prompt positivopromptString
Prompt negativonegative_promptString
Imagem principal / finalimage_url / last_image_urlReferência de imagem; veja abaixo
Várias imagens de entradaimage_urlsLista de referências de imagem
Máscara de ediçãomask_urlReferência de imagem
Vídeo / áudio principalvideo_url / audio_urlURL HTTPS pública ou URI spicy:// confirmado
Mídia de referênciareference_image_urls / reference_video_urls / reference_audio_urlsLista de referências
Duração da saídaduration_secondsNúmero ou inteiro
Resolução / proporçãoresolution / aspect_ratioEnumeração documentada
Tamanho exato da saídasize (uma opção predefinida) ou width / heightEnumeração documentada / inteiro
Taxa de quadrosfpsInteiro
Áudio nativogenerate_audioBooleano
Semente aleatóriaseedInteiro
Pesos de adaptadoresloras ou high_noise_loras / low_noise_loras quando um endpoint expõe suas etapas separadamenteLista de objetos
Quantidade de saídasnum_outputsInteiro positivo
Codificaçãooutput_formatEnumeração documentada
Conversa de chatmessagesLista
Comprimento da saída / amostragemmax_tokens / temperatureInteiro / número

Uma referência de imagem é uma URL HTTPS pública, um URI spicy:// confirmado após upload ou um pequeno URI data:image/…;base64,…. Vídeo e áudio não podem ser enviados diretamente no corpo como dados inline. Veja Mídia.

Uma entrada de pesos de adaptadores identifica um conjunto de pesos e a intensidade de aplicação. O nome do campo é fixo, mas o formato da entrada não: o que um endpoint aceita para um arquivo de pesos, uma URL ou uma chave de uma biblioteca integrada, é restringido pelo subschema items do próprio endpoint. Consulte-o em vez de presumir um formato. O mesmo vale para a quantidade máxima de entradas e para os subcampos obrigatórios.

Um campo específico de modelo só existe quando representa uma capacidade real não coberta por um campo canônico e recebe um nome baseado nessa capacidade. Um endpoint antigo pode manter nomes anteriores em seu inputSchema em tempo real; os novos não os copiam.

inputSchema e anotações de interface

Todo modelo usa JSON Schema 2020-12 em inputSchema. O mesmo schema orienta a validação no servidor, os formulários do Playground, os exemplos e os orçamentos. O SDK oficial de TypeScript oferece tipos estáticos para os envelopes comuns de solicitação e resposta; o input de cada modelo continua sendo Record<string, unknown> e precisa ser validado com o schema em tempo real, em vez de presumir a existência de campos gerados por modelo.

Este site não mantém tabelas estáticas de parâmetros por modelo. Os parâmetros têm uma única fonte: o inputSchema retornado por GET /api/v1/models?includeSchema=1, também usado pelo Playground. Uma cópia fixa fica desatualizada conforme os modelos mudam, sem que nada identifique essa divergência. Para criar sua própria tabela, veja Catálogo de modelos e schemas.

Todo schema recebido:

  • tem raiz object e recusa campos desconhecidos (additionalProperties: false);
  • declara required, tipos, enumerações, intervalos, comprimentos, limites de listas, formatos de URI, valores padrão e condições verificadas;
  • fornece uma description não vazia em inglês para cada propriedade;
  • omite campos e valores padrão não verificados, em vez de adivinhá-los;
  • expressa condições por anyOf / allOf na raiz, explicados abaixo, nunca apenas pela visibilidade na interface;
  • não contém opções que só alteram o processamento interno nem opções de filtro de conteúdo.

Anotações de apresentação: x-ui

Os metadados de apresentação não são um segundo schema de validação. Todos ficam no objeto x-ui da própria propriedade, com chaves em snake_case escolhidas de um conjunto fechado:

ChaveSignificado
widgetControle a renderizar; valores abaixo
orderA ordem dos campos, em ordem decrescente, única em cada endpoint
label / placeholderSubstituição do rótulo padrão; texto de exemplo da entrada
rowsQuantidade de linhas da área de texto
step / unitPasso numérico e sufixo da unidade (s, px)
accept / max_size_mbFiltro MIME e tamanho máximo por arquivo nos controles de upload
advancedDeve ficar em uma seção avançada recolhida
primaryEntrada principal; fixada no topo e nunca recolhida
affects_priceAlterar o valor exige um novo orçamento
visible_whenExpressão de visibilidade condicional
enum_labelsCorrespondência de valor de enumeração para rótulo de exibição

x-ui.widget aceita um de treze valores: textarea, text, upload, multi-upload, select, radio, slider, number, switch, json, object-list, chat-messages, hidden. O controle sempre corresponde ao formato dos dados, de modo que um renderizador pode usá-lo diretamente para decidir o componente: select e radio sempre têm um enum; slider sempre tem minimum e maximum, nunca apenas exclusiveMinimum / exclusiveMaximum; switch é sempre um boolean; multi-upload é uma lista com items.type: string; object-list é uma lista com items.type: object e items.properties, e cada subcampo tem seu type e sua description; chat-messages é uma lista; hidden indica que o campo ainda é enviado, mas não tem controle visível.

Em qualquer campo de lista, o minItems / maxItems da própria lista e seu subschema items contêm restrições que a lista required da raiz não menciona. O servidor as aplica da mesma forma que as demais regras do schema. Um object-list tem em items um schema de objeto completo: tem seu próprio required, seu próprio additionalProperties: false e tipo, intervalo e default para cada subcampo. Os valores padrão também são aplicados dentro dessas entradas: um subcampo omitido recebe seu default antes da validação, de modo que um subcampo obrigatório com valor padrão é, na prática, opcional. Um subcampo sem valor padrão é recusado quando ausente, assim como um subcampo desconhecido ou um valor fora do intervalo permitido.

Um 400 causado por um valor dentro de uma lista aponta para a entrada exata, com campo, índice baseado em zero e subcampo, e não para a solicitação inteira. Passe essa indicação à pessoa responsável pela correção: com várias entradas em processamento, saber qual está fora do intervalo faz a diferença entre corrigir uma linha e procurar o erro por eliminação.

Os clientes devem ignorar chaves de apresentação desconhecidas: adicionar uma chave de x-ui é uma mudança compatível com versões anteriores.

{
  "type": "object",
  "required": ["prompt", "duration_seconds"],
  "additionalProperties": false,
  "properties": {
    "prompt": {
      "type": "string",
      "minLength": 1,
      "description": "Describes the scene and its motion.",
      "x-ui": { "widget": "textarea", "order": 100, "primary": true, "rows": 4 }
    },
    "duration_seconds": {
      "type": "integer",
      "enum": [5, 8, 10],
      "description": "Output duration in seconds.",
      "x-ui": { "widget": "radio", "order": 90, "unit": "s", "affects_price": true }
    }
  },
  "x-pricing": { "variantFields": ["duration_seconds"], "billingMode": "variant_matrix" }
}

Toda description é um texto em inglês e pode ser exibida sem alterações como ajuda do campo.

x-ui.affects_price: true orienta a interface a atualizar o orçamento após uma mudança no campo. Não é uma fórmula de preço e nunca substitui o pricing ou o quantityField do catálogo. O x-pricing na raiz é a representação dessa mesma informação no servidor: variantFields lista os campos que selecionam uma faixa de preço e sempre é um subconjunto dos campos com affects_price: true; billingMode indica como o endpoint é cobrado. Ambos são orientações; o valor oficial é o retornado pelo catálogo, pelo orçamento e pela tarefa. A representação das faixas em pricing está em Como interpretar preços.

Campos condicionais

As condições têm exatamente dois formatos, ambos na raiz:

{
  "anyOf": [{ "required": ["image_url"] }, { "required": ["image_urls"] }],
  "allOf": [
    { "if": { "required": ["last_image_url"] }, "then": { "required": ["image_url"] } },
    { "if": { "properties": { "resolution": { "const": "4k" } } }, "then": { "required": ["seed"] } }
  ]
}

Cada condição de anyOf contém somente required e significa “forneça pelo menos um destes”. Cada condição de allOf é um if → then: if é ativado por required ou properties.<field>.const; then declara somente required e significa “se fornecer A, você precisa fornecer B”.

oneOf, not, dependentSchemas e dependentRequired nunca aparecem no inputSchema de um modelo: expressam a restrição, mas não podem ser representados como formulário. O usuário só descobriria a regra ao receber um erro 400 inexplicável após enviar. Implementar os dois formatos acima cobre todos os endpoints condicionais.

Ciclo de vida assíncrono

queued -> running -> succeeded
                  -> failed
                  -> expired

createTask retorna um ID de tarefa Spicy. Consulte recordInfo ou receba um webhook Spicy assinado. queued e running não são estados finais; os demais são. Registros históricos canceled continuam legíveis por compatibilidade, mas novas tarefas não oferecem ação de cancelamento. Tarefas assíncronas é a referência sobre os estados.

Um estado interno não final e desconhecido de um modelo é convertido em running até um estado final conhecido ou até o prazo absoluto da plataforma. Um envio não idempotente cuja confirmação é incerta não é repetido sem verificação, evitando geração e cobrança duplicadas.

Respostas e erros unificados

Toda API JSON nativa (/api/v1) usa o mesmo envelope; os endpoints de compatibilidade /v1 e /v1beta usam os formatos dos respectivos protocolos:

{
  "code": 200,
  "msg": "success",
  "data": {},
  "request_id": "req_01k3m8x9q2z4v7n5p6r8s0t1w2"
}

data não aparece em falhas síncronas. Baseie a lógica em code, nunca no msg, que pode mudar; use request_id ao pedir suporte. Uma falha após a criação da tarefa usa data.state: "failed" e um errorCode estável. errorMessage é legível por humanos: quando o serviço do modelo informa um motivo específico, a mensagem apresenta esse motivo em inglês, sem nomes, endereços ou dados de conta internos; caso contrário, é uma mensagem da plataforma no seu idioma de erros. Baseie a lógica em errorCode, nunca em errorMessage.

Resultados e downloads

Uma tarefa bem-sucedida lista seus arquivos em output.assets[]. Cada arquivo pronto já contém um link de download:

{
  "assets": [
    {
      "key": "tasks/2026/08/31/job_01k3m8x9q2z4v7n5p6r8s0t1w3/asset_01.mp4",
      "url": "https://example.r2.cloudflarestorage.com/results/asset_01.mp4?X-Amz-Signature=SIGNATURE_FROM_RESPONSE",
      "expiresAt": "2026-08-31T10:20:00Z",
      "mime": "video/mp4",
      "durationSeconds": 8,
      "bytes": 1234567
    }
  ]
}

Baixe url diretamente, sem sua chave de API. A URL normalmente dura 20 minutos; consulte a tarefa novamente para obter outra enquanto o resultado estiver retido, por no máximo 14 dias. Enquanto o arquivo ainda está sendo armazenado, o item tem pending: true e não tem url; se o armazenamento falhar definitivamente, tem unavailable: true. key identifica o arquivo para o endpoint opcional download-url; você não precisa dela para baixar. Todos os links apontam para o armazenamento da própria SpicyAPI.

Faturamento do cliente

pricing, startingPrice e quantityField do catálogo e estimatedCost / cost da tarefa descrevem apenas os preços para o cliente. Os valores são strings decimais em USD. Dados comerciais internos ficam fora do contrato público e nunca aparecem em catálogos, tarefas, webhooks ou logs exportados.

Compatibilidade e descontinuação

Mudanças que seu cliente deve tolerar sem falhar: um novo campo opcional, um novo campo de resposta que pode ser ignorado ou uma indicação de x-ui desconhecida.

Um novo campo obrigatório, a remoção de um valor de enumeração, uma mudança de significado ou tipo, um limite mais restrito ou a alteração de um ID público de modelo vêm acompanhados de uma nova versão do modelo ou de um prazo anunciado de descontinuação. IDs publicados permanecem imutáveis; migrações usam um alias de compatibilidade ou um redirecionamento explícito.

Mantenha o catálogo autenticado em cache conforme Cache do catálogo. Nunca mantenha uma cópia permanente do schema nem use uma página estática como alternativa quando o catálogo em tempo real não tiver nenhum item disponível para chamadas.

Nesta página