Esta documentação orienta fornecedores de software TMS (Transportation Management System) sobre como integrar seus sistemas ao Vendelo, permitindo cotação automática de frete e gestão completa do processo de despacho por meio de APIs REST padronizadas.
Índice
Introdução à Integração TMS
A integração entre o Vendelo e sistemas TMS externos permite que transportadoras e fornecedores de software logístico ofereçam cotações automáticas de frete e gerenciem todo o ciclo de despacho diretamente na plataforma Vendelo. O processo começa quando um operador solicita opções de frete para um pedido e pode evoluir até a geração de etiquetas e rastreamento.
Público-alvo: este guia é destinado especificamente a integradores e fornecedores de software TMS que desejam conectar seus sistemas ao Vendelo para ofertar serviços de frete integrados.
A integração opera em dois níveis:
- Nível 1: cotação de frete.
- Nível 2: cotação + despacho completo (registro, geração de etiqueta, acompanhamento e cancelamento).
Exemplo – Mock de Referência
Para facilitar o desenvolvimento e os testes, disponibilizamos um projeto de referência que simula um fornecedor TMS externo. Este exemplo implementa os endpoints necessários e demonstra boas práticas de integração.
Repositório GitHub: https://github.com/alcgithub/Vendelo.FakeShippingProvider
O projeto de referência (C#/.NET 6) inclui:
- Endpoints: cotação, cart, geração de etiqueta, cancelamento e consulta.
- Autenticação flexível: token estático e OAuth 2.0.
- Validação de payload: CEPs, produtos e campos obrigatórios.
- Rotas de debug: apoio para testes locais.
- Collection Postman: cenários completos com scripts de validação.
Serviços fake simulados
O mock retorna quatro serviços de frete no endpoint de cotação:
| ID | Nome do Serviço | Transportadora | Características |
|---|---|---|---|
1 |
SEDEX (Correios) | Correios | Serviço expresso com prazo reduzido |
2 |
PAC (Correios) | Correios | Serviço econômico com prazo estendido |
3 |
Jadlog Package | Jadlog | Serviço de transportadora privada |
4 |
ChinaLog | ChinaLog | Serviço internacional simulado |
Mecânica de Seleção do Vendelo
O Vendelo utiliza regras de frete para determinar quando e como chamar fornecedores TMS externos.
Processo de seleção automática
- Identifica a filial do pedido e busca regras ativas do tipo
PER_WEIGHT_FROM_EXTERNAL_SHIPPING_PROVIDER. - Aplica filtros de CEP, peso e valor conforme configurado na regra.
- Resolve a conta de integração (filial específica tem prioridade sobre filial padrão).
- Monta o request com dados de origem, destino, transportadora e produtos.
- Executa a chamada para
POST /api/v1/shipment/calculate. - Processa as opções retornadas e apresenta para seleção.
Seleção automática vs manual
- Seleção automática: aplica a melhor opção conforme configuração da regra.
- Seleção manual: operador escolhe entre as opções disponíveis.
Aplicação da despesa selecionada
Após a seleção, o Vendelo registra a opção escolhida como despesa adicional do documento e distribui o valor entre os itens conforme as regras internas.
Configuração da Conta de Integração
Para habilitar a integração com seu TMS, configure uma conta de integração no Vendelo com as credenciais e parâmetros de conexão.
| Campo | Obrigatório | Descrição |
|---|---|---|
| Host | Sim | URL base da API, sem barra final. Ex: https://api.seutms.com.br |
| Token | Condicional | Token Bearer fixo (quando não usar OAuth). |
| UserName | Condicional | client_id para OAuth 2.0. |
| Password | Condicional | client_secret para OAuth 2.0. |
| Tipo | Sim | Selecionar EXTERNAL_SHIPPING_PROVIDER. |
| Integration Tag | Opcional | Identificador para múltiplas contas do mesmo tipo. |
Resolução de conta por filial
- Filial específica: prioridade máxima.
- Filial padrão: fallback para filiais sem conta própria.
- Integration Tag: separa integrações distintas.
Ordem de resolução: filial do pedido → filial padrão. Se nenhuma conta válida for encontrada, a integração TMS não é executada.
Fluxo Operacional Completo
Cotação de frete (Nível 1 e 2)
- Operador abre as opções de frete do documento.
- Vendelo encontra regras ativas e conta de integração.
- Sistema monta request com origem, destino e itens.
- Executa
POST /api/v1/shipment/calculate. - Exibe opções de serviço para seleção.
- Aplica a opção escolhida como despesa no documento.
Registro do envio (Nível 2)
- Usuário acessa a tela de volumes.
- Vendelo envia
POST /api/v1/cart. - TMS retorna o ID do pedido externo.
- Vendelo salva o ID e marca o volume como registrado.
Geração de etiqueta
- Usuário confirma os volumes.
- Vendelo envia
POST /api/v1/shipment/generate. - TMS gera etiqueta e rastreio.
- Vendelo exibe links de etiqueta e rastreamento no documento.
Acompanhamento e rastreamento
Endpoints
Todos os endpoints devem seguir padrão REST com JSON.
Nível 1 – Cotação apenas
| Endpoint | Método | Obrigatório | Descrição |
|---|---|---|---|
| /api/v1/shipment/calculate | POST | Sim | Retorna opções de frete (preço e prazo). |
Nível 2 – Cotação + despacho completo
| Endpoint | Método | Obrigatório | Descrição |
|---|---|---|---|
| /api/v1/shipment/calculate | POST | Sim | Cotação |
| /api/v1/cart | POST | Sim | Registro do envio |
| /api/v1/shipment/generate | POST | Sim | Geração de etiqueta |
| /api/v1/cart/cancel | POST | Sim | Cancelamento |
| /api/v1/orders/{id} | GET | Sim | Status e rastreamento |
Regra de consistência: se implementar
/api/v1/cart, implemente também os demais endpoints do Nível 2.
Autenticação OAuth 2.0
Para credenciais com expiração, recomendamos OAuth 2.0 com refresh token.
Endpoint de renovação
| Endpoint | Método | Quando usado |
|---|---|---|
| /oauth/token | POST | Renovação automática antes do vencimento. |
Request de renovação
{
"grant_type": "refresh_token",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2...",
"client_id": "vendelo-client",
"client_secret": "vendelo-secret"
}
Response esperado
{
"token_type": "Bearer",
"access_token": "eyJhbGciOiJSUzI1NiJ9...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2...",
"expires_in": 2592000
}
Renovação automática: o Vendelo renova tokens próximos do vencimento antes das operações.
Estrutura de Dados
Tabela de Incoterms (PT-BR)
O campo incoterms deve ser enviado conforme os valores esperados pela integração. Abaixo estão os itens e a descrição em português:
Valor em incoterms |
Descrição (PT-BR) | Responsabilidade principal pelo frete |
|---|---|---|
BY_SENDER |
Por conta do remetente | Remetente |
BY_RECIPIENT |
Por conta do destinatário | Destinatário |
THIRD_PARTY |
Por conta de terceiros | Terceiro pagador |
NO_FREIGHT |
Sem frete / retirada | Não se aplica |
Importante: valide o valor recebido em
incotermscomo enum/string controlada. Quando o valor não for reconhecido, retorne erro de validação em JSON (HTTP 422).
Cotação de Frete – Request
Exemplo JSON válido de request enviado pelo Vendelo:
{
"from": {
"postal_code": "01310100",
"erp_id": "F001",
"company_document": "12345678000199",
"state_register": "123456789"
},
"to": {
"postal_code": "30130010",
"erp_id": "C00042",
"document": "98765432100",
"company_document": "98765432000188",
"state_register": "987654321"
},
"incoterms": "BY_SENDER",
"carrier": {
"id": "vendelo-carrier-id",
"erp_id": "TMS_CAR_001"
},
"products": [
{
"id": "item-uuid-vendelo",
"erp_id": "A00001",
"name": "Produto Exemplo",
"width": 15,
"height": 10,
"length": 20,
"weight": 0.5,
"quantity": 2,
"unit_price": 149.9,
"discount_total": 15.0,
"insurance_value": 284.8,
"available_stock": 25,
"user_fields": [
{ "name": "U_VDO_CODIGO_EXTRA", "value": "7101" },
{ "name": "U_VDO_ORIGEM", "value": "Importado" }
]
}
],
"user_fields": [
{ "name": "U_XXX_REDESPACHO", "value": "Y" },
{ "name": "U_XXX_FONTE", "value": "Indicacao" }
]
}
Cotação de Frete – Response
[
{
"id": "1",
"name": "Expresso",
"custom_price": 28.9,
"custom_delivery_time": 2,
"carrier": {
"erp_id": "V10000"
},
"company": {
"id": "1",
"name": "Nome da Transportadora",
"picture": "https://cdn.seusite.com.br/logo.png"
},
"user_fields": [
{ "name": "U_XXX_REDESPACHO", "value": "N" },
{ "name": "U_XXX_FONTE", "value": "TMS" }
],
"packages": [
{
"format": "box",
"weight": 1.0,
"price": 28.9,
"insurance_value": 284.8,
"dimensions": {
"width": 15,
"height": 10,
"length": 20
},
"products": [
{
"id": "item-uuid-vendelo",
"quantity": 2,
"user_fields": [
{ "name": "U_VDO_CODIGO_EXTRA", "value": "7202" },
{ "name": "U_VDO_ORIGEM", "value": "Nacional" }
]
}
]
}
],
"error": null
}
]
Campos opcionais de substituição no response
O response de cotação aceita dois campos opcionais que, quando presentes, instruem o Vendelo a realizar substituições no documento assim que o operador confirmar a opção de frete.
carrier — Substituição de transportadora
Retorne o bloco carrier quando quiser trocar a transportadora do documento pela transportadora identificada pelo erp_id informado. Se não quiser alterar a transportadora, omita o bloco inteiramente.
| Situação no response | Comportamento no Vendelo |
|---|---|
carrier.erp_id presente |
O Vendelo localiza a transportadora pelo erp_id e substitui a transportadora atual do documento no momento da seleção. |
Bloco carrier ausente |
A transportadora do documento permanece inalterada. |
Nunca retorne
"carrier": nullnem"erp_id": null. Não enviecarrier.idno response — o ID interno é resolvido pelo Vendelo a partir doerp_id.
user_fields — Substituição de campos de usuário
Retorne user_fields quando quiser atualizar campos de usuário no documento ou nos itens. Os campos podem ser informados em dois níveis:
| Nível | Campo no response | Comportamento no Vendelo ao selecionar a opção |
|---|---|---|
| Documento | user_fields na raiz da opção de frete |
Para cada campo retornado, localiza o campo de mesmo name no documento e sobrescreve o valor. Se ainda não existir, cria o campo com o valor informado. |
| Item | packages[].products[].user_fields |
Aplica a mesma lógica de substituição ou criação no item identificado pelo id retornado. |
Omita
user_fieldsquando não houver valor a atualizar — não envie arrays vazios. Campos de usuário no nível do volume/pacote são ignorados.
Cada campo deve conter:
| Campo | Descrição |
|---|---|
name |
Nome técnico do campo de usuário cadastrado no Vendelo/ERP, por exemplo U_XXX_FONTE. |
value |
Novo valor a ser aplicado. Sobrescreve o valor atual se o campo já existir. |
Tratamento de Erros
Implemente tratamento consistente de erros com códigos HTTP apropriados:
| Código HTTP | Significado | Comportamento do Vendelo |
|---|---|---|
| 200 | Sucesso | Processa resposta normalmente |
| 400 | Payload inválido | Exibe mensagem ao operador |
| 401 | Não autorizado | Tenta renovar token e repetir |
| 422 | Falha de validação | Exibe erros por campo |
| 429 | Rate limit | Retenta com backoff |
| 5xx | Erro interno | Registra log e exibe mensagem genérica |
Estrutura de erro padrão
{
"error": "CEP de destino invalido.",
"errors": {
"to.postal_code": ["O CEP informado nao foi encontrado."]
}
}
Importante: não retorne HTML em erros. O Vendelo espera JSON em todos os cenários.
Perguntas Frequentes
Posso implementar apenas cotação sem despacho?
Sim. No Nível 1, apenas /api/v1/shipment/calculate é obrigatório.
Como funciona a resolução de conta por filial?
O Vendelo busca primeiro a conta da filial do documento. Se não existir, usa a conta da filial padrão.
Os campos carrier são enviados na cotação?
No request, o Vendelo envia carrier.id e carrier.erp_id para identificar a transportadora atual do documento. No response, o TMS deve retornar apenas carrier.erp_id — e somente quando quiser substituir a transportadora do documento por outra. Se o bloco carrier for omitido, a transportadora do documento permanece inalterada.
O TMS pode devolver campos de usuário na cotação?
Sim. O response de /api/v1/shipment/calculate pode retornar user_fields no nível da opção de frete (para atualizar campos do documento) e em packages[].products[] (para atualizar campos de itens). Esses campos funcionam como uma instrução de substituição: ao selecionar a opção, o Vendelo aplica os valores retornados. O campo é opcional e deve ser omitido quando não houver nenhum valor a atualizar.
O retorno de user_fields altera campos já preenchidos?
Sim. Ao selecionar a opção de frete, o Vendelo aplica os campos retornados pelo TMS. Para cada campo, o Vendelo localiza no documento ou no item o campo de usuário com o mesmo name e sobrescreve o valor atual. Se o campo ainda não existir, ele é criado com o valor informado. A operação é sempre uma substituição completa — não há mesclagem parcial de valores.
Como faço para substituir a transportadora do documento via response?
Retorne o bloco carrier com o campo erp_id preenchido com o código da nova transportadora. O Vendelo localizará a transportadora correspondente e substituirá a transportadora atual do documento no momento em que o operador selecionar a opção de frete. Se não quiser alterar a transportadora, omita o bloco carrier por completo — nunca retorne "carrier": null nem "erp_id": null.
O que é available_stock no produto?
É o estoque disponível por item no momento da cotação, carregado do ERP e enviado em products[].available_stock.
Como funciona a renovação automática de OAuth?
O Vendelo renova o token via refresh token quando necessário, sem intervenção manual.
Posso usar credenciais diferentes por filial?
Sim. Configure contas separadas por filial e, se necessário, diferencie por Integration Tag.
Como testar durante o desenvolvimento?
Use o mock de referência e a collection Postman para validar cotação e despacho de ponta a ponta.