HiAPI
Blogue

Tutorial

Crie aplicações de IA multimodelo no hiapi com uma única API unificada

Oct 8, 2026
Crie aplicações de IA multimodelo no hiapi com uma única API unificada
Modelo
seedance-2.5

O que você vai construir

A maioria das equipes acaba recorrendo a três ou quatro provedores de IA diferentes para um único produto: um modelo de texto-para-imagem para miniaturas, um modelo de texto-para-vídeo para clipes curtos para redes sociais e, talvez, um modelo TTS para narração. Cada provedor tem seu próprio SDK, seu próprio esquema de autenticação, sua própria lógica de polling. O hiapi reúne tudo isso em um único padrão de endpoint: POST /v1/tasks para criar uma tarefa, GET /v1/tasks/:id para consultá-la, e isso vale para todos os modelos de geração da plataforma.

Este tutorial demonstra esse padrão de integração com três modelos reais e atualmente disponíveis — z-image (texto-para-imagem), qwen-image-2.0 (texto-para-imagem, com schema diferente) e seedance-2.5 (texto-para-vídeo) — para que você perceba claramente onde a API é idêntica e onde apenas o objeto input de cada modelo difere.

Pré-requisitos

  • Uma API key do hiapi obtida no console
  • curl ou qualquer cliente HTTP capaz de enviar JSON
  • Nenhum SDK necessário — todos os exemplos abaixo são chamadas HTTP puras

Cada requisição exige um cabeçalho:

Authorization: Bearer <your-api-key>

Se a key for inválida ou estiver ausente, um erro da classe 401 é retornado antes de qualquer modelo ser acionado:

{
  "error": {
    "code": "permission_denied",
    "message": "invalid api key",
    "request_id": "req_...",
    "type": "hiapi_error"
  }
}

Não existe modo sem key nem modo anônimo — toda chamada a /v1/tasks precisa carregar um bearer token válido. Para rotação e escopo de keys, consulte Autenticação.

Exemplo mínimo executável

1. Criar uma tarefa

A estrutura da chamada de criação é sempre a mesma: um id de model e um objeto input específico do modelo. Veja abaixo a criação de uma tarefa de imagem com z-image:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "z-image",
    "input": {
      "prompt": "a minimalist workspace, soft morning light, isometric illustration",
      "aspect_ratio": "16:9"
    }
  }'

A resposta volta imediatamente — a geração é assíncrona:

{
  "code": 200,
  "message": "ok",
  "data": {
    "taskId": "tk-hiapi-xxxxxxxxxxxx",
    "status": "queued"
  }
}

Agora o mesmo padrão com qwen-image-2.0. Mesmo endpoint, mesma estrutura externa — apenas o input muda (este modelo recebe uma string size em vez de aspect_ratio):

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-image-2.0",
    "input": {
      "prompt": "a minimalist workspace, soft morning light, isometric illustration",
      "size": "2048*2048"
    }
  }'

E agora uma tarefa de vídeo com seedance-2.5/text-to-video — novamente a mesma estrutura externa, agora com duration e um enum de aspect_ratio mais amplo:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.5/text-to-video",
    "input": {
      "prompt": "a paper airplane gliding through a sunlit office, slow motion",
      "duration": 5,
      "aspect_ratio": "16:9"
    }
  }'

Esse é o ponto central: a estrutura externa da tarefa nunca muda; só o input varia. Cada modelo no hiapi documenta seu próprio schema de input na página do modelo — consulte sempre o schema do modelo específico antes de construir uma nova integração, porque campos como aspect_ratio, size e duration não são intercambiáveis entre modelos.

2. Consultar o resultado

curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-xxxxxxxxxxxx \
  -H "Authorization: Bearer $HIAPI_API_KEY"

O status passa por queued → handling → archiving até chegar ao estado final success ou fail. Em caso de sucesso, data.output é um array — a maioria dos modelos de imagem/vídeo retorna um único item, mas uma tarefa pode retornar vários tipos de saída (por exemplo, um modelo de vídeo retornando simultaneamente video e thumbnail):

{
  "code": 200,
  "message": "ok",
  "data": {
    "taskId": "tk-hiapi-xxxxxxxxxxxx",
    "status": "success",
    "output": [
      { "type": "image", "url": "https://...", "expireAt": "2026-10-09T00:00:00Z" }
    ]
  }
}

expireAt é importante — por padrão, as URLs de saída são temporárias. Baixe o conteúdo assim que a tarefa for concluída (ou reenvie para seu próprio storage). Se precisar que a plataforma retenha os arquivos por mais tempo, defina storage: "persistent" na criação ou faça upgrade depois — consulte Armazenamento.

Em caso de falha, você recebe um objeto error em vez de output:

{
  "code": 200,
  "message": "ok",
  "data": {
    "taskId": "tk-hiapi-xxxxxxxxxxxx",
    "status": "fail",
    "error": { "code": "...", "message": "..." }
  }
}

O loop de polling mínimo em Python abaixo funciona igualmente para todos os modelos acima:

import time
import requests

def run_task(model: str, input_payload: dict, api_key: str) -> list[dict]:
    headers = {"Authorization": f"Bearer {api_key}"}
    create = requests.post(
        "https://api.hiapi.ai/v1/tasks",
        headers=headers,
        json={"model": model, "input": input_payload},
    ).json()
    task_id = create["data"]["taskId"]

    time.sleep(3)  # espera inicial antes do primeiro poll
    while True:
        poll = requests.get(
            f"https://api.hiapi.ai/v1/tasks/{task_id}", headers=headers
        ).json()
        status = poll["data"]["status"]
        if status == "success":
            return poll["data"]["output"]
        if status == "fail":
            raise RuntimeError(poll["data"]["error"])
        time.sleep(4)  # 3-5s entre polls; use 5-10s para modelos de vídeo

