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 adiciona produtos à tela que o vendedor está
olhando (POST /api/erp/channel/{channelId}/product), até o ERP fechar
a cesta (POST /api/erp/channel/{channelId}/cesta).O caminho de volta — o Sipru avisando o ERP que um item entrou no
carrinho — está descrito em webhooks, e é implementado pelo parceiro.
POST /api/erp/cart/orcamento é a rota de fechamento usada pela tela do
Sipru, com a sessão do vendedor — não pelo ERP. Veja a nota de segurança
na própria operação.
Autenticação. Salvo o fechamento, 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 non-empty Identificação do vendedor no ERP. Envie pelo menos um
identificador — os mais comuns estão abaixo, mas qualquer outro
com que o ERP trabalhe também é aceito. É por eles que o Sipru
encontra a conta real do vendedor; se nenhum corresponder a uma
conta, a chamada falha com |
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": "temp-12345",
- "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"
}Canal por cotação em que o ERP adiciona produtos à tela do vendedor, do primeiro item ao fechamento da cesta.
Faz tudo o que /api/erp/sso/session faz e ainda cria um canal
identificado por channelId, com os endpoints para o ERP adicionar
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 non-empty Identificação do vendedor no ERP. Envie pelo menos um
identificador — os mais comuns estão abaixo, mas qualquer outro
com que o ERP trabalhe também é aceito. É por eles que o Sipru
encontra a conta real do vendedor; se nenhum corresponder a uma
conta, a chamada falha com |
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": "temp-12345",
- "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",
- "endpoints": {
}
}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 a cesta é fechada no ERP, o ERP registra no Sipru o que foi fechado, com os itens finais. Credencial de parceiro, como as demais rotas do canal.
Não é uma segunda gravação do pedido: os itens já chegaram ao ERP durante o atendimento. Refechar a cesta sobrescreve o registro anterior em vez de recusar, e o canal continua aberto depois do fechamento.
Campos além de items, no corpo ou em cada linha, são guardados como
vieram e nunca recusam o fechamento.
POST /api/erp/channel/{channelId}/orcamento é o nome antigo desta
rota, mantido por compatibilidade e com a mesma resposta. Integrações
novas usam /cesta.
| channelId required | string <uuid> O |
required | Array of objects [ 1 .. 200 ] items Os itens finais da cesta no ERP. |
| cestaId | string Identificador da cesta no ERP. |
| cestaCodigoExterno | string Código externo da cesta no ERP. |
| cestaAbertaEm | string <date-time> Quando a cesta foi aberta no ERP. |
| cestaFechadaEm | string <date-time> Quando a cesta foi fechada no ERP. |
| property name* additional property | any |
{- "items": [
- {
- "sku": "72411",
- "quantity": 4,
- "price": 34.9,
- "vendedor": {
- "cpf": "12345678909",
- "codigoExterno": "V042"
}
}
], - "cestaId": "CST-55120",
- "cestaCodigoExterno": "000123",
- "cestaAbertaEm": "2026-09-03T18:02:10-03:00",
- "cestaFechadaEm": "2026-09-03T18:22:40-03:00"
}{- "success": true,
- "id": "temp-12345:cesta",
- "documentType": "cesta",
- "tempQuoteId": "temp-12345",
- "quoteId": null,
- "itemCount": 3,
- "total": 78.73,
- "closedCount": 12,
- "createdAt": "2026-09-14T11:46:27.592Z",
- "updatedAt": "2026-10-13T21:44:22.335Z",
- "extra": {
- "cestaId": "7f11e004-0498-4892-8b34-096838fffeda",
- "cestaCodigoExterno": "PV-000126",
- "vendedorInicial": {
- "cpf": "31793058865"
}, - "clienteCpfCnpj": "01234567891025",
- "cestaAbertaEm": "2026-09-10T10:41:21.0695393+00:00",
- "cestaFechadaEm": "2026-09-14T20:56:21.0695393+00:00"
}
}Quando a venda é concluída no ERP, o ERP informa à Sipru com o número
do pedido (orderCode, o mesmo order_code das vendas que o ERP envia
para a Sipru). É o que confirma os Sipru Points do vendedor contra as
vendas do ERP.
Vale depois do atendimento: com o canal expirado ou encerrado, a venda é aceita se aquele canal já teve uma cesta fechada pelo mesmo parceiro. Chamar de novo sobrescreve a venda do atendimento.
Campos além de items e orderCode, no corpo ou em cada linha, são
guardados como vieram e nunca recusam a venda. Um orderCode fora do
formato é ignorado.
| channelId required | string <uuid> O |
required | Array of objects [ 1 .. 200 ] items Os itens finais da cesta no ERP. |
| cestaId | string Identificador da cesta no ERP. |
| cestaCodigoExterno | string Código externo da cesta no ERP. |
| cestaAbertaEm | string <date-time> Quando a cesta foi aberta no ERP. |
| cestaFechadaEm | string <date-time> Quando a cesta foi fechada no ERP. |
| orderCode | string <= 64 characters ^[A-Za-z0-9._\-/]{1,64}$ Número do pedido no ERP: o mesmo |
| property name* additional property | any |
{- "orderCode": "536215",
- "items": [
- {
- "sku": "72411",
- "quantity": 4,
- "price": 34.9
}
]
}{- "success": true,
- "id": "temp-12345:venda",
- "documentType": "venda",
- "tempQuoteId": "temp-12345",
- "quoteId": null,
- "itemCount": 1,
- "total": 139.6,
- "closedCount": 1,
- "createdAt": "2026-10-16T14:02:10.000Z",
- "updatedAt": "2026-10-16T14:02:10.000Z",
- "extra": {
- "orderCode": "536215"
}
}Registra no Sipru que o atendimento do canal virou cesta.
Não é uma rota de parceiro. Quem chama é a tela do Sipru, com a
sessão do vendedor dono do canal — sem Authorization: Bearer e sem
X-Sipru-Partner-Id. O ERP fecha a cesta por
POST /api/erp/channel/{channelId}/cesta.
O caminho guardou o nome antigo do documento (orcamento), que passou a
se chamar cesta em 11/09/2026: a rota é a mesma e o documentType
da resposta volta como cesta.
| channelId required | string O |
required | Array of objects (CartCloseItem) [ 1 .. 200 ] items Os itens do atendimento. Quem fecha é quem sabe o que foi montado na tela, por isso a lista vem no corpo. |
{- "channelId": "8f2b0f1c-4d3a-4d1e-9f77-2b1c9a5e7d10",
- "items": [
- {
- "sku": "72411",
- "quantity": 4,
- "price": 34.9
}
]
}{- "success": true,
- "id": "temp-12345:cesta",
- "documentType": "cesta",
- "tempQuoteId": "temp-12345",
- "quoteId": null,
- "itemCount": 3,
- "total": 78.73,
- "closedCount": 12,
- "createdAt": "2026-09-14T11:46:27.592Z",
- "updatedAt": "2026-10-13T21:44:22.335Z",
- "extra": {
- "cestaId": "7f11e004-0498-4892-8b34-096838fffeda",
- "cestaCodigoExterno": "PV-000126",
- "vendedorInicial": {
- "cpf": "31793058865"
}, - "clienteCpfCnpj": "01234567891025",
- "cestaAbertaEm": "2026-09-10T10:41:21.0695393+00:00",
- "cestaFechadaEm": "2026-09-14T20:56:21.0695393+00:00"
}
}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",
- "externalLogin": "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"
}