Receber e processar pedidos¶
O Gubee expõe pedidos via um modelo híbrido pull + push:
- Pull — filas HTTP por status, paginadas em HATEOAS (
hal+json). - Push — webhooks HTTP enviados quando um pedido muda de status.
A recomendação é usar os dois: webhook como camada reativa de baixa latência, e poll periódico como rede de segurança para recuperar webhooks perdidos.
Pré-requisitos¶
- Catálogo sincronizado — produtos precisam existir para que os itens do pedido referenciem SKUs válidos.
- Estoque e preço atualizados — o pedido só "cai na fila" quando o pagamento é confirmado pelo marketplace.
Lifecycle do pedido¶
┌──────────┐
│ CREATED │ ← pedido criado no marketplace
└────┬─────┘
│ marketplace confirma pagamento
▼
┌──────────┐
┌──────────│ PAID │
│ └────┬─────┘
│ │ PUT /orders/invoiced/{orderId}
│ ▼
│ ┌──────────┐
│ │ INVOICED │ ← NF emitida
│ └────┬─────┘
│ │ PUT /orders/shipped/{orderId}
│ ▼
│ ┌──────────┐
│ │ SHIPPED │ ← etiqueta gerada, transporte iniciado
│ └────┬─────┘
│ │ PUT /orders/delivered/{orderId}/{shipmentCode}
│ ▼
│ ┌──────────┐
│ │ DELIVERED│
│ └──────────┘
│
│ marketplace cancela
▼
┌──────────┐
│ CANCELED │ ← pode sair de CREATED, PAID, INVOICED, SHIPPED, DELIVERED
└──────────┘
┌──────────┐
entrega ─────►│ RETURNED │ ← PUT /orders/returned/{orderId}?marketplaceStatus=
└──────────┘
Filas disponíveis para consumo via GET:
| Status | Quando entra na fila |
|---|---|
CREATED |
Pedido criado no marketplace (ainda não pago). |
PAID/PAYED |
Pagamento confirmado. Ambos aceitos (aliases). |
INVOICED |
NF emitida e confirmada via PUT. |
SHIPPED |
Pedido despachado via PUT. |
DELIVERED |
Pedido entregue ao destinatário via PUT. |
CANCELED |
Pedido cancelado (manual ou pelo marketplace). |
REJECTED |
Update rejeitado pelo marketplace (30 dias de histórico). |
Consumo via fila (pull)¶
GET /integration/orders/queue/{status} retorna pedidos paginados em
PagedModel<EntityModel<OrderApiDTO>> (HATEOAS). Pedidos permanecem na fila
até serem explicitamente removidos via DELETE — idempotentes no GET.
Request¶
curl 'https://api.gubee.com.br/integration/orders/queue/PAID?page=0&size=50&sort=createdDt,asc' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Accept: application/hal+json'
Response¶
{
"_embedded": {
"orderApiDTOList": [
{
"id": "MLB1234567890",
"status": "PAID",
"totalAmount": 4999.90,
"currency": "BRL",
"createdDt": "2026-07-07T10:30:00Z",
"paidDt": "2026-07-07T10:31:15Z",
"customer": {
"name": "Maria Silva",
"email": "maria.silva@example.com",
"documents": [{ "type": "CPF", "value": "12345678900" }],
"phones": [{ "type": "MOBILE", "number": "11987654321", "countryCode": "55" }],
"address": {
"street": "Avenida Paulista", "number": "1578",
"district": "Bela Vista", "city": "São Paulo",
"state": "SP", "zipCode": "01310-200", "country": "Brasil"
}
},
"items": [
{
"skuId": "sku-uuid-1001-blk",
"sku": "PHONE-1001-BLK",
"name": "Samsung Galaxy S24 256GB Preto",
"qty": 1,
"unitPrice": 4999.90,
"totalPrice": 4999.90
}
],
"shipments": [],
"_links": {
"self": { "href": "https://api.gubee.com.br/integration/orders/MLB1234567890" }
}
}
]
},
"_links": {
"first": { "href": "...?page=0&size=50" },
"self": { "href": "...?page=0&size=50" },
"next": { "href": "...?page=1&size=50" },
"last": { "href": "...?page=3&size=50" }
},
"page": {
"size": 50, "totalElements": 187, "totalPages": 4, "number": 0
}
}
HATEOAS¶
O campo _links contém URIs prontas para navegação (first, self, next,
last). Clientes HATEOAS descobrem próximas páginas sem construir URLs.
Query params¶
| Parâmetro | Descrição |
|---|---|
page |
Página (0-indexed). |
size |
Itens por página (1-100). Default 20. |
sort |
campo,asc ou campo,desc. Ex.: createdDt,asc. |
ACK — remover pedido da fila¶
DELETE /integration/orders/queue/{status}/{orderId} marca o pedido como
consumido. Idempotente — chamar de novo retorna 200 (ou 404 se já removido).
Semântica at-least-once: o mesmo pedido pode aparecer mais de uma vez na fila se você não der ACK. Processe de forma idempotente (use o
orderIdcomo chave de deduplicação).
curl -X DELETE 'https://api.gubee.com.br/integration/orders/queue/PAID/MLB1234567890' \
-H 'Authorization: Bearer $TOKEN'
Fluxo recomendado por pedido¶
GET /queue/PAID
└── para cada order:
1. Verifica idempotência no ERP (já processado?)
2. Salva no ERP (transação local)
3. DELETE /queue/PAID/{orderId} (ack)
4. Prossegue para próxima transição (invoice, ship, etc.)
Nunca inverta 2 e 3: ACK antes de persistir localmente gera perda de pedido se o ERP cair entre os dois passos.
Fila de rejeições (REJECTED)¶
Updates que o marketplace rejeitou (geralmente shipped, delivered,
canceled) ficam acessíveis por 30 dias:
curl 'https://api.gubee.com.br/integration/orders/queue/rejected?page=0&size=50' \
-H 'Authorization: Bearer $TOKEN'
Response (RejectedOrderDTO):
{
"_embedded": {
"rejectedOrderDTOList": [
{
"orderId": "MLB1234567890",
"status": "SHIPPED",
"rejectedDt": "2026-07-07T11:00:00Z",
"reason": "invalid tracking code format",
"attemptedPayload": { "...": "..." }
}
]
},
"page": { "size": 50, "totalElements": 3, "totalPages": 1, "number": 0 }
}
Tratamento¶
- Leia o
reasonpara corrigir o payload. - Re-envie o PUT correspondente (ex.:
PUT /orders/shipped/{orderId}) com o payload corrigido. - Dê ACK em
/queue/rejected/{orderId}após corrigir.
Transições de lifecycle (PUT)¶
Cada transição avança o pedido para o próximo estado. A tentativa de pular
estados (ex.: CREATED direto para SHIPPED) é rejeitada.
Faturar — PUT /integration/orders/invoiced/{orderId}¶
Aplica-se a pedido PAID. Anexa a NF e move para INVOICED.
curl -X PUT 'https://api.gubee.com.br/integration/orders/invoiced/MLB1234567890' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"line": "NFe",
"issueDate": "2026-07-07T12:00:00",
"danfeXml": "<nfe>...</nfe>",
"danfeLink": "https://storage.gubee.com.br/danfe/MLB1234567890.pdf",
"key": "NFe35260707891234000111150010000012341123456789",
"number": "123451"
}'
InvoiceOrderApiDTO:
| Campo | Tipo | Obrigatório | Notas |
|---|---|---|---|
line |
string |
sim | Modelo: NFe, NFSe. |
issueDate |
LocalDateTime |
sim | Data de emissão. |
danfeXml |
string |
não | XML da NF. |
danfeLink |
string |
não | URL de download da DANFE. |
key |
string |
sim* | Chave de acesso (44 dígitos). |
number |
string |
sim* | Número da NF. |
*Se você enviar um valor com 44+ caracteres em
keyounumber, o backend identifica automaticamente qual é a chave e qual é o número. São intercambiáveis na prática.
Despachar — PUT /integration/orders/shipped/{orderId}¶
Aplica-se a pedido INVOICED.
curl -X PUT 'https://api.gubee.com.br/integration/orders/shipped/MLB1234567890' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"code": "SHIPPED",
"invoiceKey": "NFe35260707891234000111150010000012341123456789",
"transport": {
"name": "Correios",
"trackingCode": "ON123456789BR",
"method": "SEDEX",
"type": "CARRIER"
},
"items": [
{
"skuId": "sku-uuid-1001-blk",
"qty": 1
}
],
"tracks": [
{ "number": "ON123456789BR", "url": "https://rastreio.correios.com.br/ON123456789BR" }
],
"estimatedDeliveryDt": "2026-07-12T18:00:00"
}'
ShipmentOrderApiDTO:
| Campo | Tipo | Obrigatório | Notas |
|---|---|---|---|
code |
string |
sim | Código interno do shipment (uuid do grupo). |
invoiceKey |
string |
não* | Obrigatório se houver múltiplas NFs. |
transport |
TransportOrderApiDTO |
sim | Transportadora + tracking. |
items |
Set<ItemOrderDTO> |
sim | Itens incluídos neste shipment. |
tracks |
Set<TrackingOrderDTO> |
não | Tracking numbers individuais. |
estimatedDeliveryDt |
LocalDateTime |
sim | Estimativa de entrega. |
*Se
invoiceKeyfor omitido e houver apenas 1 NF no pedido, o backend usa automaticamente a chave da única NF existente.
Entregar — PUT /integration/orders/delivered/{orderId}/{shipmentCode}¶
Aplica-se a pedido SHIPPED. {shipmentCode} é o code usado no shipment.
curl -X PUT 'https://api.gubee.com.br/integration/orders/delivered/MLB1234567890/SHIPPED' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"deliveredDt": "2026-07-12T14:30:00Z"
}'
Cancelar — PUT /integration/orders/cancel/{orderId}¶
Pode partir de CREATED, PAID, INVOICED, SHIPPED ou DELIVERED.
Nem todos marketplaces aceitam cancelamento em qualquer estágio.
curl -X PUT 'https://api.gubee.com.br/integration/orders/cancel/MLB1234567890' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"cancelDt": "2026-07-07T15:00:00Z"
}'
Devolver — PUT /integration/orders/returned/{orderId}?marketplaceStatus=...¶
Marca o pedido como devolvido. O parâmetro marketplaceStatus carrega o
motivo/status reportado pelo marketplace.
curl -X PUT 'https://api.gubee.com.br/integration/orders/returned/MLB1234567890?marketplaceStatus=RETURNED' \
-H 'Authorization: Bearer $TOKEN'
Marcar como pago (sandbox) — PUT /integration/orders/paid/{orderId}?marketplaceStatus=...¶
Sandbox-only. Em produção, o status
PAIDsó vem via webhook do marketplace.
curl -X PUT 'https://api.gubee.com.br/integration/orders/paid/MLB1234567890?marketplaceStatus=PAID' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '[]'
Body opcional: Set<PaymentApiDTO> com detalhes do pagamento.
Push via webhooks¶
Para baixa latência, configure webhooks em Eventos de webhook.
O Gubee faz POST HTTP para a URL cadastrada quando o pedido muda de status.
Recuperação de webhooks perdidos¶
Se seu endpoint ficar indisponível, o Gubee armazena as notificações perdidas por 7 dias. Recupere via:
curl 'https://api.gubee.com.br/integration/notifications/missed/{urlName}?page=0&size=100' \
-H 'Authorization: Bearer $TOKEN'
urlName é o nome cadastrado no painel de webhooks. Após processar cada
notificação perdida, marque como lida:
curl -X DELETE 'https://api.gubee.com.br/integration/notifications/missed/{notificationId}' \
-H 'Authorization: Bearer $TOKEN'
Estratégia de polling¶
worker ──► GET /queue/PAID (page=0, size=50)
├── se vazio: sleep 30s, repetir
├── se cheio:
│ ├── para cada order:
│ │ ├── persiste local
│ │ ├── DELETE /queue/PAID/{orderId}
│ │ └── dispara próxima transição (invoice async)
│ └── se page.next existe: continua imediatamente
└── escala workers horizontalmente particionando por seller
Intervalo recomendado¶
| Volume diário (por seller) | Intervalo de poll |
|---|---|
| < 100 pedidos | 2 minutos |
| 100-1000 | 30 segundos |
| 1000-10000 | 10 segundos |
| > 10000 | 5 segundos + múltiplos workers por status |
Anti-patterns¶
- Poll agressivo (< 5s) sem volume real: gera rate limit e aquecimento desnecessário.
- ACK antes de persistir: perda de pedido em crash.
- Processamento síncrono dentro do loop de poll: bloqueia o worker. Use fila interna (uma fila interna (RabbitMQ, SQS, Redis Streams, etc)) para desacoplar consumo de processamento.
Idempotência¶
| Operação | Idempotente por |
|---|---|
GET /queue/{status} |
Sempre (pode repetir). |
DELETE /queue/.../{id} |
Sim — segundo DELETE = 404 esperado. |
PUT /orders/invoiced/.. |
orderId — re-envio do mesmo payload atualiza. |
PUT /orders/shipped/.. |
orderId + code (uuid do shipment). |
PUT /orders/cancel/.. |
orderId — cancelamento de pedido já cancelado é no-op. |
Tratamento de erros comuns¶
| Status | Causa | Ação |
|---|---|---|
| 400 | Transição inválida (ex.: CREATED → SHIPPED) |
Siga o lifecycle — passe por PAID e INVOICED antes. |
| 404 | Pedido não encontrado ou status não aplicável | Re-leia o pedido via GET /orders/{orderId}. |
| 409 | Conflito de estado (raro) | Re-leia e reconcilie. |
| 422 | Payload inválido (ex.: key mal formatada) |
Corrija e refaça. |
Próximos passos¶
- Faturamento e DANFE — fluxo completo de emissão de NF
via serviço
invoicer. - Etiquetas de envio — geração de etiquetas e PLPs.
- Eventos de webhook — referência completa de eventos.