jetblip API / directory

Catálogo das APIs internas dos serviços jetblip (jet-scan, jet-ask, labs). Atualmente Phase 1 — directório estático para referência. Phase 2 (planeada): self-service API keys + signup + trial credits.
← infra portal · mockups · icons library

🚧 Phase 2 · self-service API access (planeado)

Hoje as APIs estão protegidas por @login_required que age como no-op (jet-scan é público; jet-ask é semi-público). Para escalar para developers externos sem a minha intervenção pessoal (ver PHILOSOPHY.md), precisamos de:

🔍

📷 jet-scan

port 8093 https://my.jetblip.com/blip-scan/

Wallet de cartões de fidelização, scan de códigos de barras/QR, sistema de preferências por pessoa, registo de faturas. Backend Flask + SQLite. Reutilizável: produtos, lojas, pessoas, cartões.

POST/blip-scan/api/scanpublic*
Regista um scan. Auto-classifica em kind (barcode/qr/fatura/etc). Para barcodes, auto-seed prefs dont_know por pessoa. Auto-attach loja prior se mesmo código já tenha sido scaneado.
Body
{ "value": "1850380231797", "format": "EAN_13", "note"?: "..." }
Response
{ "ok": true, "id": 42, "value": "...", "format": "...", "kind": "barcode", "session_id": "...", "store_id": null }
GET/blip-scan/api/cardspublic*
Lista todos os cartões de fidelização (joined com store + person). Optional ?store_id=.
Response
{ "ok": true, "cards": [{ "id", "store_id", "store_name", "person_id", "person_name", "card_value", "card_format", "label", "created_at" }] }
GET/blip-scan/api/storespublic*
Lista todas as lojas. Cada uma: id, name, country.
POST/blip-scan/api/storespublic*
Cria nova loja. Case-insensitive dedup: se já existir com esse nome, devolve o ID existente.
Body
{ "name": "Auchan PT" }
Response
{ "ok": true, "store_id": 7, "name": "Auchan PT" }
GET/blip-scan/api/stores/<id>/cardspublic*
Cartões de uma loja específica.
POST/blip-scan/api/stores/<id>/cardspublic*
Cria um novo cartão de fidelização para uma loja. Cria pessoa nova se person_name não existir.
Body
{ "card_value": "...", "card_format"?: "EAN_13", "label"?: "...", "person_id"?: 1, "person_name"?: "Jeremy" }
POST/blip-scan/api/cards/<id>/deletepublic*
Soft delete de um cartão (marca deleted_at).
POST/blip-scan/api/scans/<id>/storepublic*
Atribui (ou remove) uma loja a um scan.
Body
{ "store_id": 7 } ou { "store_id": null }
GET/blip-scan/api/preferences/<code>public*
Preferências (sentiments por pessoa) para um dado código de barras.
POST/blip-scan/api/preferences/setpublic*
Atualiza sentiment de uma pessoa para um código. Sentiments: dont_know · dislike · neutral · like · favorite · style_favorite · worth_heartburn.
Body
{ "code": "1850380231797", "person_name": "Jeremy", "sentiment": "favorite" }
GET/blip-scan/api/pricespublic*
Lista preços registados por loja/produto.
POST/blip-scan/api/pricespublic*
Regista um preço.
POST/blip-scan/api/products/manualpublic*
Adiciona um produto manual (sem código de barras).
GET/blip-scan/api/products/searchpublic*
Pesquisa de produtos. Query param ?q=.
GET/blip-scan/api/products/<code>/enrichpublic*
Enriquece um produto via lookup externo (Open Food Facts).
GET/blip-scan/api/session/<sid>public*
Detalhes de uma sessão de scan.
POST/blip-scan/api/session/endpublic*
Termina a sessão atual de scan.
GET/blip-scan/healthzpublic
Health check. Retorna 200 OK + JSON simples.

* public = endpoint público hoje (decorator @login_required é no-op). Phase 2 vai introduzir auth real via API keys.

❓ jet-ask

port 8082 https://my.jetblip.com/blip-ask/

