Documentação da API
Base URL: https://api-gigrunner.softrace.pt/api/v1
Referência completa dos endpoints + guia de integração para a app GigRunner / Cue Companion.
Guia de integração (app)
Destinado a quem implementa o cliente desktop/mobile. O site trata de registo/compra; a app trata de login, validar licença e consumir créditos AI.
1. Setup
Em desenvolvimento podes usar o Playground para validar as respostas antes de ligar a app.
2. Login (uma vez / quando expirar)
Ecrã de login na app → POST /login com email e password.
POST /api/v1/login
{ "email": "user@email.com", "password": "…" }
→ 200
{
"user": { "id", "uuid", "name", "email" },
"license": { "valid", "status", "plan", "starts_at", "expires_at" },
"credits": { "ai": 50 },
"token": "1|…"
}
Guardar em disco (seguro):
token, user.uuid, license, credits,
e last_validated_at = now.
Se license.valid === false: deixa entrar só ao ecrã “activa / compra licença”
(abre o site no browser). Não desbloqueies a app completa.
3. Arranque seguinte (já tem token)
- Ler token do disco. Se não houver → ecrã de login.
- Com rede:
GET /license(ouGET /mese quiseres user + credits também). - Actualizar cache local (
license,creditsse vierem,last_validated_at). - Se
valid === true→ app normal. Caso contrário → bloquear / pedir compra. - Se 401 → token inválido → limpar cache → login.
O utilizador não volta a fazer login em cada abertura se o token ainda for válido.
4. Usar AI (obrigatório)
Antes de cada pedido AI à tua infra / modelo:
POST /api/v1/credits/consume
Authorization: Bearer …
{ "type": "ai", "amount": 1, "reason": "cue_suggest" }
→ 200 { "ok": true, "balance": 49, "credits": { "ai": 49 } }
→ 402 { "message": "Créditos insuficientes.", "credits": { "ai": 0 } }
- 200 → actualiza saldo local → executa a AI.
- 402 → não chames a AI; UI “compra mais créditos” (link ao site).
- Não confies só no saldo em cache para autorizar o gasto — o servidor decide.
- Opcional: envia
referenceúnico por operação (ex. id do job) para auditar / evitar double-spend no futuro.
4b. Análise de áudio (Magic Chords)
A app não chama a Magic Chords directamente. Usa as URLs GigRunner. O backend escolhe o provider (hoje: Magic Chords). Requer licença válida; consome 1 crédito AI ao criar o job.
POST /api/v1/audio/jobs
{ "url": "https://…/song.mp3", "kind": "analyze" }
ou multipart: file + kind
→ 201 { "job": { "id", "status", "progress", … }, "credits" }
GET /api/v1/audio/jobs/{id} → poll até status=complete
GET /api/v1/audio/jobs/{id}/result → acordes, tempo, key, …
kind: analyze (acordes/tempo/key) ou transcribe (letras).
Os jobs demoram — faz poll a cada 2–5s.
5. Offline (proposta)
Ensaios podem não ter rede. Regra sugerida (acordar valor de N):
- Se há cache com
license.valid === trueenow - last_validated_at < N dias(ex.: 7) → permite usar a app. - Funções AI requerem rede (porque precisam de
/credits/consume). Sem rede → desactivar AI ou mensagem clara. - Quando voltar a rede → revalidar logo (
GET /license+ opcionalGET /credits). - Se online a API disser inválida/revogada → bloquear mesmo com cache antigo.
6. O que a app deve fazer por erro
7. Checklist para o cliente
- □ Base URL configurável (dev / produção)
- □ Login → guardar
token+uuid+license+credits - □ Arranque com token →
GET /license(não pedir password outra vez) - □ Bloquear app se
license.valid === false - □ Antes de AI genérica →
POST /credits/consume; tratar 402 - □ Análise áudio →
POST /audio/jobs+ poll +/result - □ Link “Registar / Comprar” → site (browser)
- □ Logout opcional →
POST /logout+ limpar disco - □ Regra offline documentada (N dias; AI só online)
Endpoints de teste (activate-test, purchase-test) são para o backend/playground —
a app de produção não precisa de os chamar; a compra será no site.
Fluxo típico (resumo)
- Utilizador cria conta no site.
- Compra licença (ex.: 10€) → fica com app activa + créditos iniciais (ex.: 50 AI).
- Na app: login → token + license + credits.
- Antes de cada uso AI:
POST /credits/consume. Se 402 → sem saldo, pedir top-up.
Autenticação
Endpoints protegidos precisam do header:
Authorization: Bearer <token>
Accept: application/json
O token vem em POST /login ou POST /register.
O utilizador final nunca gera tokens à mão — isso é só a app.
Endpoints
Resposta:
{ "ok": true, "app": "...", "env": "..." }
Body:
name, email, password, password_confirmationResposta 201:
{ user, license, credits, token }
Body:
email, passwordResposta:
{ user, license, credits, token }
Resposta:
{ user, license, credits }
Resposta:
{
"license": {
"valid": true,
"status": "active",
"plan": "trial",
"starts_at": "2026-09-27T00:00:00+01:00",
"expires_at": "2026-10-27T00:00:00+01:00"
}
}
valid: false, status: "inactive".
Resposta 201:
{ license }
Resposta:
{ license }
Modelo: licença vs créditos
Licença = pode usar a app (porta de entrada).
Créditos = saldo por tipo (agora só ai) para acções pagas.
Não precisas de “verificar créditos” em ciclo. A regra é:
- Ao abrir a app →
GET /license(e opcionalmente cache offline). - Antes de cada acção AI →
POST /credits/consume(atómico no servidor). - Se 402 → mostra “sem créditos” e link para comprar pack.
Há um ledger (credit_transactions) para auditar compras e consumos.
Resposta:
{ credits: { ai }, packs: [...] }
Body:
type (ai), amount? (default 1), reason?200:
{ ok, type, balance, credits }402: créditos insuficientes
Body:
{ "pack": "license_standard" }Packs:
license_standard (10€ → licença + 50 AI), ai_50, ai_200.
JSON:
{ "url": "https://…", "kind": "analyze"|"transcribe" }multipart:
file + kind201:
{ job, credits } · 402 sem créditos · 403 sem licença
queued / processing / complete / failed) + progresso.
409 se ainda não estiver
complete.
Resposta:
{ "ok": true }
Erros comuns
Objecto user
{
"id": 1,
"uuid": "63f50785-…",
"name": "Nome",
"email": "user@email.com"
}
O uuid é estável — a app pode guardá-lo localmente junto com o token e o estado da licença.