HeroShot

Documentação da API

Gere pôsteres a partir de fotos pelo seu próprio sistema. Você compra créditos, cria os temas no painel e consome a geração via API REST. Cada foto gerada com sucesso consome 1 crédito.

Base e autenticação

Todas as rotas ficam sob https://heroshot.me/api/v1 e exigem uma chave de API enviada no cabeçalho Authorization. Gere e gerencie suas chaves no painel, em API. A chave é mostrada uma única vez — guarde com segurança; ela identifica sua conta e o consumo de créditos.

Authorization: Bearer hs_live_suachave

Respostas são JSON. Sempre use HTTPS. Erros retornam { "error": "mensagem" } com o status HTTP correspondente.

Como funciona (assíncrono)

A geração leva cerca de 30 a 60 segundos. Por isso o fluxo é assíncrono:

  1. POST /photos responde na hora com { id, status: "processing" } (HTTP 202).
  2. O resultado fica pronto depois. Você descobre de duas formas: consultando GET /photos/{id} (polling) ou recebendo um webhook quando concluir.
  3. Com o resultado pronto, baixe a imagem pela `resultUrl`.

Gerar uma foto

POST/api/v1/photos

Envie a imagem de uma destas formas: arquivo via multipart/form-data (campo photo), ou JSON com imageUrl (nós baixamos) ou imageBase64. Sempre informe o themeId (veja Listar temas). Limite de 15 MB por imagem.

O campo eventId é opcional: informe o id de um evento seu para a foto entrar na galeria/telão desse evento. Sem eventId, a foto vai para o evento padrão de integrações da sua conta.

Exemplo — upload de arquivo

curl -X POST https://heroshot.me/api/v1/photos \
  -H "Authorization: Bearer hs_live_suachave" \
  -H "Idempotency-Key: pedido-123" \
  -F "photo=@foto.jpg" \
  -F "themeId=ID_DO_TEMA"

Exemplo — por URL (JSON)

curl -X POST https://heroshot.me/api/v1/photos \
  -H "Authorization: Bearer hs_live_suachave" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-123" \
  -d '{ "imageUrl": "https://...", "themeId": "ID_DO_TEMA" }'

Resposta (202)

{
  "id": "9f8e...",
  "status": "processing",
  "galleryUrl": "https://heroshot.me/p/k7Qm2pX9aB"
}

Consultar o resultado

GET/api/v1/photos/{id}

Devolve o status atual. Quando done, traz a resultUrl (arquivo da imagem) e a galleryUrl (página pública de visualização e download — a mesma do QR code, para enviar ao cliente final). Para receber a imagem embutida em base64, adicione ?format=base64.

curl https://heroshot.me/api/v1/photos/9f8e... \
  -H "Authorization: Bearer hs_live_suachave"

Pronta (done)

{
  "id": "9f8e...",
  "status": "done",
  "themeId": "...",
  "resultUrl": "https://heroshot.me/api/files/photos/9f8e.../result.jpg",
  "galleryUrl": "https://heroshot.me/p/k7Qm2pX9aB",
  "error": null,
  "createdAt": "2026-06-11T23:44:47.973Z"
}

Enquanto processa, status é processing e resultUrl/galleryUrl são null. Em falha, status é error e error traz o motivo.

Listar temas

GET/api/v1/themes

Temas disponíveis para sua conta (os padrão da plataforma + os que você criou), apenas ativos. Use o id no POST /photos.

curl https://heroshot.me/api/v1/themes \
  -H "Authorization: Bearer hs_live_suachave"

{
  "themes": [
    { "id": "...", "name": "Faroeste", "kind": "poster",
      "orientation": "portrait", "custom": false }
  ]
}

Consultar saldo

GET/api/v1/credits

Saldo da conta: balance é o total; bonus é a parte de cortesia e paid a parte comprada. Os créditos de bônus são consumidos primeiro a cada geração. Sem saldo, o POST /photos responde 402.

curl https://heroshot.me/api/v1/credits \
  -H "Authorization: Bearer hs_live_suachave"

{ "balance": 120, "bonus": 10, "paid": 110 }

Idempotência

Em qualquer POST /photos, envie o cabeçalho Idempotency-Key com um valor único por pedido. Se a mesma chave chegar de novo (ex.: retry após timeout de rede), devolvemos a mesma foto sem gerar nem cobrar outra vez. Use um identificador do seu lado (id do pedido, UUID).

Webhook

Em vez de ficar consultando, configure uma URL de webhook no painel (em API). Quando uma foto fica pronta (ou falha), enviamos um POST para essa URL:

{
  "event": "photo.done",
  "id": "9f8e...",
  "status": "done",
  "resultUrl": "https://heroshot.me/api/files/photos/9f8e.../result.jpg",
  "galleryUrl": "https://heroshot.me/p/k7Qm2pX9aB"
}

Cada envio vem assinado no cabeçalho heroshot-signature (HMAC SHA-256 do corpo, usando seu segredo do webhook). Valide antes de confiar:

import crypto from 'node:crypto'

const assinatura = req.headers['heroshot-signature']
const esperado = crypto
  .createHmac('sha256', SEU_SEGREDO_DO_WEBHOOK)
  .update(corpoBrutoDaRequisicao) // o body cru, sem reserializar
  .digest('hex')

const valido =
  assinatura.length === esperado.length &&
  crypto.timingSafeEqual(Buffer.from(assinatura), Buffer.from(esperado))

Códigos de erro

401Chave de API ausente ou inválida
402Sem créditos — recarregue para continuar
404Foto ou evento não encontrado (ou não é da sua conta)
409Tema inexistente ou indisponível para a conta
413Imagem acima de 15 MB
422Parâmetros faltando ou inválidos

Boas práticas