Let's Go DeliveryLet's Go Developers · API Open Delivery — Logística

Let's Go Delivery — API Open Delivery (Logística)

Versão do padrão: Open Delivery v1.7.1 · Papel do Let's Go: operador logístico (Logistics Service)


1. Introdução

O Let's Go Delivery recebe pedidos de entrega do seu sistema pelo padrão Open Delivery, despacha um entregador (moto) e devolve o andamento por webhook.

Fluxo resumido:

  1. Seu sistema obtém um token (/oauth/token) com as credenciais da loja.
  2. Seu sistema cria a entrega (/v1/logistics/delivery).
  3. O Let's Go despacha o entregador e envia cada mudança de status para o seu webhook.
  4. Seu sistema pode consultar os detalhes a qualquer momento e cancelar antes da coleta.
  5. A cobrança das entregas é semanal, por fatura.

Nesta documentação, <client_id>, <client_secret>, <access_token> e <seu MerchantId> são marcadores: troque pelos valores reais.


2. Trocar informações com o estabelecimento

2.1 O que o Let's Go entrega a você

InformaçãoComo é entregue
URL base e AppId do Let's Gonesta documentação (seção 3)
client_id da lojapor um canal (ex.: e-mail)
client_secret da lojapor outro canal, separado (ex.: gerenciador de senhas com link de uso único)

2.2 O que você entrega ao Let's Go

