Módulo Loggi
Integração de cotação de frete, criação de envio/etiqueta e rastreio. Cotação e etiquetas Loggi na API. Declaração de conteúdo: usar
store.freight.content_declaration(Loja, compartilhada) — não gerar conteúdo aleatório. Docs oficiais: API Loggi.
Ativação
Seção intitulada “Ativação”| Flag | Origem |
|---|---|
modules.loggi.enabled |
Admin (system_configs) |
modules.loggi.use_for_quote |
default false |
modules.loggi.use_for_label |
default false |
Desabilitado → 503 MODULE_DISABLED em todas as rotas abaixo.
Prefixo
Seção intitulada “Prefixo”/api/v1/modules/loggiCredenciais
Seção intitulada “Credenciais”Ver credentials. Campos: client_id, client_secret, company_id, opcional api_base_url, token_url.
Auth oficial: OAuth 2.0 client credentials → POST https://api.loggi.com/v2/oauth2/token (credenciais via config/env, nunca hardcoded).
Cascata: system_api_credentials → env LOGGI_*.
Infos compartilhadas (admin Loja)
Seção intitulada “Infos compartilhadas (admin Loja)”Declaração de conteúdo não é por módulo. Todos os providers leem:
| Key | Shape |
|---|---|
store.freight.content_declaration |
{ "description": string, "total_value": number } |
- Configurável em Loja → Frete
- Usada na cotação (
goodsValue) e no create-label (contentDeclaration) - Proibido gerar descrição/valor aleatórios (integrações específicas de associação)
Sem description + total_value > 0 → CONFIG_INCOMPLETE em create-label.
Modalidades de entrega (tipos de serviço)
Seção intitulada “Modalidades de entrega (tipos de serviço)”A Loggi não oferece um endpoint de catálogo do tipo “listar serviços”. As modalidades vêm da própria cotação:
Upstream: POST /v1/companies/{company_id}/quotations
Ref: Criar Cotação.
Para cada pacote, packagesQuotations[].quotations[] pode retornar até duas opções, tipicamente:
freightType |
freightTypeLabel (exemplo) |
|---|---|
FREIGHT_TYPE_ECONOMIC |
Loggi Econômico |
FREIGHT_TYPE_EXPRESS |
Loggi Expresso |
Também retornam externalServiceId (SISU), preço e prazo. Os SISUs oficiais da conta são informados pelo Sales Engineering da Loggi na homologação; podem ser configurados no admin (store.freight.loggi.external_service_ids) e enviados no body da cotação (externalServiceIds). Não misturar externalServiceIds com pickupTypes na mesma request (regra oficial).
No carrinho, o operador escolhe entre as modalidades retornadas (ex.: Econômico vs Expresso), não apenas “Loggi” genérico.
No admin, a favorita pode ser Loggi > econômico (ver store.freight.default_option em fields).
GET /service-options
Seção intitulada “GET /service-options”Lista as modalidades conhecidas / configuráveis para a UI de favoritos do admin (sem cotação de CEP).
Como não há catálogo upstream, a resposta é derivada de:
- Enum oficial
FREIGHT_TYPE_ECONOMIC/FREIGHT_TYPE_EXPRESS - SISUs configurados em
store.freight.loggi.external_service_ids(se houver) - (Opcional) última cotação de teste bem-sucedida, se quiser enriquecer labels
{ "data": { "provider": "loggi", "options": [ { "option_key": "loggi:FREIGHT_TYPE_ECONOMIC", "freight_type": "FREIGHT_TYPE_ECONOMIC", "label": "Loggi Econômico", "external_service_id": null }, { "option_key": "loggi:FREIGHT_TYPE_EXPRESS", "freight_type": "FREIGHT_TYPE_EXPRESS", "label": "Loggi Expresso", "external_service_id": null } ] }}POST /quote-freight
Seção intitulada “POST /quote-freight”Cotação para o endereço de entrega do associado. Deve devolver todas as modalidades, não só a mais barata.
Upstream Loggi: POST /v1/companies/{company_id}/quotations
Ref: Criar Cotação.
Request:
{ "address": { "street": "Rua Exemplo", "number": "100", "neighborhood": "Centro", "complement": "", "city": "Goiânia", "state": "GO", "cep": "74000000" }}Response 200:
{ "data": { "options": [ { "option_key": "loggi:FREIGHT_TYPE_ECONOMIC", "provider": "loggi", "company": "Loggi", "service_label": "Loggi Econômico", "freight_type": "FREIGHT_TYPE_ECONOMIC", "external_service_id": "DLVR-DROF-DOOR-STAN-01", "price": 18.5, "eta_days": 5 }, { "option_key": "loggi:FREIGHT_TYPE_EXPRESS", "provider": "loggi", "company": "Loggi", "service_label": "Loggi Expresso", "freight_type": "FREIGHT_TYPE_EXPRESS", "external_service_id": "DLVR-DROF-DOOR-STAN-01", "price": 22.9, "eta_days": 3 } ], "cheapest": { "option_key": "loggi:FREIGHT_TYPE_ECONOMIC", "price": 18.5 } }}Compatibilidade: respostas antigas devolviam um único price/serviceLabel. O usa options[]; o front escolhe a linha (favorita admin ou operador).
Regras:
- Origem =
store.ship_from(admin Loja) — nunca endereço fixo no código - Pacote =
store.freight.package(obrigatório no admin; sem peso/dims default no código) goodsValue=store.freight.content_declaration.total_value- Enviar
externalServiceIdsconfigurados, se existirem - Listar todas as
quotationsdo pacote - CEP inválido → “verifique o CEP”
- Sem
ship_fromoupackageválidos →CONFIG_INCOMPLETE - Retry transitório (3x), exceto 4xx ≠ 429
Requer use_for_quote=true.
POST /create-label
Seção intitulada “POST /create-label”Cria envio assíncrono na Loggi e associa ao pedido. Dimensões: store.freight.label_package ?? store.freight.package.
Upstream: POST /v1/companies/{company_id}/async-shipments
Ref: Create async shipment — freightType: FREIGHT_TYPE_ECONOMIC | FREIGHT_TYPE_EXPRESS.
Request: corpo do pedido (ou { orderId }) + modalidade escolhida:
{ "orderId": 123, "freight_type": "FREIGHT_TYPE_ECONOMIC", "external_service_id": "DLVR-DROF-DOOR-STAN-01"}Se omitido, usar orders.freight_option persistido no checkout ou o default da loja.
Declaração de conteúdo: ler store.freight.content_declaration (preenchida no admin) e enviar no formato Loggi. Números/textos nos exemplos desta doc são ilustrativos — não são defaults do sistema.
{ "documentTypes": [ { "contentDeclaration": { "totalValue": "30.00", "description": "Produto de aromaterapia" } } ]}Response: payload Loggi + echo da declaração usada; server grava tracking_code, tracking_code_date, status, e snapshot em dce.loggiDeclaration (cópia da config no momento do envio, para auditoria).
Requer use_for_label=true e declaração configurada.
Elegibilidade (histórico getLoggiLabelEligibility): não aguardando pagamento, sem tracking, endereço completo.
POST /cancel
Seção intitulada “POST /cancel”Request: { "orderId": 1, "tracking_code": "…" }
Upstream: cancel package Loggi; limpa tracking_code no order; status → Pagamento concluído .
POST /packages
Seção intitulada “POST /packages”Request: { "trackingCode": "…" }
Merge details + tracking; response { packages: [merged], trackingPartial }.
POST /test
Seção intitulada “POST /test”Valida credenciais sem efeito colateral de pedido.
Passos sugeridos:
- Obter access token OAuth
- (Opcional) cotação para CEP de
store.ship_fromou CEP fixo de sandbox
Response:
{ "data": { "ok": true, "checks": [ { "name": "oauth_token", "ok": true }, { "name": "quotation", "ok": true, "price": 19.9 } ] }}Atualiza last_tested_at / last_test_ok nas rows do serviço.
GET /status
Seção intitulada “GET /status”{ "data": { "enabled": true, "use_for_quote": true, "use_for_label": true, "credentials_complete": true, "credentials_source": "db", "last_test_ok": true }}Notas de comportamento
Seção intitulada “Notas de comportamento”| Comportamento | Detalhe |
|---|---|
| client_id/secret | credentials / env |
| Origem do frete | store.ship_from no admin Loja |
| Dimensões/peso | Só store.freight.package + store.ship_from no admin (sem fallback numérico) |
| Declaração de conteúdo | store.freight.content_declaration (compartilhada) |
| Valor declarado | store.freight.content_declaration.total_value |
| Cotações no carrinho | Devolver options[] (Econômico + Expresso) |
| Catálogo de serviços | GET /service-options a partir do enum + SISUs config |
