Download OpenAPI specification:Download
Handoff SSO, canal ao vivo e push de produto para a tela do vendedor.
Contrato server-to-server entre o ERP parceiro e o Sipru. Cobre os dois modos de integração hoje em produção:
POST /api/erp/sso/session): o ERP pede uma URL de
entrada e o vendedor "sai" do ERP já logado na conta Sipru real dele,
com a cotação e o cliente anexados ao contexto.POST /api/erp/channel): além do handoff, abre um
canal em que o ERP empurra produtos para a tela que o vendedor está
olhando (POST /api/erp/channel/{channelId}/product).O caminho de volta — o Sipru avisando o ERP que um item entrou no
carrinho — está descrito em webhooks, e é implementado pelo parceiro.
Autenticação. Toda rota exige as duas credenciais juntas:
X-Sipru-Partner-Id: <id do parceiro> e
Authorization: Bearer <segredo do parceiro>. O segredo é emitido em
/integracoes/erp-sso e guardado apenas como hash — ele é exibido uma
única vez, na emissão ou na rotação.
environment é sandbox por padrão. Esse campo decide qual banco do ERP
recebe a gravação do pedido, e apenas o literal "prd" seleciona a base
real. Qualquer outro valor, incluindo o campo ausente, cai no sandbox —
deliberadamente, para que um campo esquecido nunca escreva na base de
produção do parceiro.
Devolve uma URL de uso único, válida por ERP_SSO_TOKEN_TTL_SEC
(600 s por padrão). A URL funciona exatamente uma vez: um segundo
clique ou um reload da mesma URL responde
ERP_SSO_TOKEN_ALREADY_USED. Para testar de novo, gere uma URL nova —
esse comportamento é a proteção contra replay, não um defeito.
| tempQuoteId required | string <= 120 characters Identificador da cotação em aberto no ERP. É a chave de idempotência da gravação do pedido — uma gravação por cotação. |
| quoteId | string <= 120 characters Número definitivo da cotação/orçamento, quando já existe. |
required | object |
object (Cliente) Cliente da cotação. Todos os campos são opcionais. | |
| companyId | string <= 120 characters Tenant no Sipru. Opcional: se omitido, |
| locationId required | string <= 120 characters Loja. Com |
| pricingPolicy | string (PricingPolicy) Enum: "margem1" "margem2" "margem3" "margem4" Faixa de margem aplicada aos preços exibidos. Valor desconhecido ou
ausente cai em |
| environment | string (Environment) Enum: "dev" "prd" Banco do ERP que recebe a gravação do pedido. Só o literal |
| redirectPath | string Caminho interno para onde mandar o vendedor depois do login.
Precisa começar com |
{- "tempQuoteId": "TMP-90321",
- "quoteId": "ORC-2026-1187",
- "vendedor": {
- "cpf": "12345678909"
}, - "cliente": {
- "cnpj": "04252011000110",
- "razaoSocial": "Construtora Alvorada Ltda",
- "nomeFantasia": "Alvorada Materiais"
}, - "locationId": "07526557000100",
- "pricingPolicy": "margem2",
- "environment": "dev"
}{- "expiresAt": "2019-08-24T14:15:22Z",
- "contextId": "84451116-c600-49e2-9c60-5b6b34fae0d6"
}Faz tudo o que /api/erp/sso/session faz e ainda cria um canal
identificado por channelId, com os endpoints para o ERP empurrar
produtos e para a tela do vendedor consumir os eventos.
Se cartCallbackUrl for informado, ele tem precedência sobre a
configuração de loja em /integracoes/cart-erp para o webhook de
item adicionado (ver webhooks).
| tempQuoteId required | string <= 120 characters Identificador da cotação em aberto no ERP. É a chave de idempotência da gravação do pedido — uma gravação por cotação. |
| quoteId | string <= 120 characters Número definitivo da cotação/orçamento, quando já existe. |
required | object |
object (Cliente) Cliente da cotação. Todos os campos são opcionais. | |
| companyId | string <= 120 characters Tenant no Sipru. Opcional: se omitido, |
| locationId required | string <= 120 characters Loja. Com |
| pricingPolicy | string (PricingPolicy) Enum: "margem1" "margem2" "margem3" "margem4" Faixa de margem aplicada aos preços exibidos. Valor desconhecido ou
ausente cai em |
| environment | string (Environment) Enum: "dev" "prd" Banco do ERP que recebe a gravação do pedido. Só o literal |
| cartCallbackUrl | string <uri> <= 500 characters Endpoint do parceiro que recebe o webhook |
object Credencial estática do callback. OAuth não é suportado aqui. | |
| ttlSec | integer [ 1 .. 86400 ] Validade do canal em segundos. Valores acima de 86400 são truncados; valor inválido cai no padrão do servidor. |
{- "tempQuoteId": "TMP-90321",
- "vendedor": {
- "cpf": "12345678909"
}, - "locationId": "07526557000100",
- "pricingPolicy": "margem1",
- "environment": "dev",
- "cartCallbackAuth": {
- "mode": "bearer",
- "token": "••••"
}, - "ttlSec": 14400
}{- "channelId": "5f6d08bc-455a-4532-98b8-19e2cee51160",
- "contextId": "84451116-c600-49e2-9c60-5b6b34fae0d6",
- "expiresAt": "2019-08-24T14:15:22Z",
- "channelExpiresAt": "2019-08-24T14:15:22Z",
}Resolve o termo no catálogo da loja do canal — com o tenant e a política de preço do próprio canal — e publica o resultado na tela que o vendedor está olhando, junto com substitutos, cross-sell e upsell.
A precedência do termo é productCode → ean → query, porque o
código do parceiro é o mais determinístico e o texto livre é o último
recurso (cobre o caso de o código não existir no catálogo Sipru).
| channelId required | string <uuid> O |
| productCode required | string <= 120 characters Código do produto no ERP do parceiro. |
| ean | string <= 60 characters |
| query | string <= 120 characters Texto livre. |
| quantity | integer [ 1 .. 9999 ] Default: 1 Valor inválido ou ausente vira 1; acima de 9999 é truncado. |
{- "productCode": "72411",
- "quantity": 4
}{- "seq": 0,
- "product": {
- "sku": "string",
- "name": "string",
- "price": 0,
- "coinsReward": 0
}, - "recommendations": {
- "substitutes": 0,
- "crossSell": 0,
- "upsell": 0
}
}Quando o vendedor clica em "adicionar" na tela do Sipru, o Sipru faz
POST no endpoint do parceiro. O destino é resolvido nesta ordem:
cartCallbackUrl do canal, quando enviado na criação;cartCallbackUrl cadastrada para a loja em /integracoes/cart-erp;erpBaseUrl + orderEndpointPath da mesma configuração.Sem nenhum dos três, o clique não vira POST.
Contrato esperado do parceiro: responder 2xx. O Sipru tenta 2 vezes,
com timeout de 8 s, e só repete em status transitório (408, 429, 5xx) —
um 4xx não transitório recusa o item de vez. Deduplique por
Idempotency-Key, que também vem no corpo como idempotencyKey.
| Idempotency-Key required | string Igual ao |
| idempotencyKey required | string |
| event required | string Value: "cart_item_added" |
| channelId required | string <uuid> |
| tempQuoteId required | string |
| quoteId | string or null |
object (Cliente) Cliente da cotação. Todos os campos são opcionais. | |
required | object |
required | object |
required | object |
| timestamp required | string <date-time> |
{- "idempotencyKey": "erp_cart_4f1c…",
- "event": "cart_item_added",
- "channelId": "5f6d08bc-455a-4532-98b8-19e2cee51160",
- "tempQuoteId": "string",
- "quoteId": "string",
- "cliente": {
- "cnpj": "string",
- "razaoSocial": "string",
- "nomeFantasia": "string"
}, - "vendedor": {
- "cpf": "string",
- "email": "string"
}, - "tenant": {
- "companyId": "string",
- "locationId": "string"
}, - "item": {
- "productCode": "string",
- "ean": "string",
- "name": "string",
- "quantity": 0,
- "unitPrice": 0,
- "coinsReward": 0,
- "source": "string"
}, - "timestamp": "2019-08-24T14:15:22Z"
}