InformaçãoUso
URL do seu webhook (https://…)onde enviamos os eventos de status
Seu MerchantId (identificador da loja no seu sistema)vai no cabeçalho X-App-MerchantId e em merchant.id
Seu AppIdidentificação do seu sistema
Contato técnicosuporte durante a integração

2.3 Modo teste e liberação para produção


3. URL base e APP-ID

ItemValor
URL basehttps://astbkmpegcmqljltmdpx.supabase.co/functions/v1/open-delivery
APP-ID do Let's Go070b173c-70f5-4dc6-910f-6f962ec419e4

A mesma URL atende teste e produção; o que muda é a credencial.


4. Autenticação

**POST {URL_BASE}/oauth/token**

Requisição:

texto
POST /functions/v1/open-delivery/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>

Resposta 200:

json
{ "access_token": "<access_token>", "token_type": "bearer", "expires_in": 3600 }

Regras:

Erros: 401 invalid_request (corpo não é form-urlencoded), 401 unsupported_grant_type, 401 invalid_client, 429 too_many_requests, 503 service_unavailable.


5. Criar entrega

**POST {URL_BASE}/v1/logistics/delivery**

5.1 Campos lidos pelo Let's Go

CampoObrigatórioObservação
orderIdsimidentificador do pedido no seu sistema; chave de idempotência por loja (até 100 caracteres)
orderDisplayIdsimnúmero exibido ao entregador e no painel (até 50 caracteres)
customerNamesimnome do cliente
customerPhonenãotelefone do cliente
deliveryAddresssimver Address; **latitude e longitude obrigatórias**
vehiclesimver Vehicle; type deve conter MOTORBIKE_BAG ou MOTORBIKE_BOX
returnToMerchantnãoprecisa ser false (ou ausente)
payments.methodnãoONLINE (padrão). OFFLINE não é aceito
specialInstructionsnãoinstruções para o entregador (até 500 caracteres)

Outros campos da especificação podem ser enviados, mas são ignorados nesta versão. O endereço de coleta é sempre o endereço da loja cadastrado no Let's Go.

5.2 Exemplo de requisição

json
{
  "orderId": "PEDIDO-12345",
  "orderDisplayId": "1234",
  "customerName": "Maria Silva",
  "customerPhone": "16999990000",
  "deliveryAddress": {
    "country": "BR",
    "state": "SP",
    "city": "Ribeirão Preto",
    "district": "Centro",
    "street": "Rua Exemplo",
    "number": "100",
    "postalCode": "14000000",
    "complement": "Ap 12",
    "latitude": -21.1775,
    "longitude": -47.8103
  },
  "vehicle": { "type": ["MOTORBIKE_BAG"], "container": "NORMAL" },
  "returnToMerchant": false,
  "payments": { "method": "ONLINE" },
  "specialInstructions": "Interfone 12"
}

5.3 Resposta 202

json
{
  "deliveryId": "3f1c2a9e-0000-4000-8000-000000000000",
  "event": "ACCEPTED",
  "completion": { "estimate": "2026-10-06T18:40:00Z" }
}

5.4 Regras e limites


6. Cancelar entrega

**POST {URL_BASE}/v1/logistics/cancel/{orderId}**

Requisição:

json
{
  "reason": "CONSUMER_CANCELLATION_REQUESTED",
  "action": "CANCEL_DELIVERY",
  "message": "Cliente desistiu"
}
CampoObrigatórioValores
reasonsimCONSUMER_CANCELLATION_REQUESTED, NO_SHOW, PROBLEM_AT_MERCHANT, HIGH_ACCEPTANCE_TIME, INCORRECT_ORDER_OR_PRODUCT_PICKUP, PROBLEM_RESOLUTION, DISCOMBINE_ORDER, OTHER
actionnãoregistrado; não altera o comportamento nesta versão
messagenãoregistrado (até 300 caracteres)

Resposta 202:

json
{ "additionalCharges": false }

Regras:

Situação da entregaResultado
Ainda não coletada (aceita, entregador a caminho ou na loja)cancela; 202, sem taxa
Já cancelada202 (idempotente)
Já coletada / a caminho do cliente422 cannot_cancel_after_pickup
Concluída422 already_delivered
reason fora da lista400 invalid_reason
Entrega inexistente ou de outra loja404 not_found

Após o cancelamento, o evento CANCELLED é enviado ao seu webhook.


7. Detalhes da entrega

**GET {URL_BASE}/v1/logistics/delivery/{orderId}**

Resposta 200:

json
{
  "deliveryId": "3f1c2a9e-0000-4000-8000-000000000000",
  "orderId": "PEDIDO-12345",
  "orderDisplayId": "1234",
  "merchant": { "id": "<seu MerchantId>", "name": "Nome da Loja" },
  "customerName": "Maria Silva",
  "customerPhone": "16999990000",
  "events": [
    { "type": "ACCEPTED", "datetime": "2026-10-06T18:00:00Z" },
    { "type": "PICKUP_ONGOING", "datetime": "2026-10-06T18:03:00Z" },
    { "type": "ARRIVED_AT_MERCHANT", "datetime": "2026-10-06T18:12:00Z" }
  ],
  "vehicle": { "type": ["MOTORBIKE_BAG"], "container": "NORMAL" },
  "deliveryPrice": {
    "price": { "value": 15.10, "currency": "BRL" },
    "pricingList": "DYNAMIC",
    "additionalPricePercentual": 24.79
  },
  "deliveryPerson": { "id": "…", "name": "Nome do Entregador", "phone": "16…" }
}

8. Webhook de status

8.1 Envio

Enviamos um POST para a URL que você cadastrou a cada mudança de status.

Requisitos da URL: **https, porta 443, domínio público** (não aceitamos IP, localhost nem nomes internos).

8.2 Headers

texto
Content-Type: application/json
User-Agent: LetsGo-OpenDelivery/1.0
X-App-Id: 070b173c-70f5-4dc6-910f-6f962ec419e4
X-App-MerchantId: <seu MerchantId>
X-App-Signature: <assinatura HMAC>

8.3 Corpo

json
{
  "deliveryId": "3f1c2a9e-0000-4000-8000-000000000000",
  "orderId": "PEDIDO-12345",
  "orderDisplayId": "1234",
  "merchant": { "id": "<seu MerchantId>", "name": "Nome da Loja" },
  "event": { "type": "PICKUP_ONGOING", "datetime": "2026-10-06T18:03:00Z" },
  "customerName": "Maria Silva",
  "vehicle": { "type": ["MOTORBIKE_BAG"], "container": "NORMAL" },
  "deliveryPrice": {
    "price": { "value": 15.10, "currency": "BRL" },
    "pricingList": "DYNAMIC",
    "additionalPricePercentual": 24.79
  },
  "deliveryPerson": { "id": "…", "name": "Nome do Entregador", "phone": "16…" }
}

deliveryPerson só aparece quando há entregador alocado.

8.4 Assinatura HMAC

Exemplo em Node.js (Express):

js
const crypto = require('crypto');
const express = require('express');
const app = express();

// guarde o corpo BRUTO; não valide sobre o JSON re-serializado
app.post('/deliveryEvent', express.raw({ type: 'application/json' }), (req, res) => {
  const recebida = String(req.get('X-App-Signature') || '');
  const esperada = crypto
    .createHmac('sha256', process.env.LETSGO_CLIENT_SECRET)
    .update(req.body)            // Buffer com o corpo bruto
    .digest('hex');              // hexadecimal minúsculo

  const ok = recebida.length === esperada.length &&
             crypto.timingSafeEqual(Buffer.from(recebida), Buffer.from(esperada));
  if (!ok) return res.status(401).end();

  const evento = JSON.parse(req.body.toString('utf8'));
  // trate a repetição por evento.deliveryId + evento.event.type
  res.status(204).end();
});

8.5 Resposta, novas tentativas e ordem

8.6 Eventos

event.typeQuando
ACCEPTEDentrega criada e aceita pelo Let's Go
PICKUP_ONGOINGentregador alocado, a caminho da loja
ARRIVED_AT_MERCHANTentregador chegou à loja
ORDER_PICKEDpedido coletado
DELIVERY_ONGOINGa caminho do cliente
ARRIVED_AT_CUSTOMERentregador chegou ao cliente
ORDER_DELIVEREDpedido entregue
DELIVERY_FINISHEDentrega encerrada
CANCELLEDentrega cancelada (pela API, pelo cliente ou pela nossa operação)

Depois de DELIVERY_FINISHED ou CANCELLED, nenhum outro evento é enviado.

8.7 Taxa de entrega


9. Schemas auxiliares

9.1 Address

CampoTipoObrigatórioObservação
streetstringrecomendadousado no endereço exibido ao entregador
numberstringrecomendado
complementstringnão
districtstringrecomendado
citystringrecomendado
statestringrecomendado
country, postalCode, referencestringnãoaceitos e ignorados
latitudenumbersimdentro do Brasil, diferente de 0
longitudenumbersimdentro do Brasil, diferente de 0

9.2 Vehicle

CampoTipoObservação
typearray de stringdeve conter MOTORBIKE_BAG ou MOTORBIKE_BOX; outros (CAR, BICYCLE, SCOOTER, VUC) são recusados
containerstringNORMAL ou THERMIC (informativo)

Nas respostas e webhooks, o Let's Go informa { "type": ["MOTORBIKE_BAG"], "container": "NORMAL" }.

9.3 Event

CampoTipoObservação
typestringver tabela da seção 8.6
datetimestring (ISO 8601, UTC)momento do evento

9.4 DeliveryPrice

CampoTipoObservação
price.valuenumbervalor congelado da entrega
price.currencystringsempre BRL
pricingListstringNORMAL (só tabela) ou DYNAMIC (com acréscimo dinâmico)
additionalPricePercentualnumberpercentual do acréscimo dinâmico sobre o valor de tabela; 0 se não houver

9.5 Merchant

CampoTipoObservação
idstringseu MerchantId (ou o identificador da loja no Let's Go)
namestringnome da loja no Let's Go

9.6 DeliveryPerson

CampoTipoObservação
idstringidentificador do entregador
namestringnome
phonestringtelefone

9.7 Error

json
{ "title": "<código>", "status": 422 }

10. Códigos de erro

HTTPtitleRotaQuando
400missing_required_fieldscriar entregafalta orderId, orderDisplayId, customerName, deliveryAddress ou vehicle
400invalid_jsoncriar / cancelarcorpo não é JSON válido
400invalid_content_typecriar entregaContent-Type diferente de application/json
400payload_too_largecriar / cancelarcorpo acima de 64 KB (criar) ou 8 KB (cancelar)
400invalid_reasoncancelarreason fora da lista
401invalid_request/oauth/tokencorpo não é form-urlencoded
401unsupported_grant_type/oauth/tokengrant_type diferente de client_credentials
401invalid_client/oauth/tokenclient_id/client_secret inválidos ou credencial revogada
401unauthorizeddemais rotastoken ausente, inválido, expirado ou revogado
403merchant_inactivecriar entregaloja inativa no Let's Go
404not_founddetalhes / cancelar / rota desconhecidaentrega inexistente ou de outra loja
422invalid_delivery_coordinatescriar entregacoordenada de entrega ausente, inválida, fora do Brasil ou 0,0
422vehicle_not_supportedcriar entregavehicle.type sem MOTORBIKE_BAG/MOTORBIKE_BOX
422return_to_merchant_not_supportedcriar entregareturnToMerchant: true
422offline_payment_not_supportedcriar entregapayments.method: OFFLINE
422distance_out_of_rangecriar entregamais de 32 km
422merchant_not_configuredcriar entregaloja sem endereço/coordenada cadastrados
422merchant_billing_not_supportedcriar entregaloja fora da modalidade de faturamento
422cannot_cancel_after_pickupcancelarpedido já coletado
422already_deliveredcancelarentrega concluída
429too_many_requests/oauth/tokenlimite de tokens ou bloqueio por tentativas com falha
429daily_limit_reachedcriar entregalimite de 300 entregas por dia
503route_unavailablecriar entregacálculo de rota indisponível; repita com o mesmo orderId
503service_unavailabletodasfalha temporária

11. Fora desta versão

Não estão disponíveis nesta versão:


12. Segurança e suporte