Integração com o SAP via Dispatcher — guia da aplicação cliente
Este documento é para quem consome o SAP a partir de uma aplicação (ERP, portal, integração). Ele descreve o que muda ao fazer a requisição através do dispatcher em vez de bater direto no SAP Business One Service Layer.
Em uma frase: você troca a URL e a forma de autenticar; o resto do OData continua igual.
1. Por que existe o dispatcher
A empresa que hospeda o SAP protege tudo por firewall e demora para liberar IPs. Em vez de liberar o IP de cada aplicação, liberamos um único IP — o do dispatcher — e todas as aplicações passam por ele. O dispatcher:
- guarda o usuário técnico do SAP (ninguém mais precisa da senha do SAP);
- dá a cada aplicação uma chave própria, com permissões próprias;
- registra todas as requisições (auditoria);
- reaproveita a sessão do SAP (login/
ROUTEID/timeout são problema dele).
2. O que MUDA
2.1. A URL base
| Direto no SAP | Via dispatcher | |
|---|---|---|
| Base | https://sl01-dcs.datacore.com.br:24131/b1s/v1 |
https://dispatcher.nixen.com.br/v1/sap |
| Exemplo | .../b1s/v1/Orders |
.../v1/sap/Orders |
Tudo que vinha depois de /b1s/v1/ vem, igual, depois de /v1/sap/. O
caminho do recurso, a query OData ($filter, $select, $top, $orderby,
$expand…) — tudo idêntico.
2.2. Autenticação — este é o ponto que mais muda
Direto no SAP você faria POST /Login com CompanyDB, UserName e
Password, guardaria os cookies B1SESSION/ROUTEID, os reenviaria em toda
chamada e trataria a expiração da sessão (código -2028).
Via dispatcher, nada disso. Você não faz Login, não tem cookie de
sessão, não conhece CompanyDB/usuário/senha do SAP. Você só manda a sua
chave de API no cabeçalho:
Authorization: Bearer sapd_<id>_<segredo>
O dispatcher cuida do Login, do ROUTEID, do timeout de 30 min e do re-login
transparente. Para a sua aplicação, a chamada é stateless: manda a chave,
recebe a resposta.
2.3. O que você PODE fazer é limitado pela sua chave (allowlist)
A sua chave só pode acessar as rotas que foram liberadas explicitamente para ela (método + caminho). Qualquer outra coisa recebe 403, sem tocar o SAP. É deny-by-default: o que não foi liberado, é negado.
Para liberar uma rota nova (outra entidade, ou escrita além de leitura), peça no backoffice de credenciais — não é algo que a aplicação faz sozinha.
2.4. Cabeçalhos
- Enviados por você e repassados ao SAP:
Content-Type,Accept,Prefer(ex.:Prefer: odata.maxpagesize=20),If-Match/If-None-Match(ETag), e osB1S-*do Service Layer. - Ignorados (não vão ao SAP):
Cookie,Authorization(a sua chave para daqui, não segue adiante),Host, e cabeçalhos de conexão. Mandar umCookie: B1SESSION=...não adianta — é descartado. - Na resposta, o dispatcher devolve o corpo do SAP e um conjunto seguro de
cabeçalhos (
Content-Type,OData-Version,ETag,Location…). OSet-Cookiedo SAP nunca é repassado, e a resposta vem comCache-Control: no-store(é dado autenticado, não pode ser cacheado).
2.5. Erros — dois formatos
Erros do dispatcher (antes de chegar ao SAP) vêm num formato próprio:
{ "error": { "code": "forbidden", "message": "...", "trace_id": "..." } }HTTP code quando 400 invalid_requestcaminho/método inválido, corpo grande demais 401 unauthenticatedchave ausente, malformada, revogada ou expirada 403 forbiddenrota fora da allowlist da sua chave 429 rate_limitedexcedeu o limite por minuto (veja Retry-After)502 upstream_error/upstream_unavailableo SAP recusou ou está fora 503 audit_unavailableo dispatcher não conseguiu auditar (fail-closed) O
trace_idtambém vem no cabeçalhoX-Trace-Id. Cite-o ao abrir um chamado — é ele que localiza a requisição na trilha de auditoria.Erros de negócio do SAP (ex.: validação de um documento) são repassados como vieram — o corpo OData do B1 e o status correspondente. Ou seja: 4xx com
{"error":{"code":..., "message":{...}}}do próprio SAP passa direto.
2.6. Limite de requisições
Cada chave tem um teto por minuto. Ao estourar, você recebe 429 com o
cabeçalho Retry-After (segundos). É por chave — uma aplicação não afeta a
outra.
3. O que NÃO muda
- A sintaxe OData:
$filter,$select,$top,$skip,$orderby,$expand,$count,$inlinecount, paginação comPrefer: odata.maxpagesize=Ne o@odata.nextLink. - Os corpos de resposta: o JSON que o SAP devolve chega intacto.
- ETags e concorrência otimista:
ETagna resposta,If-Matchna atualização — funcionam igual (para as rotas de escrita que a sua chave tiver). - Os nomes e o comportamento das entidades/ações do Service Layer.
Regra prática: se funciona no Service Layer, funciona igual via dispatcher — contanto que a rota esteja na allowlist da sua chave.
4. Exemplos
Suponha o dispatcher em https://dispatcher.nixen.com.br e a sua chave em $KEY.
4.1. Ler pedidos (GET com query OData)
curl -H "Authorization: Bearer $KEY" \
"https://dispatcher.nixen.com.br/v1/sap/Orders?\$top=5&\$select=DocEntry,DocNum,CardCode,DocDate&\$orderby=DocEntry desc"
Resposta (corpo do próprio SAP):
{
"odata.metadata": ".../$metadata#Orders",
"value": [
{ "odata.etag": "W/\"...\"", "DocEntry": 94581, "DocNum": 35893, "CardCode": "FL00057", "DocDate": "2024-03-25T00:00:00Z" }
]
}
4.2. Um parceiro de negócio específico
curl -H "Authorization: Bearer $KEY" \
"https://dispatcher.nixen.com.br/v1/sap/BusinessPartners('FL00057')?\$select=CardCode,CardName"
4.3. Filtro OData
curl -H "Authorization: Bearer $KEY" \
"https://dispatcher.nixen.com.br/v1/sap/Orders?\$filter=DocDate ge '2024-01-01'&\$top=10"
4.4. O que dá errado (esperado)
# rota não liberada para a sua chave:
curl -H "Authorization: Bearer $KEY" "https://dispatcher.nixen.com.br/v1/sap/EmployeesInfo"
# -> 403 {"error":{"code":"forbidden",...}}
# sem a chave:
curl "https://dispatcher.nixen.com.br/v1/sap/Orders"
# -> 401 {"error":{"code":"unauthenticated",...}}
5. Checklist para portar uma integração existente
- Troque a base
.../b1s/v1por.../v1/sap. - Remova o fluxo de
Login/Logoute o gerenciamento de cookiesB1SESSION/ROUTEID— o dispatcher faz isso. - Remova
CompanyDB/usuário/senha do SAP do seu código. - Passe a mandar
Authorization: Bearer <sua-chave>em toda requisição. - Trate os códigos do dispatcher (401/403/429/502/503) além dos erros do SAP.
- Confirme que todas as rotas que a sua integração usa estão liberadas na allowlist da sua chave (senão: 403). Peça a liberação do que faltar.
- Guarde a chave como segredo (variável de ambiente / cofre) — ela é o acesso ao ERP. Nunca no código-fonte, nunca no navegador.
7. Catálogo de operações do SAP (referência completa)
Tudo que o SAP Business One Service Layer expõe — 197 serviços, 674 rotas
(entidades, ações, campos, exemplos) — está na referência oficial, adaptada
para o dispatcher: os exemplos já vêm com a URL trocada para
https://dispatcher.nixen.com.br/v1/sap, e o topo lembra que a autenticação é
por chave e que a allowlist se aplica.
➡ Referência completa: https://docs-dispatcher.nixen.com.br/sap-reference.html
Use-a para descobrir o que existe (Orders, BusinessPartners, Items,
Invoices, Quotations, ações como Cancel, Close…) e como montar cada
chamada. Lembre: só as rotas liberadas na sua chave respondem — o resto é 403.
6. Segurança da chave
- A chave é mostrada uma única vez na emissão. Não é recuperável — se perder, emite-se outra e revoga-se a antiga.
- Trate-a como senha: variável de ambiente ou cofre de segredos, nunca commitada e nunca exposta no cliente (browser/app mobile).
- Toda requisição feita com ela é auditada (quem, quando, o quê, resultado).
- Se vazar, revogue no backoffice — o corte é imediato.