spicyapiDocumentação
SDKs
Conteúdo principal

SDK para Go

O SDK oficial da SpicyAPI para Go (github.com/spicyapi-ai/spicy-go) — instale, cote e faça a sua primeira geração, envie um arquivo local, percorra o seu histórico de tarefas e trate todos os códigos de erro.

O spicy-go é o SDK oficial para Go da SpicyAPI. Ele coloca a geração de imagem, vídeo e áudio atrás de um único *spicy.Client: anexa a sua chave de API, decodifica o envelope da resposta em structs tipadas, espera por uma tarefa com pausas crescentes e limitadas, envia arquivos locais numa única chamada e dá a toda falha um único tipo de erro, que você identifica com errors.As.

Ele exige Go 1.23 ou mais recente e usa apenas a biblioteca padrão. Isso é de propósito: este pacote entra no seu grafo de dependências, e cada módulo que ele arrastaria junto é mais uma coisa para você auditar.

Esta é a ferramenta certa?

Você quer…Use
Chamar a SpicyAPI a partir do seu próprio código GoEste SDK
Chamá-la a partir de Node.js ou TypeScriptO SDK para TypeScript
Chamá-la a partir de Python, PHP ou JavaO SDK para Python, PHP ou Java
Gerar conteúdo pelo terminal, sem escrever códigoA CLI
Deixar um assistente de IA chamar a SpicyAPI por vocêO servidor MCP e o Agent Skill
Usar um modelo de conversa ou de textoUm cliente Go consolidado para os formatos da OpenAI, da Anthropic ou do Gemini — veja Texto e streaming

Instalar

O Go resolve módulos direto do repositório deles, então não há etapa de registro nem nada a esperar. Este comando funciona hoje:

go get github.com/spicyapi-ai/spicy-go

Depois coloque a sua chave no ambiente, para que ela nunca apareça no seu código nem no arquivo de histórico do seu shell:

export SPICY_API_KEY="sk-spicy-..."

Seu primeiro resultado

Peça o preço, decida, crie a tarefa, espere, leia os arquivos. Cotar é grátis e não reserva nada.

client, err := spicy.New(spicy.Options{}) // lê SPICY_API_KEY do ambiente
if err != nil {
    return err
}

request := spicy.CreateTaskInput{
    Model: "MODEL_ID_FROM_CATALOG",
    Input: map[string]any{"prompt": "a lantern in fog"},
}

quote, err := client.Quote(ctx, request)
if err != nil {
    return err
}
log.Printf("this will cost at most %s", quote.MaxCharge)

// Guarde esta chave junto do seu próprio registro do trabalho antes de enviar:
// a razão de ela existir é continuar ali depois da falha que perdeu a resposta.
key, err := spicy.NewIdempotencyKey()
if err != nil {
    return err
}

request.Model = quote.Model
request.QuoteID = quote.QuoteID
request.ExpectedCost = quote.EstimatedCost

task, err := client.CreateTask(ctx, request, key, spicy.CreateTaskOptions{})
if err != nil {
    return err
}

final, err := client.WaitForTerminal(ctx, task.TaskID, spicy.WaitOptions{})
if err != nil {
    return err
}
for _, asset := range final.ReadyAssets() {
    log.Println(asset.URL)
}

MODEL_ID_FROM_CATALOG é um marcador. Pegue um ID de verdade no catálogo autenticado — client.ListModels, que é GET /api/v1/models — e nunca de memória nem de uma página antiga: modelos são acrescentados, pausados e aposentados. Monte o Input a partir do inputSchema daquele modelo, que ListModels devolve; cada modelo aceita campos diferentes.

Os valores são texto decimal em dólares americanos, nunca floats, porque números binários de ponto flutuante não guardam a maioria dos valores decimais com exatidão. Não existem créditos nem pontos em lugar nenhum desta API.

Um estado terminal não é necessariamente um estado de sucesso: failed, canceled e expired também encerram a espera. Confira o final.State.

Pule a primeira consulta

O WaitSeconds pede ao serviço que mantenha a conexão aberta até a tarefa terminar, o que num modelo rápido significa que o resultado chega junto com o envio.

seconds := 30
task, err := client.CreateTask(ctx, request, key, spicy.CreateTaskOptions{WaitSeconds: &seconds})
if err != nil {
    return err
}

// Task é nil sempre que a espera se esgota. Esse é o desfecho comum, não um
// erro — a geração continua rodando, então siga consultando a partir daqui.
final := task.Task
if final == nil {
    final, err = client.WaitForTerminal(ctx, task.TaskID, spicy.WaitOptions{})
    if err != nil {
        return err
    }
}
log.Println(final.State, final.Cost)

É uma otimização, nunca uma garantia. Um código que lê task.Task sem a verificação de nil funciona até a primeira geração mais lenta que o orçamento de espera — e aí entra em pânico em produção.

Começar por um arquivo local

Imagem para vídeo, troca de personagem e edição de imagem precisam do seu material do nosso lado antes de mais nada. O UploadFile faz o envio de três etapas — ticket, PUT para o armazenamento e commit — numa única chamada e devolve uma URI spicy://. É essa URI que vai no Input.

