{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"7e207411-7624-4909-8d24-35ec0605eb45","name":"Hubii API","description":"# Integração para parceiros\n\nEsta collection documenta a integração de parceiros com a API pública da Hubii. O fluxo foi desenhado para ERPs, PDVs e WMS que precisam aceitar pedidos, importar dados para operação, faturar, acompanhar eventos logísticos e tratar cancelamentos.\n\nA integração usa **dois pollings independentes**, executados em paralelo. Eles não são alternativas entre si: cada um cobre uma etapa diferente do ciclo do pedido.\n\n---\n\n## Visão rápida dos pollings\n\n### Polling 1 — Aceite de pedidos\n\nUsado para decidir se o hub aceita ou recusa uma **oferta de pedido**.\n\n| Ponto | Regra |\n| --- | --- |\n| Quando usar | Sempre que o hub precisa responder pedidos novos |\n| Rotas | `GET /hubs/{hub_uuid}/orders/to-answer` → `GET /hubs/{hub_uuid}/orders/{order_uuid}` → `POST .../answer` |\n| O que retorna | Ofertas pendentes, ainda não aceitas |\n| Decisão | Para cada oferta, consulte o pedido completo antes de aceitar ou recusar |\n| Prazo | Cada oferta expira em `available_until_at`; depois disso, some da fila |\n| Aceite via painel | Também é válido e dispara o Polling 2 |\n| Recusa / expiração | Remove a oferta de `to-answer` e não gera notificação para aquele hub |\n\n> A listagem de `to-answer` deve ser tratada como fila de ofertas. A decisão normalmente depende do pedido completo, principalmente dos itens, quantidades, preços e disponibilidade do hub. \n  \n\n### Polling 2 — Notificações de pedidos aceitos\n\nUsado para acompanhar pedidos **após o aceite**: importação no ERP, entrega, NF-e, etiqueta e cancelamentos.\n\n| Ponto | Regra |\n| --- | --- |\n| Quando usar | Depois do aceite via API ou painel, em paralelo ao Polling 1 |\n| Rotas | `GET /v2/notifications` → processar → `POST /notifications/ack` |\n| O que retorna | Eventos de pedidos aceitos, como `ORDER_CREATED`, entrega e etiqueta |\n| `ORDER_CREATED` | Só chega após o aceite; é o gatilho para importar o pedido no ERP |\n| ACK | Obrigatório após processar; eventos reaparecem até ACK e expiram em 2 dias |\n\n> **Resumo:** Polling 1 decide se o hub aceita a oferta. Polling 2 opera o pedido depois que ele foi aceito. Execute os dois a cada **30–60 segundos**. \n  \n\n---\n\n## Implementação mínima\n\nPara uma integração funcional, implemente este caminho primeiro:\n\n1. Configure `base_url` e envie o header `apikey` em todas as requisições.\n    \n2. Chame `GET /hubs` e salve o `uuid` de cada hub.\n    \n3. A cada 30–60 segundos, execute o **Polling 1**: `GET /hubs/{hub_uuid}/orders/to-answer`.\n    \n4. Para cada oferta retornada, consulte o pedido completo em `GET /hubs/{hub_uuid}/orders/{order_uuid}`.\n    \n5. Com base no pedido completo, principalmente nos itens, estoque e regras do hub, aceite ou recuse com `POST .../answer` antes de `available_until_at`.\n    \n6. Em paralelo, execute o **Polling 2**: `GET /v2/notifications`.\n    \n7. Ao receber `ORDER_CREATED`, busque ou reconcilie os detalhes do pedido e importe no ERP.\n    \n8. Após processar e persistir a notificação, envie `POST /notifications/ack` usando `notification_uuid`.\n    \n9. Quando aplicável, envie a NF-e com `POST .../invoice`.\n    \n10. Ao receber `SHIPPING_LABEL_AVAILABLE`, baixe a etiqueta com `GET .../label`.\n    \n\nNão use busy-loop. Em `429`, interrompa o ciclo atual, aplique backoff e tente novamente no próximo intervalo.\n\n---\n\n## Fluxo operacional\n\n``` text\nGET /hubs\n  ↓\n[Polling 1] GET .../to-answer\n  ↓ para cada order_uuid\nGET /hubs/{hub_uuid}/orders/{order_uuid}\n  ↓ decidir com base no pedido completo\nPOST .../answer\n  ↓ após aceite via API ou painel\n[Polling 2] GET /v2/notifications\n  ↓ ORDER_CREATED\nGET /hubs/{hub_uuid}/orders/{order_uuid}\n  ↓ após persistir no ERP\nPOST /notifications/ack\n  ↓ quando aplicável\nPOST .../invoice\n  ↓ SHIPPING_LABEL_AVAILABLE\nGET .../label\n\n ```\n\n`GET .../to-invoice` está **descontinuado** e existe apenas por compatibilidade. Para novas integrações, use `ORDER_CREATED` no Polling 2.\n\n---\n\n## Decisão de aceite ou recusa\n\nA Hubii recomenda este padrão para cada oferta retornada em `to-answer`:\n\n1. Ler `order_uuid` e `available_until_at` na listagem.\n    \n2. Buscar o pedido completo em `GET /hubs/{hub_uuid}/orders/{order_uuid}`.\n    \n3. Avaliar itens, quantidades, preços, disponibilidade, regras fiscais e operação do hub.\n    \n4. Responder com `POST .../answer` antes do prazo.\n    \n\nEssa etapa evita decisões baseadas apenas no resumo da fila e reduz recusa incorreta, aceite sem estoque ou divergência operacional.\n\n---\n\n## Variáveis da collection\n\n| Variável | Uso |\n| --- | --- |\n| `base_url` | `https://api.staging.hubii.co` em homologação ou `https://api.hubii.co` em produção |\n| `apikey` | API Key Hubii enviada no header `apikey` |\n| `hub_uuid` | UUID do hub retornado em `GET /hubs` |\n| `hub_uuid_2` | Opcional; segundo hub para exemplos de filtro com múltiplos hubs |\n| `order_uuid` | UUID do pedido retornado em `to-answer` ou em uma notificação |\n| `notification_uuid` | UUID da notificação retornada em `GET /v2/notifications`; usar no ACK |\n\n---\n\n## Autenticação\n\nEnvie o header abaixo em todas as requisições:\n\n``` http\napikey: {sua_chave}\n\n ```\n\nAPI Key ausente, inválida ou sem permissão deve ser tratada como erro de configuração, não como falha temporária.\n\n---\n\n## Rate limits\n\n| Grupo | Limite | Rotas |\n| --- | --- | --- |\n| Listagem | 60/min por token | `/hubs`, `.../to-answer`, `.../to-invoice` legado |\n| Detalhe | 30/min por token | `.../orders/{order_uuid}` |\n| Ação | 10/min por token | `.../answer`, `.../invoice`, `/notifications/ack`, `.../cancel-accepted` |\n| Notificações | 5/min por token | `/v2/notifications` |\n\n> Em runtime, use os headers **`X-RateLimit-\\\\\\\\\\*`** como referência operacional. A tabela acima documenta o limite esperado/contratual. \n  \n\nEm `429`, não faça retry imediato em loop. Aguarde com backoff exponencial e retome o polling no próximo ciclo.\n\n---\n\n## Idempotência e retry seguro\n\n| Operação | Como tratar retry |\n| --- | --- |\n| `GET /hubs` | Seguro repetir |\n| `GET .../to-answer` | Seguro repetir; a lista reflete a fila atual |\n| `GET .../orders/{order_uuid}` | Seguro repetir; use antes de decidir aceite/recusa e para reconciliar pedido aceito |\n| `POST .../answer` | Não é retry cego; pode retornar `422` se o pedido já foi respondido |\n| `GET /v2/notifications` | Seguro repetir; eventos reaparecem até ACK |\n| `POST /notifications/ack` | Enviar só depois de persistir; se falhar, retentar o ACK, não o processamento |\n| `POST .../invoice` | Reenvio do mesmo XML é idempotente |\n| `POST .../cancel-accepted` | Ação sensível; evitar retry automático sem checar o estado do pedido |\n\nUse `notification_uuid` como chave de idempotência dos eventos no ERP.\n\n---\n\n## Estratégia recomendada de ACK\n\n1. Buscar notificações.\n    \n2. Processar cada evento no ERP.\n    \n3. Persistir localmente usando `notification_uuid` como chave única.\n    \n4. Enviar ACK somente após sucesso da persistência.\n    \n5. Se o ACK falhar, retentar apenas o ACK. Não reprocessar o evento duplicado.\n    \n\n> ACK cedo demais pode causar perda de evento no ERP. Sem ACK, a notificação reaparece por até 2 dias. \n  \n\n---\n\n## Segurança operacional\n\n- Nunca exponha API Key em frontend, repositório, tickets públicos ou logs.\n    \n- Não commite environments do Postman com secrets preenchidos.\n    \n- Mascare credenciais em evidências de homologação.\n    \n- Trate `401` como configuração incorreta e acione revisão de credenciais.\n    \n\n---\n\n## Homologação\n\n### Obrigatório para todos os parceiros\n\n- Smoke test: `GET /hubs`, `401` com key inválida e `403`/`404` em hub sem permissão.\n    \n- Polling 1: listar ofertas, consultar detalhe completo antes da decisão, aceitar pedido, recusar com motivos, tratar pedido já respondido e pedido expirado.\n    \n- Polling 2: buscar notificações, processar `ORDER_CREATED`, fazer ACK e validar reprocessamento quando não há ACK.\n    \n- Detalhes do pedido: importar dados completos e exibir `order.id` no ERP.\n    \n- Operação: aplicar backoff em `429`, retry em `5xx`/timeout e proteger credenciais nos logs.\n    \n\n### Obrigatório quando aplicável ao escopo\n\n- Envio de NF-e XML com campo multipart `invoice_file`.\n    \n- Tratamento de formatos diferentes de NF-e.\n    \n- Download de etiqueta após `SHIPPING_LABEL_AVAILABLE`.\n    \n- Consulta de `pickup_code` após `ORDER_DELIVERY_PICKING_UP`.\n    \n- Cancelamento pós-aceite antes da coleta.\n    \n\n### Evidências aceitas\n\n- Logs com credenciais mascaradas.\n    \n- Gravação de tela do fluxo em staging.\n    \n\n---\n\n## Boas práticas\n\n- Consulte o detalhe completo de cada oferta antes de aceitar ou recusar.\n    \n- Exiba `order.id` no ERP; é o identificador usado no painel Hubii e no suporte.\n    \n- Armazene `notification_uuid` para evitar duplicidade de processamento.\n    \n- Execute Polling 1 e Polling 2 com o mesmo intervalo recomendado: 30–60 segundos.\n    \n- Cancelamentos Hubii/cliente podem chegar até 1 dia após o evento real.","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"34374925","team":6169040,"collectionId":"7e207411-7624-4909-8d24-35ec0605eb45","publishedId":"2sBXwvJoRJ","public":true,"publicUrl":"https://doc.hubii.io","privateUrl":"https://go.postman.co/documentation/34374925-7e207411-7624-4909-8d24-35ec0605eb45","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"6348e5"},"documentationLayout":"classic-double-column","customisation":{"metaTags":[{"name":"description","value":""},{"name":"title","value":""}],"appearance":{"default":"light","themes":[{"name":"dark","logo":"https://content.pstmn.io/8e790b1c-046c-44b3-9e3c-3b8d80f398ce/aHViaWktbWFpbi1ibHVlLXNxdWFyZS5wbmc=","colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"FF6C37"}},{"name":"light","logo":"https://content.pstmn.io/8e790b1c-046c-44b3-9e3c-3b8d80f398ce/aHViaWktbWFpbi1ibHVlLXNxdWFyZS5wbmc=","colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"6348e5"}}]}},"version":"8.11.14","publishDate":"2026-06-19T21:15:22.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"","description":""},"logos":{"logoLight":"https://content.pstmn.io/8e790b1c-046c-44b3-9e3c-3b8d80f398ce/aHViaWktbWFpbi1ibHVlLXNxdWFyZS5wbmc=","logoDark":"https://content.pstmn.io/8e790b1c-046c-44b3-9e3c-3b8d80f398ce/aHViaWktbWFpbi1ibHVlLXNxdWFyZS5wbmc="}},"statusCode":200},"environments":[],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/a227e2abd84dc3b146cb9b00c01c76e0efa0e15d3d7595e1ffcefc5d935738eb","favicon":"https://res.cloudinary.com/postman/image/upload/v1732208124/team/ec0329432070069ad5e0e76baaea5772.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"}],"canonicalUrl":"https://doc.hubii.io/view/metadata/2sBXwvJoRJ"}