Padrões para produção

Use callbacks em vez de polling em produção

O polling funciona bem para scripts ou ferramentas de CLI, mas em qualquer escala real de tráfego o callback é preferível: passe um objeto callback ao criar a tarefa e o hiapi fará um POST do resultado final para seu endpoint, em vez de você precisar repetir GET /v1/tasks/:id em um loop.

{
  "model": "z-image",
  "input": { "prompt": "...", "aspect_ratio": "1:1" },
  "callback": { "url": "https://yourapp.com/webhooks/hiapi", "when": "final" }
}

when: "final" significa que você receberá apenas um POST, disparado no estado final (success ou fail) — sem o ruído dos estados intermediários handling/archiving. Se você configurou um callback mas não recebeu nada, verifique se seu endpoint é publicamente acessível e retorna 2xx rapidamente; para conhecer a causa mais comum de callbacks perdidos silenciosamente, consulte este artigo relacionado.

Retentativas idempotentes

Instabilidades de rede são inevitáveis. Se você repetir uma chamada POST /v1/tasks após um timeout sem proteção, pode acabar criando (e pagando por) tarefas duplicadas. Envie um cabeçalho Idempotency-Key (qualquer string de até 255 bytes, normalmente um UUID gerado por requisição lógica); retentativas com a mesma key retornam a tarefa original em vez de criar uma nova:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Idempotency-Key: 8f14e45f-ceea-467e-bd5f-...-9a2c" \
  -H "Content-Type: application/json" \
  -d '{"model": "z-image", "input": {"prompt": "...", "aspect_ratio": "1:1"}}'

Trate erros de validação por modelo

Como cada modelo tem seu próprio schema de input, o modo de falha mais comum é um 400 em um campo — um campo válido para um modelo e inválido para outro, por exemplo, enviar aspect_ratio para um modelo que espera size:

{
  "code": 400,
  "data": null,
  "error_code": "INVALID_REQUEST",
  "message": "invalid input: aspect_ratio: value must be one of '1:1', '4:3', '3:4', '16:9', '9:16'"
}

Se você estiver construindo um roteador multimodelo (permitindo que o usuário ou sua própria lógica escolha o modelo em tempo de execução), mantenha um pequeno registro de construtores de input por modelo, em vez de uma estrutura de payload compartilhada:

MODEL_INPUT_BUILDERS = {
    "z-image": lambda prompt, **kw: {
        "prompt": prompt, "aspect_ratio": kw.get("aspect_ratio", "1:1")
    },
    "qwen-image-2.0": lambda prompt, **kw: {
        "prompt": prompt, "size": kw.get("size", "2048*2048")
    },
    "seedance-2.5/text-to-video": lambda prompt, **kw: {
        "prompt": prompt,
        "duration": kw.get("duration", 5),
        "aspect_ratio": kw.get("aspect_ratio", "16:9"),
    },
}

def build_task_payload(model: str, prompt: str, **kw) -> dict:
    return {"model": model, "input": MODEL_INPUT_BUILDERS[model](prompt, **kw)}

Assim, as particularidades de cada modelo ficam concentradas em um único lugar, em vez de espalhadas por cada ponto de chamada. Um taskId inexistente ou de outra conta retorna um 404 comum:

{ "code": 404, "message": "task not found", "data": null }

Já um 503 temporário deve ser reprocessado com backoff exponencial, em vez de ser exposto diretamente ao usuário — limites de taxa e de capacidade estão documentados em Limites de taxa.

Leitura relacionada

Perguntas frequentes

Cada modelo exige um SDK ou uma API key diferente? Não. Uma API key e um padrão de endpoint (/v1/tasks) servem para todos os modelos da plataforma. Apenas o objeto input do corpo da requisição muda.

Por que a resposta logo após criar a tarefa ainda não tem output? A geração é assíncrona. A chamada de criação retorna apenas taskId e status: "queued" — você precisa consultar GET /v1/tasks/:id (ou usar callback) até que o status atinja success ou fail.

Posso chamar a API sem autenticação para um teste rápido? Não — toda chamada a /v1/tasks exige uma key válida em Authorization: Bearer. Não há modo sem key nem modo de demonstração para chamadas de produção; gere uma key primeiro no console.

O que acontece se eu consultar depois que a URL de saída expirar? O registro da tarefa em si permanece, mas o output[].url de tarefas não persistentes deixa de ser resolvível após o expireAt. Baixe os arquivos imediatamente após o sucesso ou, se precisar de retenção de longo prazo, defina storage: "persistent" na criação.

Como descubro quais campos um modelo aceita? Consulte a página do modelo em Modelos — cada uma documenta o schema exato de input. Não presuma que aspect_ratio, size ou duration são intercambiáveis entre modelos; como mostrado acima, z-image e qwen-image-2.0 já divergem na forma de expressar o formato da imagem.

Artigos relacionados

Ver todos os artigos →

Comece a criar com artefactos de IA persistentes

Obtenha a sua chave de API e chame modelos de imagem, vídeo e áudio através de uma única API baseada em tasks.

Ler a documentação da API