uploaded, err := client.UploadFile(ctx, "/path/to/reference.png", "")
// uploaded.URI -> "spicy://f/fil_..."

Uma URL HTTPS acessível publicamente pode ir direto na entrada e não precisa de envio nenhum. Imagens são aceitas até 10 MiB; áudio e vídeo, até 90 MiB. Veja Mídia.

Saldo, uso e histórico

Os três são limitados à chave de API que fez a chamada: chaves irmãs da mesma conta, e gerações iniciadas no console web, não entram — e essa ausência não é defeito.

balance, err := client.GetBalance(ctx)
if err != nil {
    return err
}
log.Printf("%s available, %s held by accepted tasks", balance.Available, balance.Held)

usage, err := client.GetUsage(ctx, spicy.UsageOptions{From: "2026-09-01", To: "2026-09-08"})
if err != nil {
    return err
}
log.Printf("%d calls, %s settled over [%s,%s)", usage.TotalCalls, usage.TotalSpend, usage.From, usage.To)

// EachTask repete cada filtro em todas as páginas e move apenas o cursor.
if err := client.EachTask(ctx, spicy.ListTasksOptions{From: "2026-09-01", To: "2026-09-08"},
    func(task spicy.TaskListItem) bool {
        log.Println(task.TaskID, task.State, task.Cost)
        return true // devolva false para parar antes do fim
    }); err != nil {
    return err
}

As datas são dias do calendário em UTC, num intervalo semiaberto [from, to) de no máximo 92 dias. Fixe From e To em qualquer varredura que possa atravessar a meia-noite UTC. Deixados vazios, o servidor recalcula a própria janela a cada página — o to é o dia seguinte em UTC —, então uma varredura que começa às 23h59 e continua às 00h01 faz duas perguntas diferentes e emenda as respostas. Nada avisa isso.

O GetUsage serve para conferência contábil, não para acompanhar o andamento. Ele fica atrás de um orçamento de requisições que vale para a conta inteira e é compartilhado por todas as chaves, e esse limitador falha fechando: ficar consultando pode trancar todas as outras chaves para fora dos próprios relatórios. Acompanhe uma tarefa com WaitForTerminal. A liquidação também pode chegar atrasada, então um número lido hoje ainda pode mudar amanhã.

Erros

As falhas voltam como *spicy.APIError, alcançável com errors.As:

var apiErr *spicy.APIError
if errors.As(err, &apiErr) {
    log.Println(apiErr.Status, apiErr.Code, apiErr.RequestID, apiErr.RetryAfter)
}

Decida pelo Code, nunca pela mensagem — mensagens são traduzidas, códigos não. O HTTP 503 é compartilhado por três códigos de negócio diferentes, então o status sozinho não basta para decidir o que fazer:

CodeO que significaO que fazer
40003os bytes enviados não correspondem ao ticket delesrecomece com um ticket novo
40004nenhuma implantação atende a essa combinação de parâmetrosmude o parâmetro citado na mensagem
40201saldo insuficienteadicione saldo
40901o preço mudou antes de a tarefa ser criadacote de novo, mantendo a mesma chave de idempotência
503uma dependência está indisponível por pouco tempoespere o que o RetryAfter pedir
50301nenhuma implantação nem preço utilizáveis neste momentoatualize o catálogo, sem insistir em rajada
50302uma geração síncrona falhou no processamento e foi estornadatente de novo com uma chave de idempotência nova

Todos os códigos estão listados em Erros. Cite o RequestID ao falar com o suporte.

Duas coisas que vão economizar o seu dinheiro

Use uma chave de idempotência por envio. Reaproveite-a em cada reenvio, inclusive depois de um tempo esgotado. Uma resposta perdida não prova que a tarefa não foi criada — uma chave nova transforma um resultado desconhecido numa segunda tarefa paga. É exatamente por isso que o CreateTask exige a chave. Veja Idempotência.

Uma tarefa que dá certo é cobrada, mesmo que o resultado decepcione. O Quote não reserva nada, então cote antes quando o preço importar.

O que este pacote não faz

  • Modelos de texto. Eles falam os formatos de rede da OpenAI, da Anthropic e do Gemini — os clientes Go consolidados para esses formatos já funcionam contra https://api.spicyapi.ai/v1 com a mesma chave. Veja Texto e streaming.
  • Aplicações que rodam no cliente. Nunca distribua esta chave dentro de um binário que você entrega a terceiros. Chame a partir do seu servidor.
  • Escolher o modelo ou preencher os campos dele. O pacote entrega o catálogo e o schema de cada modelo; quem decide o que enviar é você.
  • Cancelar uma tarefa. Depois de aceita, ela vai até o fim. Cancelar o context só interrompe a sua espera.

Código-fonte

O módulo tem licença MIT e é desenvolvido abertamente em github.com/spicyapi-ai/spicy-go. O README dele é o passeio completo mais curto pelo cliente; esta página acrescenta os conceitos em volta.

Próximos passos

Nesta página