Skip to Content
Documentação de integração da plataforma — em evolução contínua.
PedidosRegistrar o webhook

Registrar o webhook

O webhook é o canal automatizado pelo qual você descobre o resultado do processamento assíncrono: sem ele, um lote aceito com 200 OK que falhou depois não avisa o seu ERP.

Ele não é a única forma de enxergar o que aconteceu — o painel administrativo da Grocers mostra as operações e o resultado de cada uma, e serve para conferência manual e apuração de suporte. A diferença é o uso: o painel é consulta humana, o webhook é o que a sua integração consome sem alguém olhando. Para operação diária, é o webhook que precisa estar de pé.

Endpoint

POST /v1/Webhooks
curl -X POST $GROCERS_API/v1/Webhooks \ -H "Authorization: Basic $BASIC" \ -H "x-contractAccountId: $TENANT" \ -H "Content-Type: application/json" \ -d '{ "originType": "Api_call", "originData": "ERP-Producao", "url": "https://api.seusite.com/webhooks/grocers", "authType": "Bearer", "authToken": "s3gr3d0-do-erp", "eventTypes": [ "ProductWithSKUs_Created", "ProductWithSKUs_Updated", "ProductWithSKUs_CreationFailed", "ProductWithSKUs_UpdateFailed", "ProductWithSKUs_PartiallyFailed", "Order_Updated", "Order_StatusUpdateFailed", "Order_CancelFailed", "Operation_Failed" ] }'

Resposta de sucesso — 200, com dois campos e nada mais:

{ "id": "5c1d9e70-2b3a-4f18-9d6c-7e8f0a1b2c3d", "url": "https://api.seusite.com/webhooks/grocers" }
CódigoSignificadoO que fazer
200registro criadoguarde o id; ele é o único comprovante que você terá
400originType fora do enum, originData ou url vazios, um eventTypes inválido, ou x-contractAccountId ausente/malformadocorrija o corpo ou o header
409já existe um webhook para este contractAccountIdnão há rota de alteração nem de exclusão: abra chamado
500falha internaretente
CampoTipoObrigatórioDescrição
originTypeenumsimUser (1) ou Api_call (2)
originDatastringsimIdentificador livre da origem
urlstringsimURL que recebe as notificações — só é validado que não está vazia
authTypestringnãoBearer ou Basic
authTokenstringnãoValor enviado no header Authorization de cada entrega
eventTypesarrayna prática, simEventos assinados — veja Eventos de webhook

Formato da notificação

Toda notificação chega como POST com o mesmo envelope, qualquer que seja o evento:

{ "operationId": "54d6a979-5f62-4e17-9d4c-dbd9f5ede403", "contractAccountId": "9f36a666-acd5-4987-a47f-3de247f65d82", "relatedEntity": "ProductWithSKUs", "eventType": "ProductWithSKUs_Created", "data": { "product": { "externalReference": "PROD-114970", "name": "Macarrão Espaguete 500g", "processed": true, "error": null }, "skus": { "total": 2, "successful": 2, "failed": 0, "successfulSKUs": ["114970", "114970-CS"], "failedSKUs": [] }, "summary": { "status": "Success", "processedAt": "2026-07-29T14:32:10.512Z" } } }

O data de catálogo é um relatório do processamento do produto inteiro, não uma cópia do que você enviou: um produto e seus SKUs viram uma notificação só, com a contagem de sucessos e a lista dos SKUs que falharam. summary.status é Success, PartialFailure ou Failed.

CampoDescrição
operationIdCorrelaciona a notificação com o lote que a originou
relatedEntityEntidade do evento — um de ProductWithSKUs, Category, Brand, Warehouse, WarehouseSKU, SKUPricing, Order, User
eventTypeNome do evento, em texto — não o código numérico
dataPayload específico do evento
contractAccountIdTenant dono do dado
errorPresente apenas em falhas

Onde fica o erro

O diagnóstico de falha aparece em um de dois lugares, e qual deles depende da entidade:

EntidadeOnde está o erro
ProductWithSKUsdentro de data — em data.product.error e em data.skus.failedSKUs[].error. O campo error do envelope não vem
Brand, Category, Warehouse, SKUPricing, Order, Userno campo error do envelope

Catálogo (ProductWithSKUs_CreationFailed, _UpdateFailed, _PartiallyFailed):

{ "operationId": "54d6a979-5f62-4e17-9d4c-dbd9f5ede403", "contractAccountId": "9f36a666-acd5-4987-a47f-3de247f65d82", "relatedEntity": "ProductWithSKUs", "eventType": "ProductWithSKUs_PartiallyFailed", "data": { "product": { "externalReference": "PROD-114970", "name": "Macarrão Espaguete 500g", "processed": true, "error": null }, "skus": { "total": 2, "successful": 1, "failed": 1, "successfulSKUs": ["114970"], "failedSKUs": [ { "externalReference": "114970-CS", "error": { "statusCode": 400, "message": "{\"errors\":{\"ManufacturerCode\":[\"Código do fabricante é obrigatório\"]}}", "title": "Requisição inválida", "detail": "Ocorreram um ou mais erros de validação", "validationErrors": [ { "id": 1, "key": "ManufacturerCode", "validation": "Código do fabricante é obrigatório" } ] } } ] }, "summary": { "status": "PartialFailure", "processedAt": "2026-07-29T14:32:10.512Z" } } }

Demais entidades — o erro vem no envelope:

{ "operationId": "54d6a979-5f62-4e17-9d4c-dbd9f5ede403", "contractAccountId": "9f36a666-acd5-4987-a47f-3de247f65d82", "relatedEntity": "Brand", "eventType": "Brand_CreationFailed", "data": { "externalReference": "MARCA-001", "name": "Marca Teste" }, "error": { "statusCode": 400, "message": "{\"errors\":{\"Name\":[\"Nome é um campo obrigatório\"]}}", "title": "Requisição inválida", "detail": "Ocorreram um ou mais erros de validação", "instance": "/v1/brands/integration", "traceId": "00-3f2a91c4b7…-01", "validationErrors": [ { "id": 1, "key": "Name", "validation": "Nome é um campo obrigatório" } ] } }
Campo de errorConteúdo
statusCodecódigo HTTP que o core devolveu ao processador
messagecorpo cru da resposta do core — guarde-o, é o que sobra quando validationErrors vem vazio
title / detail / instance / traceIdcampos do ProblemDetails, quando o core respondeu nesse formato
validationErrorslista { id, key, validation }key é a propriedade reprovada

Como receber bem

Persista, responda, processe depois

Grave a notificação crua numa fila sua, responda 200 e só então processe. Nessa ordem: se você responde antes de persistir e o seu processo cai no meio, a plataforma já considerou a entrega bem-sucedida e o evento não volta.

Trate como “pelo menos uma vez”

A retentativa pode entregar a mesma notificação mais de uma vez — são até 3 entregas, sem espera entre elas.

A chave de deduplicação canônica, válida para todo tipo de evento, é operationId + eventType + a identidade da entidade dentro de data. Ela está definida com a tabela por entidade em Receber pedidos (webhook) → Deduplicação.

Não deduplique só por operationId. Ele identifica a operação, não a notificação: um POST /v1/batch/Products com 500 produtos gera 500 notificações com o mesmo operationId. Deduplicar por ele descarta 499.

Não assuma ordem

Notificações de um mesmo lote chegam independentes entre si. Se a ordem importa para o seu processamento, reordene pelo seu lado.

Registre o payload cru

Guardar o JSON recebido, mesmo o que você descartou, é o que torna possível investigar divergência depois.