Bubble Dev — Passo a passo
Você é o dev Bubble, vai conectar Blueprintt ao backend Blu × Omie. Aqui está o caminho mais curto: setup → trigger automático → botões de ops → writeback → testar local.
-
Base URL.
- Staging:
https://staging-blu-omie.devmagic.com.br - Local dev (com ngrok):
https://<your-tunnel>.ngrok-free.app
- Staging:
-
Headers obrigatórios em toda chamada Bubble → Backend.
Authorization: Bearer <BUBBLE_API_KEY>Idempotency-Key: <uuid>X-Request-Timestamp: <epoch ms>Content-Type: application/jsonBUBBLE_API_KEYvive em Bubble Plugin Settings → API Connector (NÃO commitar, NÃO colar em workflow visível).Idempotency-Key— gerar via expression Bubble (Current date/time:formatted as+ suffix) ou plugin uuid. Garante que retry não duplica OS na Omie.X-Request-Timestamp—Current date/time:extract UNIX× 1000. Backend tolera ±5min de drift.
-
Instalar API Connector. Plugin oficial “API Connector”. Add a new API com nome
Blueprintt × Omie Backend. Auth:Private key in header, Key nameAuthorization, Key valueBearer [API_KEY]([API_KEY]vira parâmetro do plugin). -
Importar endpoints. Bubble não importa OpenAPI nativo — cada endpoint vira 1 API Call configurada manualmente. Abra
docs/openapi.yamlda staging como referência (1path × method= 1 API Call). Detalhe completo do mapping está emdocs/bubble-api-connector.md. -
Testar conectividade. Configure uma call
GET /healthz. Clique Initialize call — deve retornar 200. Se der 401, Bearer está errado. Se der CORS / timeout, base URL está errada.
Trigger automático — workflow “Pedido criado”
Section titled “Trigger automático — workflow “Pedido criado””O único webhook automático que o Bubble dispara. Chamado quando o type order é criado.
-
Workflow trigger. Database Trigger Event → When a new
orderis created. -
Action: API Call →
sync-omie. Use a API callPOST /v1/orders/{bubble_order_id}/sync-omie. Path parambubble_order_id=Current order's unique id. -
Body (JSON). Payload mínimo:
{"company": "aabc","trigger_source": "auto"}companysempre"aabc"na Versão Atual. LNG está fora de escopo — não enviar. -
Headers. Adicionar:
Idempotency-Key: <Current order's unique id>:syncKey fixa por pedido (sem timestamp). Se o workflow Bubble retentar, backend reconhece a key e retorna o resultado anterior sem reabrir OS na Omie.
-
Sucesso esperado. HTTP
202ou200. Backend já escreveustatus_pedidoestatus_faturamentovia Data API (ver próxima seção). Não precisa ler o response —Current orderjá reflete o novo estado em ~1s.
Botões de ops — backoffice
Section titled “Botões de ops — backoffice”Cada botão de ação backoffice chama um endpoint dedicado. Bubble não tem lógica fiscal — só dispara a call e mostra o resultado quando status_faturamento mudar.
Quando usar. NFS-e falhou (rate-limit Omie, REDUNDANT, erro Prefeitura). Botão “Tentar emitir NF novamente” na tela do pedido.
Endpoint. POST /v1/orders/{bubble_order_id}/retry
Body.
{ "reason": "manual retry by <Current User's email>"}Headers. Idempotency-Key: <order_id>:retry:<Current date/time:formatted as UNIX> — cada clique tem key única; sem o timestamp, backend bloqueia segundo clique.
Sucesso. 202 — backend re-enfileira job de emissão. status_faturamento volta a agendado ou faturando.
Falha. 409 se já está sendo processado. 4xx se estado inválido (ex.: NF já emitida).
Quando usar. NFS-e foi emitida e precisa ser cancelada na Prefeitura. Botão “Cancelar NF” requer motivo + justificativa antes do submit.
Endpoint. POST /v1/orders/{bubble_order_id}/cancel-nf
Body.
{ "motivo": "<código motivo Prefeitura>", "justificativa": "<texto livre obrigatório>", "actor": "<Current User's email>"}Headers. Idempotency-Key: <order_id>:cancel-nf (key fixa — cancelar 2x é o mesmo cancelamento).
Sucesso. 200 — status_faturamento evolui pra nf_cancelada.
Falha. 409 se NF nunca foi emitida. 502 se Prefeitura recusou cancelamento.
Quando usar. Contador emitiu a NFS-e direto na UI do Omie web. Bubble precisa registrar os IDs pra fechar o ciclo.
Endpoint. POST /v1/orders/{bubble_order_id}/mark-nf-manual
Body.
{ "omie_nfse_id": "<id Omie>", "numero_nfse": "<número Prefeitura>", "link_nfse": "<URL PDF>", "actor": "<Current User's email>"}Headers. Idempotency-Key: <order_id>:mark-manual
Sucesso. 200 — status_faturamento = faturamento_manual. Backend escreve omie_nfse_id, numero_nfse, link_nfse via Data API.
Falha. 409 se NF já registrada via fluxo automático.
Writeback — campos escritos pelo backend
Section titled “Writeback — campos escritos pelo backend”Backend faz PATCH no Bubble Data API atualizando estes campos. Você não escreve nestes — backend é dono. Bubble só lê pra exibir.
| Campo Bubble | Tipo | Valores possíveis | Quando atualiza |
|---|---|---|---|
status_pedido | text (Option Set ns_status_pedido) | aguardando_pagamento, confirmado, cancelado | Pagar.me webhook + ordem cancelada |
status_faturamento | text (Option Set ns_status_faturamento) | aguardando_pagamento, aguardando_confirmacao, bloqueado_dia25, agendado, faturando, nf_emitida, nf_cancelada, erro_faturamento, faturamento_manual | Cada transição do billing state machine |
omie_os_id | text | UUID Omie OS | Após CreateOS |
omie_nfse_id | text | UUID Omie NFS-e | Após EmitirNFSe |
numero_nfse | text | Número NFS-e Prefeitura | Após callback Omie |
link_nfse | text (URL) | PDF NFS-e | Após callback Omie |
Option Sets Bubble — criar antes
Section titled “Option Sets Bubble — criar antes”Crie estes dois Option Sets exatamente com estes valores antes de configurar os campos:
ns_status_pedido (3 valores):
aguardando_pagamentoconfirmadocancelado
ns_status_faturamento (9 valores):
aguardando_pagamentoaguardando_confirmacaobloqueado_dia25agendadofaturandonf_emitidanf_canceladaerro_faturamentofaturamento_manual
Strings devem casar exatamente (lowercase, underscore) — backend escreve essa forma literal.
Pagar.me webhook — backend recebe direto
Section titled “Pagar.me webhook — backend recebe direto”Pagar.me
charge.*events NÃO vão pro Bubble. Vão pro backend (POST /webhooks/pagarme) com validação HMAC. Backend escrevestatus_pedidono Bubble após confirmar pagamento.
Do ponto de vista Bubble, o webhook foi processado quando você observa:
status_pedidomuda praconfirmado(backend escreveu via PATCH Data API).status_faturamentoevolui (aguardando_pagamento→agendadooubloqueado_dia25).paymentrecord atualizado compayment_method+paid_at(backend escreve).
Testar local — apontar Bubble staging pro seu backend
Section titled “Testar local — apontar Bubble staging pro seu backend”-
Rodar backend local.
cd backend && make dev(uvicorn em:8000). -
Expor via ngrok.
ngrok http 8000. Copy URLhttps://abc123.ngrok-free.app. -
Trocar base URL no API Connector. Substituir
https://staging-blu-omie.devmagic.com.brpela sua URL ngrok. Re-initialize as calls que mudaram path. -
Disparar pedido de teste no Bubble staging. Use um backoffice pessoal pra não poluir tickets reais.
-
Observar logs. Terminal do
uvicornmostra request entrando + structlog estruturado por correlation id. DB local é sqlite tmp (auto-criado). -
Voltar pra staging. Após terminar, trocar base URL de volta. Não esqueça — clientes reais ficarão tentando hit no seu laptop.
Reference rápido
Section titled “Reference rápido”| Endpoint | Quando | Idempotency-Key sugerida |
|---|---|---|
POST /v1/orders/{id}/sync-omie | Trigger automático ao criar pedido | <order_id>:sync |
POST /v1/orders/{id}/retry | Botão “Tentar emitir NF” | <order_id>:retry:<timestamp> |
POST /v1/orders/{id}/cancel-nf | Botão “Cancelar NF” | <order_id>:cancel-nf |
POST /v1/orders/{id}/mark-nf-manual | Botão “Marcar manual” | <order_id>:mark-manual |
POST /v1/orders/{id}/approve-billing-hold | Aprovar hold backoffice | <order_id>:approve-hold |
POST /v1/orders/{id}/override-day25 | Override dia 25 | <order_id>:override-day25 |
POST /v1/orders/{id}/transfer-cc | Transferir carta de crédito | <order_id>:transfer-cc:<destination_id> |
POST /v1/orders/{id}/use-cc | Aplicar carta de crédito | <order_id>:use-cc:<cc_id> |
GET /v1/orders/{id}/status | Polling status (opcional) | n/a |
GET /healthz | Liveness | n/a |
Troubleshooting comum
Section titled “Troubleshooting comum”401Unauthorized — Bearer token errado ou expirado. ConfirmarAuthorizationheader no API Connector + key no plugin settings.409Conflict —Idempotency-Keyjá foi processada. Use timestamp ou UUID nova por clique em endpoints que aceitam re-execução (retry, transfer-cc, use-cc).425Too Early — Omie rate-limit ban (31min). Backend retry automático. Não tratar como erro. UI mostra spinner / “Sincronizando…” atéstatus_faturamentoevoluir.5xx— backend down ou conexão DB perdeu. Retry com backoff exponencial (1s, 2s, 4s, 8s); se persistir, alertar ops.- Timeout 30s —
sync-omiesíncrono normal leva ~3s; >10s indica problema. Cancela a call e mude pra polling emGET /v1/orders/{id}/status. - Webhook Pagar.me chega no Bubble — bug — está roteado errado. Reportar (pendência BUBBLE-1); workflow no Bubble deve ser removido ou desabilitado.