Integração de dados
Visão geral
O Sipru é um copiloto de vendas para o balconista: durante o atendimento, ele sugere substitutos, cross-sell e upsell, e recompensa o vendedor em Sipru Points pelos produtos de maior margem e giro.
Este guia cobre o envio de dados — como o seu catálogo, as suas lojas e o seu histórico de venda chegam até a Sipru. É o que alimenta as recomendações: sem dado não há o que sugerir.
Para a integração em que o vendedor sai da cotação do seu ERP e cai no catálogo Sipru já autenticado, veja Integração ERP.
O que é preciso antes de começar
O onboarding com o time da Sipru entrega três coisas, e nenhuma delas está nesta documentação porque são específicas do seu parceiro:
- o bucket de destino;
- a Service Account com permissão de escrita nele;
- o seu identificador de parceiro, que nomeia a sua pasta.
Ver Suporte para iniciar.
Arquitetura
Os dados do parceiro chegam por quatro caminhos. Todos convergem para o mesmo pipeline de processamento e enriquecimento.
Os quatro caminhos
Arquivo CSV no Cloud Storage. Você deposita arquivos em um bucket dedicado e eles são processados assim que chegam. É o caminho padrão e o mais usado.
→ Envio por arquivo CSV · Dicionário de dados
Conector dedicado. Se você não tem equipe para montar a exportação, o time da Sipru constrói e opera um extrator ligado direto ao seu sistema.
API REST. Envio e consulta por HTTP, em tempo real, direto do seu ERP.
→ Integração via API REST — ainda não disponível
Webhook. Grandes volumes em tempo real, com persistência automática e particionada no Cloud Storage.
→ Integração via Webhook — ainda não disponível
A API REST e o Webhook estão documentados porque o desenho está definido, mas nenhum endpoint deles responde hoje. Cada uma dessas páginas repete o aviso no topo.
Qual método escolher
| Se você… | use | disponível |
|---|---|---|
| já consegue exportar CSV do seu sistema | arquivo CSV | sim |
| precisa de carga completa periódica | arquivo CSV | sim |
| exporta em outro formato, ou só tem o banco | conector dedicado | sim |
| não tem equipe técnica disponível | conector dedicado | sim |
| quer atualização em tempo real via HTTP | API REST | não |
| tem grande volume de eventos em tempo real | webhook | não |
O dicionário desta seção descreve os nomes canônicos que o Sipru usa internamente. Se o seu ERP exporta com outros nomes, o time configura um mapeamento de colunas específico para o seu parceiro no momento do onboarding — você manda o CSV do jeito que o seu sistema já gera. O que não pode faltar é o dado; o nome da coluna a gente resolve.
Estrutura de pastas
Você deposita arquivos no bucket do Cloud Storage entregue no onboarding, e eles são processados assim que chegam. Não há chamada de API, agendamento nem confirmação a fazer.
Formato do arquivo
- CSV em UTF-8, com a primeira linha trazendo o cabeçalho das colunas.
- Uma entidade por arquivo — não misture lojas e produtos no mesmo CSV.
O que o validador aceita sem você precisar ajustar
Boa parte do trabalho de "arrumar o CSV" é desnecessária. O validador é tolerante nestes pontos:
| Separador | vírgula, ponto e vírgula, tabulação ou barra vertical — detectado sozinho pelo cabeçalho |
| Decimal | 47.90 e 47,90 valem o mesmo |
| BOM | um BOM no início do arquivo é ignorado; não precisa removê-lo |
| Booleanos | true/false, 1/0, yes/no, sim/não — maiúsculas ou minúsculas |
| Colunas extras | ignoradas; você não precisa recortar o seu export |
Onde ele é exigente
| Colunas obrigatórias | precisam existir no cabeçalho, com o nome canônico ou o mapeado para você |
Campos data | estritamente YYYY-MM-DD |
Campos data e hora | qualquer formato ISO reconhecível |
| Nome do arquivo | precisa começar pela entidade — ver abaixo |
O nome do arquivo importa
A entidade é deduzida do nome do arquivo, não da pasta. O nome precisa começar pelo nome
da entidade, seguido de _, -, ou nada:
| Nome do arquivo | Resultado |
|---|---|
orders_22052026.csv | reconhecido como orders |
produtos-2026.csv | reconhecido como produtos |
inventory.csv | reconhecido como inventory |
posicao_estoque.csv | não reconhecido — o arquivo é ignorado |
Um arquivo cujo nome não comece por uma das entidades não é processado, e não gera erro visível para você. Se um envio "sumiu", o nome é o primeiro lugar para olhar.
As entidades são lojas, produtos, precos, sellout, orders, inventory e
campaigns —
ver Dicionário de dados.
Onde depositar
Dentro do bucket, a convenção é uma pasta por parceiro e, se você atende mais de uma rede, uma subpasta por rede:
{seu_parceiro}/
└── {sua_rede}/
├── lojas_20260413.csv
├── produtos_20260413.csv
├── sellout_20260413.csv
├── orders_20260413.csv
├── inventory_20260413.csv
└── campaigns_20260413.csv
A data no nome deve ser a do período dos dados, não a do envio — é ela que o time usa para investigar uma carga.
O caminho é convenção, e serve para você se organizar. Quem determina a entidade é sempre o nome do arquivo.
Envio manual via WinSCP
Para quem prefere arrastar e soltar em vez de automatizar. Qualquer cliente que fale com o Cloud Storage serve — Cyberduck ou o próprio console do Google Cloud —, mas o WinSCP é o mais usado pelos parceiros.
1. Instale o WinSCP. Baixe em winscp.net.
2. Configure o protocolo. Na tela de login, mude o protocolo de arquivo para Amazon S3 — é compatível com o Cloud Storage.
3. Defina o host. Preencha com storage.googleapis.com.
4. Insira as credenciais. O Access Key ID e a Secret Key são entregues pelo time no onboarding.
5. Configure o diretório remoto. Em Avançado → Ambientes → Diretórios, preencha
"Diretório Remoto" com {bucket}/{seu_parceiro}.
6. Salve, conecte e envie. Arraste os CSV para a pasta da rede correspondente.
Vale a mesma regra de nome de arquivo: ele precisa começar pela entidade.
Envio via SDK Python
Autentique com a Service Account entregue no onboarding:
export GOOGLE_APPLICATION_CREDENTIALS="$HOME/credenciais-sipru.json"
pip install google-cloud-storage
from datetime import datetime
from pathlib import Path
from google.cloud import storage
BUCKET = "..." # entregue no onboarding
PARCEIRO = "..." # seu identificador de parceiro
REDE = "..." # a rede/cliente a que os dados pertencem
ENTIDADE = "orders" # lojas | produtos | sellout | orders | inventory | campaigns
data = datetime.now().strftime("%Y%m%d")
origem = Path(f"dados/{ENTIDADE}_{data}.csv")
destino = f"{PARCEIRO}/{REDE}/{ENTIDADE}_{data}.csv"
bucket = storage.Client().bucket(BUCKET)
bucket.blob(destino).upload_from_filename(str(origem))
print(f"Enviado: gs://{BUCKET}/{destino}")
Dicionário de dados
Abaixo estão os schemas das entidades aceitas. Todos os arquivos devem ser enviados no formato CSV com encoding UTF-8 e separador vírgula.
A ingestão usa nomes canônicos próprios e aceita um mapeamento de colunas por parceiro. Confirme com o time quais nomes valem para você antes da primeira carga — você não precisa mudar o seu export, mas o mapeamento precisa existir.
Lojas
| Campo | Tipo | Obrig. | Descrição | Exemplo |
|---|---|---|---|---|
location_name | Texto | Sim | Nome/descrição da loja | Loja Shopping SP |
location_code | Texto | Sim | Código único (CNPJ ou ID comercial) | S74 |
is_active | Booleano | Sim | Status da loja (true / false) | true |
category | Texto | Não | Ramo de atuação | Alimentação |
cep | Numérico | Não | CEP da loja | 81000-000 |
uf | Texto | Não | UF do estado | SP |
city | Texto | Não | Cidade | São Paulo |
segment | Texto | Não | Segmento da loja | Alimentação |
channel | Texto | Não | Canal de vendas (varejo, atacado) | Varejo |
Produtos
| Campo | Tipo | Obrig. | Descrição | Exemplo |
|---|---|---|---|---|
product_name | Texto | Sim | Nome/descrição do produto | Bateria p/Celular |
product_code | Texto | Sim | Código único (SKU) | P123 |
is_active | Booleano | Sim | Status do produto (true / false) | true |
category | Texto | Sim | Categoria | Smartphones |
sub_category | Texto | Não | Subcategoria | Android |
master_product | Texto | Não | Produto principal/agrupador | Galaxy |
multiple | Numérico | Não | Múltiplos de venda (padrão: 1) | 5.0 |
ean_code | Texto | Não | Código de barras internacional (GTIN/EAN) | 7891000001234 |
ncm_code | Texto | Não | Nomenclatura Comum do Mercosul (8 dígitos) | 2523.29.10 |
base_price | Decimal | Não | Preço base líquido unitário do produto — referência única para todas as lojas | 58.90 |
Preços
| Campo | Tipo | Obrig. | Descrição | Exemplo |
|---|---|---|---|---|
location_code | Texto | Sim | Código da loja (deve existir em Lojas) | L01 |
product_code | Texto | Sim | Código do produto (deve existir em Produtos) | P123 |
price_name | Texto | Sim | Nome da condição comercial. Identifica a linha e é referenciado em Orders | ATACADO |
unit_cost_price | Decimal | Sim | Custo unitário do produto (CMV) associado a esta condição | 25.00 |
unit_sale_price | Decimal | Sim | Valor líquido unitário de venda desta condição | 47.90 |
Inventory
Posição de estoque. Idealmente o fechamento de D-1.
| Campo | Tipo | Obrig. | Descrição | Exemplo |
|---|---|---|---|---|
location_code | Texto | Sim | Código da loja (deve existir em Lojas) | L01 |
product_code | Texto | Sim | Código do produto (deve existir em Produtos) | P123 |
date | Data | Sim | Data de fechamento do estoque (YYYY-MM-DD) | 2026-04-14 |
quantity | Numérico | Sim | Quantidade em estoque na data | 60.0 |
Orders
Cada item do pedido é um registro individual.
| Campo | Tipo | Obrig. | Descrição | Exemplo |
|---|---|---|---|---|
order_code | Texto | Sim | Código único do pedido | PED-20260414-001 |
location_code | Texto | Sim | Código da loja (deve existir em Lojas) | L01 |
product_code | Texto | Sim | Código do produto (deve existir em Produtos) | P123 |
date | Data | Sim | Data do pedido (YYYY-MM-DD) | 2026-04-14 |
quantity | Numérico | Sim | Quantidade solicitada no pedido | 15.0 |
unit_sale_price | Decimal | Sim | Valor líquido unitário de venda do item (já deduzidos descontos do item e impostos de saída) | 40.00 |
unit_cost_price | Decimal | Sim | Custo unitário do produto em estoque (CMV) associado a este pedido | 25.00 |
order_status | Texto | Sim | Status do pedido (pending / confirmed / shipped / delivered / cancelled) | confirmed |
price_name | Texto | Não | Condição comercial aplicada no item (deve existir em Preços) | ATACADO |
customer_code | Texto | Não | Código do cliente que fez o pedido | CLI-0472 |
delivery_date | Data | Não | Data prevista de entrega (YYYY-MM-DD) | 2026-04-21 |
freight_price | Decimal | Não | Valor total do frete cobrado ou atribuído ao pedido | 150.00 |
discount_price | Decimal | Não | Desconto global aplicado no fechamento do carrinho (valor rateado entre os itens) | 50.00 |
notes | Texto | Não | Observações adicionais do pedido | Entrega urgente |
Sellout
Venda unitária — o que saiu, quando e de qual loja. É o insumo dos algoritmos de substituto, cross-sell e upsell.
| Campo | Tipo | Obrig. | Descrição | Exemplo |
|---|---|---|---|---|
location_code | Texto | Sim | Código da loja (deve existir em Lojas) | L01 |
product_code | Texto | Sim | Código do produto (deve existir em Produtos) | P123 |
date | Data | Sim | Data da venda (YYYY-MM-DD) | 2026-04-14 |
quantity | Numérico | Sim | Quantidade vendida | 12.0 |
gross_amount | Decimal | Não | Valor bruto da venda | 418.80 |
Campaigns
| Campo | Tipo | Obrig. | Descrição | Exemplo |
|---|---|---|---|---|
campaign_id | Texto | Sim | Código único da campanha | CAMP-2026-04 |
name | Texto | Sim | Nome da campanha | Semana do Cimento |
starts_at | Data e hora | Não | Início da campanha | 2026-04-14T00:00:00Z |
ends_at | Data e hora | Não | Fim da campanha | 2026-04-21T23:59:59Z |
budget | Decimal | Não | Verba da campanha | 15000.00 |
Visão geral da API REST
Nenhum endpoint desta seção responde hoje — não há API de ingestão em nenhum ambiente. Para integrar agora, use Cloud Storage ou conector dedicado.
A API REST permite que parceiros enviem lojas, produtos, preços, pedidos e estoque em tempo real, direto do ERP ou do sistema interno.
Base URL
https://api.sipru.ai/v1
Todas as requisições usam HTTPS; requisições HTTP são rejeitadas. O Content-Type esperado é
application/json e o encoding é UTF-8.
Se a API REST é bloqueante para o seu caso, diga a sipru@sipru.ai — saber quem depende dela define a ordem de construção.
Autenticação da API
Autenticação por API Key no header de cada requisição. As credenciais são fornecidas pela equipe de integração durante o onboarding.
Header de autenticação
Authorization: Bearer {sua_api_key}
Content-Type: application/json
X-Partner-ID: {seu_partner_id}
Exemplo com cURL
curl -X POST https://api.sipru.ai/v1/locations \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-H "X-Partner-ID: {seu_partner_id}" \
-d '{ "data": [] }'
Exemplo com Python
import requests
BASE_URL = "https://api.sipru.ai/v1"
HEADERS = {
"Authorization": "Bearer sk_live_...",
"Content-Type": "application/json",
"X-Partner-ID": "{seu_partner_id}",
}
response = requests.post(f"{BASE_URL}/locations", headers=HEADERS, json={"data": []})
print(response.json())
Endpoints
Cada entidade tem endpoint próprio para envio e consulta. Todos aceitam envio unitário ou em
lote — um array de objetos no campo data.
| Método | Endpoint | O que faz |
|---|---|---|
POST | /v1/locations | Envia lojas |
POST | /v1/products | Envia produtos |
POST | /v1/prices | Envia tabela de preços |
POST | /v1/inventory | Envia posição de estoque |
POST | /v1/orders | Envia pedidos e itens |
POST | /v1/campaigns | Cria ou atualiza campanhas |
GET | /v1/{entidade} | Consulta o que foi enviado |
Lojas (locations)
{
"data": [
{
"location_name": "Loja Shopping São Paulo",
"location_code": "S74",
"is_active": true,
"category": "Material de construção",
"cep": "81000-000",
"uf": "SP",
"city": "São Paulo",
"segment": "Varejo",
"channel": "Varejo"
}
]
}
Produtos (products)
{
"data": [
{
"product_name": "Argamassa AC-III 20kg",
"product_code": "P123",
"is_active": true,
"category": "Argamassas",
"sub_category": "Assentamento",
"master_product": "AC-III",
"multiple": 5.0,
"ean_code": "7891000001234",
"base_price": 34.90,
"ncm_code": "3824.50.00"
}
]
}
Preços (prices)
Tabela de preço por loja e condição comercial. Os valores são unitários.
{
"data": [
{
"location_code": "L01",
"product_code": "P123",
"price_name": "ATACADO",
"unit_cost_price": 25.00,
"unit_sale_price": 47.90
}
]
}
Estoque (inventory)
Posição de estoque, idealmente o fechamento de D-1.
{
"data": [
{ "location_code": "L01", "product_code": "P123", "date": "2026-04-14", "quantity": 60.0 }
]
}
Pedidos (orders)
Cada item do pedido é um registro individual.
{
"data": [
{
"order_code": "PED-20260414-001",
"location_code": "L01",
"product_code": "P123",
"date": "2026-04-14",
"quantity": 15.0,
"unit_sale_price": 40.00,
"unit_cost_price": 25.00,
"order_status": "confirmed",
"price_name": "ATACADO",
"customer_code": "CLI-0472",
"delivery_date": "2026-04-21",
"freight_price": 150.00,
"discount_price": 50.00,
"notes": "Entrega urgente"
}
]
}
Consultas (GET)
Também é possível consultar o status dos dados enviados:
GET /v1/locations
GET /v1/products?category=Argamassas
GET /v1/prices?location_code=L01
GET /v1/inventory?location_code=L01
GET /v1/orders?date_from=2026-04-01&order_status=confirmed
Paginação. Respostas com mais de 100 registros são paginadas. Use page e per_page
(máximo 500). O header X-Total-Count indica o total de registros.
Erros e respostas
Resposta de sucesso
{
"status": "success",
"message": "3 registros processados com sucesso.",
"processed": 3,
"errors": 0,
"request_id": "req_8f2a4b6c..."
}
Resposta de erro
{
"status": "error",
"message": "Validação falhou em 1 registro.",
"processed": 2,
"errors": 1,
"details": [
{
"index": 2,
"field": "date",
"code": "INVALID_FORMAT",
"message": "Data deve estar no formato YYYY-MM-DD."
}
]
}
Códigos de status HTTP
| Código | Significado |
|---|---|
200 | OK — requisição processada com sucesso |
201 | Created — registros criados com sucesso |
400 | Bad Request — payload inválido ou campos obrigatórios ausentes |
401 | Unauthorized — API Key inválida ou ausente |
403 | Forbidden — sem permissão para o recurso solicitado |
404 | Not Found — endpoint ou recurso não encontrado |
422 | Unprocessable Entity — dados válidos, mas com erro semântico |
429 | Too Many Requests — rate limit excedido (aguarde 60 s) |
500 | Internal Server Error — erro interno, contate o suporte |
O limite de referência é de 100 requisições por minuto por parceiro. Para cargas grandes, prefira envio em lote ou Cloud Storage.
Conector dedicado
Nem todo parceiro tem equipe disponível para montar uma exportação. No conector dedicado, o time da Sipru constrói, opera e mantém um extrator ligado direto ao seu sistema — você não escreve código.
Quando faz sentido
- Você não tem equipe técnica livre para desenvolver e manter a integração.
- Seu sistema não oferece exportação padrão nem API.
- Trata-se de ERP proprietário, base SQL legada, ou dados que hoje vivem em planilha.
O que a Sipru assume
O extrator é escrito para a sua fonte específica — banco SQL, API interna, plataforma de e-commerce — e roda na infraestrutura da Sipru, em agendamento combinado com você. A saída alimenta o mesmo pipeline do envio por CSV, com o mesmo dicionário de dados.
Já existem conectores em produção lendo bancos de parceiros por rede privada, quando o acesso direto não é possível pela internet.
O que fica do seu lado
Três coisas, e só elas:
- Acesso de leitura à fonte — usuário de banco, credencial de API, ou o caminho combinado.
- Uma pessoa de referência que saiba explicar o modelo de dados do seu sistema: onde está a venda, o que é loja, qual campo é o SKU.
- Aval para a conectividade — se o acesso exige rede privada ou liberação de IP, o time propõe o desenho e você aprova.
O levantamento do seu modelo de dados costuma ser a parte mais longa, e depende mais da disponibilidade dessa pessoa de referência do que do desenvolvimento em si.
Como é o onboarding
1. Levantamento técnico. O time analisa o seu sistema e identifica onde estão os dados, em que formato e com que frequência mudam. É a etapa mais longa, e a que mais depende de você — ver a pessoa de referência acima.
2. Desenvolvimento do conector. O time constrói o extrator e a transformação para o formato do dicionário de dados.
3. Validação conjunta. Testes com dados reais, com você junto, para conferir integridade e consistência antes de valer.
4. Ativação e monitoramento. O conector entra em produção monitorado pelo time, que é avisado quando uma extração falha.
O desenvolvimento, a manutenção e a operação do conector são custeados pela Sipru. Do seu lado ficam apenas os três itens acima.
Para começar, escreva para sipru@sipru.ai contando qual é o seu sistema e quem é o contato técnico.
Webhook
Nenhum endpoint desta seção responde hoje — o serviço de ingestão não é alcançável de fora da infraestrutura da Sipru, e a exposição pública ainda não foi decidida. Para integrar agora, use Cloud Storage ou conector dedicado.
Receba grandes volumes de dados em tempo real via HTTP, com persistência automática no Google Cloud Storage, particionada por data, origem e tipo de evento.
Como funciona
A plataforma disponibiliza endpoints de webhook dedicados para cada parceiro. Ao receber uma requisição HTTP, o webhook captura o payload, valida a estrutura e persiste os dados no GCS de forma organizada e particionada, permitindo consumo posterior para análise e integração.
O desenho prevê baixa latência com resposta imediata, tolerância a picos de tráfego sem perda de dados, e retries automáticos com deduplicação.
Arquitetura do webhook
Fluxo detalhado
1. Recepção da requisição. O parceiro envia um POST para o endpoint exclusivo do
webhook. O sistema responde 202 Accepted imediatamente, confirmando o recebimento.
2. Validação e autenticação. O payload é validado contra o schema esperado, e a
autenticação é verificada por token, header customizado ou assinatura HMAC. Requisições
inválidas recebem 400 ou 401 com detalhe do erro.
3. Enfileiramento com deduplicação. Os dados validados são enfileirados com controle de
duplicidade por idempotency_key. Se a mesma requisição chegar mais de uma vez, só a primeira
é processada.
4. Persistência no GCS. Os dados são gravados particionados por data, origem e tipo de evento.
5. Processamento pelo pipeline. Depois de persistidos, os dados entram no pipeline de validação e enriquecimento, alimentando a plataforma.
Estrutura de particionamento no GCS
{seu_parceiro}/
└── webhooks/
├── event_type=orders/
│ └── date=2026-04-14/
│ ├── batch_001.json
│ └── batch_002.json
├── event_type=inventory/
│ └── date=2026-04-14/
│ └── batch_001.json
└── event_type=prices/
└── date=2026-04-14/
└── batch_001.json
Mecanismos de resiliência
| Mecanismo | Descrição |
|---|---|
| Retries automáticos | Em caso de falha na persistência, até 5 tentativas com backoff exponencial (1 s, 2 s, 4 s, 8 s, 16 s). |
| Controle de duplicidade | Cada requisição pode incluir idempotency_key. Eventos duplicados são descartados dentro de uma janela de 24 h. |
| Dead Letter Queue | Mensagens que falharam após todas as tentativas vão para uma fila de erros, para investigação e reprocessamento manual. |
| Resposta assíncrona | O endpoint retorna 202 Accepted de imediato, desacoplando recepção de processamento e evitando timeout. |
| Circuit breaker | Em falha sistêmica, entra em modo de proteção e enfileira os dados até a recuperação do serviço. |
Formato do payload
{
"event_type": "orders",
"idempotency_key": "evt_2026041410300001",
"timestamp": "2026-04-14T10:30:00Z",
"data": [
{
"location_code": "L01",
"product_code": "P123",
"date": "2026-04-14",
"quantity": 60.0,
"unit_sale_price": 40.00,
"unit_cost_price": 25.00,
"order_status": "confirmed"
}
]
}
Resposta do webhook
{
"status": "accepted",
"request_id": "req_8f2a4b6c9d...",
"idempotency_key": "evt_2026041410300001",
"message": "Payload recebido e enfileirado para processamento."
}
Portal self-service
O desenho prevê que o parceiro crie, configure e monitore os próprios webhooks por uma interface, sem depender de suporte técnico.
| Funcionalidade | Descrição |
|---|---|
| Criar e gerenciar endpoints | Cada endpoint gera um link único para envio de dados. |
| Configurar autenticação | Bearer Token, headers customizados ou assinatura HMAC-SHA256, com rotação de token sem downtime. |
| Visualizar logs de requisições | Histórico completo com status, payload recebido, tempo de resposta e detalhe de validação. |
| Métricas em tempo real | Volume de eventos, taxa de sucesso e erro, latência média e alertas por threshold. |
Exemplo: endpoint criado pelo portal
Cada endpoint criado geraria um link único:
https://webhooks.sipru.ai/v1/ingest/wh_abc123def456
Exemplo: enviando dados
curl -X POST https://webhooks.sipru.ai/v1/ingest/wh_abc123def456 \
-H "Authorization: Bearer whsec_live_..." \
-H "Content-Type: application/json" \
-d '{
"event_type": "orders",
"idempotency_key": "evt_2026041410300001",
"timestamp": "2026-04-14T10:30:00Z",
"data": [
{
"location_code": "L01",
"product_code": "P123",
"date": "2026-04-14",
"quantity": 60.0,
"unit_sale_price": 40.00,
"unit_cost_price": 25.00,
"order_status": "confirmed"
}
]
}'
A tela existe em /integracoes/webhooks, mas sem backend: os endpoints exibidos não são
emitidos de verdade e não recebem tráfego.
Segurança do webhook
| Camada | Mecanismo | Descrição |
|---|---|---|
| Autenticação | Bearer Token / HMAC-SHA256 | Cada endpoint tem um token secreto. Opcionalmente, assinatura HMAC valida a integridade do payload. |
| Transporte | TLS obrigatório | Todas as requisições usam HTTPS; conexões HTTP são rejeitadas. |
| Rate limiting | Controle por endpoint | Limite configurável por endpoint (padrão 1.000 req/min). Excedentes recebem 429. |
| IP allowlisting | Filtro por IP de origem | Opcionalmente, restringe o acesso a uma lista de IPs autorizados. |
| Acesso ao GCS | IAM com menor privilégio | Os dados persistidos são acessíveis apenas pelo pipeline, por service accounts com permissão mínima. |
| Proteção contra abuso | Limite de tamanho | Payloads limitados a 5 MB. Requisições maiores recebem 413. |
Validação via HMAC-SHA256
O parceiro calcula a assinatura sobre o corpo cru da requisição e a envia no header. A plataforma recalcula e compara.
import hashlib
import hmac
webhook_secret = "whsec_live_..." # fornecido no onboarding
payload_body = b'{"event_type":"orders"}' # corpo cru da requisição
signature = hmac.new(webhook_secret.encode(), payload_body, hashlib.sha256).hexdigest()
headers = {
"X-Webhook-Signature": f"sha256={signature}",
"Content-Type": "application/json",
}
Observabilidade
| Descrição | |
|---|---|
| Logs | Log estruturado de cada requisição: timestamp, status, tempo de processamento, tamanho do payload e detalhe de validação. Retenção de 90 dias. |
| Métricas | Volume de eventos por minuto, hora e dia; taxa de sucesso e erro; latência P50, P95 e P99; tamanho médio do payload; uso do rate limit. |
| Alertas | Configuráveis por threshold — taxa de erro acima de X%, latência acima de Y ms, volume abaixo do esperado. Notificação por e-mail ou webhook reverso. |
Códigos de resposta do webhook
| Código | Significado |
|---|---|
202 | Accepted — payload recebido e enfileirado |
400 | Bad Request — payload inválido ou schema incorreto |
401 | Unauthorized — token inválido ou assinatura HMAC incorreta |
403 | Forbidden — IP não autorizado, quando o allowlisting está ativo |
409 | Conflict — idempotency_key já processada, duplicata descartada |
413 | Payload Too Large — payload acima de 5 MB |
429 | Too Many Requests — rate limit excedido para o endpoint |
500 | Internal Server Error — erro interno, dados enfileirados para retry |
Para acompanhar a disponibilização desta integração, escreva para sipru@sipru.ai.
Checklist antes do envio
- O nome do arquivo começa pela entidade, no padrão
entidade_YYYYMMDD.csv? - A data no nome corresponde ao período dos dados, não ao dia do envio?
- O cabeçalho tem todas as colunas obrigatórias daquela entidade?
- Os campos
dataestão emYYYY-MM-DD? (nem toda entidade usa o mesmo campo de data — ver o dicionário) - Os valores monetários são unitários, não o total da linha?
- Os
location_codeeproduct_codereferenciados já foram enviados emlojaseprodutos, e são os mesmos códigos em todas as entidades? - Os códigos estão sem espaço sobrando no começo ou no fim?
- O arquivo está em UTF-8? Acento quebrado no cabeçalho impede o reconhecimento da coluna.
Separador, BOM, vírgula decimal e colunas extras não precisam de conferência — ver o que o validador aceita.
Suporte
Em caso de dúvida sobre a integração, escreva para sipru@sipru.ai.
O time acompanha todo o processo de integração sem custo para o parceiro. Vale agendar uma call de kickoff para receber as credenciais e tirar as dúvidas técnicas de uma vez.