Sistema de captura de pedidos/bugs/ideias. Queue priorizada, decisões, follow-ups. Backend Flask + SQLite. APIs em /api/jet-ask/*.

POST/api/jet-ask/logpublic*
Regista um novo pedido/bug/ideia. Aceita texto, prioridade, anexos, contexto da página de origem.
Body
{ "text": "...", "priority"?: -2..5, "source"?: "ask-quick|ask-full|bug", "page_url"?: "..." }
GET/api/jet-ask/pendingpublic*
Lista pedidos pendentes na queue.
GET/api/jet-ask/decisions/readypublic*
Decisões prontas a serem feitas.
POST/api/jet-ask/<id>/claimpublic*
Reclama um todo (lock até completar/release).
POST/api/jet-ask/<id>/releasepublic*
Liberta um todo previamente claimed.
POST/api/jet-ask/<id>/draft-responsepublic*
Gera draft de resposta para um todo (LLM-assisted).
POST/api/jet-ask/<id>/updatepublic*
Atualiza um todo (texto, prioridade, status).
GET/api/jet-ask/tips/randompublic
Tip aleatório (frontend ticker).
GET/jet-ask/healthzpublic
Health check.

Os endpoints /jet-ask/<id>/... (sem prefix /api) são form-based e retornam HTML. Os /api/jet-ask/* são JSON.

🔬 blip-research

port 5050 https://my.jetblip.com/blip-research/

Price tracker e histórico de pesquisas. Operador escreve pedidos via dashboard; Claude lê via /api/state no início de cada sessão de pesquisa. Backend Flask + SQLite. ⚠ Cloudflare Bot Fight Mode activo — acesso externo requer User-Agent de browser real; acesso interno via SSH: curl -s http://127.0.0.1:5050/blip-research/api/state.

GET/blip-research/api/statepublic (CF-protected)
Snapshot JSON completo do estado actual. Usado pelo dashboard (auto-refresh 30s) e por Claude no início de cada sessão de pesquisa. Inclui contagens, 20 observações recentes, 10 sessões, 30 notas, 10 descidas de preço, itens esgotados.
Response
{ "counts": { "items": N, "obs": N, "sessions": N, "sources": N, "notes": N }, "recent": [{ "br_id", "item_id", "item_name", "source", "url", "price_fmt", "currency", "availability", "observed_at", "session_slug" }], "sessions": [{ "slug", "title", "context", "item_count", "obs_count", "last_obs" }], "notes": [{ "id", "content", "session_slug", "created_at" }], "drops": [...], "oos": [...], "ts": "ISO8601" }
Fetch interno (SSH)
ssh rpi "curl -s http://127.0.0.1:5050/blip-research/api/state"
Fetch externo (com UA)
curl -s -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" https://my.jetblip.com/blip-research/api/state
POST/blip-research/api/observepublic (CF-protected)
Regista uma observação de preço/disponibilidade. Cria item se não existir (item_id ou item_name obrigatório). Cria/actualiza sessão se session_slug for fornecido. Preço aceita formato europeu (vírgula como decimal).
Body
{ "item_id"?: 1, "item_name"?: "Crucial DDR5 8GB", "item_category"?: "ram", "item_spec"?: "DDR5-5600 SODIMM", "source": "Amazon.fr", "condition"?: "new|business|private|service", "price"?: "161,59", "currency"?: "EUR", "url"?: "https://...", "availability"?: "in_stock|oos|unknown", "notes"?: "...", "session_slug"?: "thierry-laptop-fw", "session_title"?: "...", "session_context"?: "..." }
Response
{ "ok": true, "obs_id": 42, "item_id": 7, "br_id": "BR-260524-13" }
Nota
Requer User-Agent de browser (CF Bot Fight Mode). Usar SSH + curl interno para acesso programático.
POST/blip-research/api/notepublic (CF-protected)
Operador submete nota/pedido de pesquisa. Claude lê via /api/state ao início de cada sessão. Histórico permanente.
Body
{ "content": "pesquisa RAM DDR5 SO-DIMM 16GB para Thierry", "session_slug"?: "thierry-laptop-fw" }
Response
{ "id": 5, "created_at": "2026-05-24T09:50:00Z" } · HTTP 201
GET/blip-research/api/notespublic (CF-protected)
Lista de notas do operador. Suporta ?limit=30 e ?session_slug=thierry-laptop-fw para filtrar por sessão.
Response
{ "notes": [{ "id", "content", "session_slug", "created_at" }] }

🧪 labs

multi-port (gunicorn) https://my.jetblip.com/labs/

Host aggregator: roteia /blip-scan/* → jet-scan, /blip-ask/* → jet-ask. nginx config em labs/deploy/nginx-b-ab.conf. Variantes A/B/C/D/E/F/G/H/I/J/K/L via prefix /b/ /c/ /d/ ... /l/ com X-UI-Version header.

GET/admin/operator
Dashboard admin (apenas operador com cookie).
GET/labs/healthzpublic
Health check do labs aggregator.

Lista parcial — labs tem rotas adicionais para A/B testing dashboard, métricas, etc. Ver labs/app.py para enumeração completa.

🔑 Auth pattern

Como autenticar contra estas APIs hoje e amanhã.

GETHoje (Phase 1)
@login_required é no-op em jet-scan (público por design). jet-ask + labs usam cookie de sessão labs_op. Para preview, opera-se passar ?lnw-dev uma vez (set localStorage 30 dias).
GETPhase 2 (planeado)TBD
Header Authorization: Bearer JBI-XXXX identifica utilizador + plano. Middleware verifica key contra tabela api_keys, regista uso em usage_log, aplica rate limit conforme plano.
Exemplo (futuro)
curl -X POST https://my.jetblip.com/blip-scan/api/scan \ -H "Authorization: Bearer JBI-abc123def456" \ -H "Content-Type: application/json" \ -d '{"value": "1850380231797", "format": "EAN_13"}'