advanced
MDS
provider
JWT

Configuracao do MDS 2.0 Provider

Referencia completa para os endpoints MDS 2.0 Provider, assinatura JWT, discovery JWKS, paginacao por cursor e configuracao do validador.

Equipe Levy FleetsMay 18, 202618 min read

Configuracao do MDS 2.0 Provider

O Levy Fleets implementa a Mobility Data Specification (MDS) 2.0 Provider API de ponta a ponta. Todos os endpoints vivem sob /api/mds/[subaccountId]/provider/v2/... e sao assinados com JWTs RS256 cujas chaves publicas sao publicadas em .well-known/jwks.json por subconta.

Versao da spec

Fixamos em MDS 2.0.1. O campo version no envelope de resposta reporta 2.0.1 e o header Content-Type e application/vnd.mds+json;version=2.0. Cidades executando um mds-provider-validator contra essa base devem passar sem avisos de esquema.

Catalogo de endpoints

Todas as rotas tem prefixo /api/mds/{subaccountId}/provider/v2/. O subaccountId e o UUID da subconta do operador (uma por cidade para a maioria dos operadores).

EndpointMetodoPropositoPaginacaoCache
/vehiclesGETTodos os veiculos registrados na subcontanenhuma (pagina unica)60s edge
/vehicles/statusGETEstado atual por veiculo (uma linha cada)cursor60s edge
/vehicles/{device_id}GETDetalhe de veiculo unicon/anenhum
/tripsGETViagens terminando na janela ?end_timecursor por ended_atnenhum
/eventsGETEventos de mudanca de estado na janelacursor por event_timenenhum
/telemetry/{vehicle_id}GETAmostras GPS/bateria para janelanenhumanenhum
/stopsGETEstacionamentos + pontos de carga do operadornenhuma60s edge
/reportsGETAgregados mensais pre-computadosnenhuma60s edge
/.well-known/jwks.jsonGETJWK Set publico para verificar JWTs de respostan/a60s edge

Lista de veiculos -- /vehicles

Retorna todo veiculo vinculado a subconta. Uma linha por device_id.

curl -H "Authorization: Bearer <token>" \
  https://fleets.levyelectric.com/api/mds/<subaccountId>/provider/v2/vehicles

Envelope de resposta:

{
  "version": "2.0.1",
  "last_updated": "2026-05-18T12:00:00Z",
  "ttl": 60000,
  "vehicles": [ /* Objetos Vehicle MDS */ ]
}

Status de veiculos -- /vehicles/status

Paginado por cursor. Tamanho de pagina padrao 100, maximo 500. O cursor codifica o timestamp de atualizacao + ID do ultimo veiculo, de modo que paginas subsequentes sao estaveis em escritas.

curl -H "Authorization: Bearer <token>" \
  "https://fleets.levyelectric.com/api/mds/<subaccountId>/provider/v2/vehicles/status?cursor=<opaque>&limit=200"

A resposta inclui next_cursor quando ha mais paginas:

{
  "version": "2.0.1",
  "last_updated": "2026-05-18T12:00:00Z",
  "vehicles_status": [ /* objetos de status, inclui current_speed_limit_kph */ ],
  "next_cursor": "eyJ0aW1lIjoiMjAyNi0wNS0xOFQxMjowMDowMFoiLCJpZCI6IjQyIn0="
}

O campo current_speed_limit_kph em cada linha de status reflete o menor limite de velocidade aplicavel na ultima posicao conhecida do veiculo, considerando tanto zonas do operador quanto geofences de politica ativos. Veja Aplicacao de Velocidade em Tempo Real.

Veiculo unico -- /vehicles/{device_id}

Retorna um objeto Vehicle MDS. Util para validadores que sondam registros individuais antes de varrer a lista completa.

Viagens -- /trips

Paginacao por cursor ordenada por ended_at ascendente. Query parameter obrigatorio end_time e uma janela de 1 hora em ISO 8601:

GET /trips?end_time=2026-05-18T00:00:00Z

O endpoint retorna viagens cujo ended_at cai em [end_time, end_time + 1h). Viagens abertas sao excluidas.

Eventos -- /events

Paginacao por cursor ordenada por event_time ascendente. Mesma semantica de janela end_time que /trips. Emite mudancas de estado (available, reserved, on_trip, non_operational, removed etc.).

Telemetria -- /telemetry/{vehicle_id}

Retorna amostras GPS + bateria para um unico veiculo em uma janela de tempo. Se a tabela vehicle_telemetry estiver ausente (algumas subcontas antigas), a rota volta a vehicle_events automaticamente.

Stops -- /stops

Estacionamentos e pontos de carga definidos pelo operador, expostos como objetos Stop MDS. Inclui vehicle_type_capacity conforme esquema MDS 2.0.

Reports -- /reports

Agregados mensais pre-computados: total de viagens, total de veiculos ativos, distancia media de viagem, duracao media de viagem. Util para revisao trimestral da cidade sem varrer /trips.

Autenticacao

O Levy Fleets aceita requisicoes MDS com token bearer. Cidades podem adicionalmente verificar o JWT assinado que retornamos em cada resposta.

Tokens bearer

Emitidos em Configuracoes -> API e Integracoes -> Tokens MDS. Um token por cidade por subconta e tipico. O token e verificado contra mds_city_tokens em toda requisicao.

Authorization: Bearer <opaque_token>

JWT assinado em cada resposta

Toda resposta bem-sucedida inclui um header MDS-JWT contendo um JWT assinado em RS256. O payload do JWT inclui o sha256 do corpo da resposta, o ID da subconta, o issuer (https://fleets.levyelectric.com) e o timestamp issued-at. Cidades que exigem prova de integridade podem verificar o JWT contra a URL JWKS.

A chave de assinatura e a linha ativa em mds_jwks_keys para a subconta. Gerada lazy na primeira requisicao. Veja Gerenciamento de Chaves JWKS para rotacao.

Assinatura HMAC opcional no corpo

Para cidades que exigem prova de integridade HMAC ao inves (ou alem) do JWT, defina o header MDS-Signature na resposta. O segredo compartilhado e configurado por linha de city-token.

Discovery JWKS

O conjunto JWK publico vive em:

GET /api/mds/{subaccountId}/.well-known/jwks.json

Forma da resposta:

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "mds-2026-05",
      "use": "sig",
      "alg": "RS256",
      "n": "...",
      "e": "AQAB"
    }
  ]
}

O kid corresponde ao campo kid no header MDS-JWT para que cidades possam escolher a chave certa durante rotacao. Sempre publicamos a chave ativa mais quaisquer chaves ainda em sua janela de carencia de rotacao (padrao 7 dias).

Se uma cidade acessar a URL JWKS antes que a primeira requisicao tenha sido assinada, a rota gera lazy o primeiro par de chaves. Isso significa que novos operadores nao precisam tomar acao manual -- o primeiro ping do Populus e suficiente.

Envelope de resposta

Toda resposta MDS 2.0 usa a mesma forma externa:

{
  "version": "2.0.1",
  "last_updated": "2026-05-18T12:00:00Z",
  "ttl": 60000,
  "<data_key>": [ /* array de objetos MDS */ ],
  "next_cursor": "..."
}
  • last_updated e sempre RFC3339 UTC (sem POSIX epoch -- MDS 2.0 exige RFC3339).
  • ttl corresponde ao header Cache-Control: max-age (em milissegundos -- spec MDS usa ms, HTTP usa s).
  • next_cursor esta presente apenas quando ha mais paginas.

Paginacao por cursor

Cursores sao JSON { "time": <ISO>, "id": <last_id> } codificados em base64 opaco. Sao estaveis em escritas: uma nova linha inserida apos voce comecar o crawl aparecera em uma pagina futura, nunca no cursor atual.

Cidades devem:

  1. Fazer uma requisicao inicial sem cursor.
  2. Ler next_cursor da resposta.
  3. Passa-lo de volta na proxima requisicao: ?cursor=<value>.
  4. Parar quando next_cursor estiver ausente.

Tamanho de pagina padrao 100. Passe ?limit=<n> para sobrescrever (max 500).

Cache de borda

Cacheamos /vehicles, /vehicles/status, /stops, /reports e /.well-known/jwks.json no edge do Vercel por 60 segundos. Trips, events e telemetry nao sao cacheados -- sao delimitados por tempo via query, entao cada requisicao tem uma chave de cache unica de qualquer forma.

O header Cache-Control: public, s-maxage=60 e definido automaticamente em endpoints cacheados.

Rate limiting

Cada token bearer e limitado a 60 requisicoes por minuto com um burst de 600 requisicoes. Exceder o limite retorna HTTP 429 com Retry-After definido. Crawls de validador (10-15 endpoints consecutivos) ficam bem dentro do burst.

Se uma cidade consistentemente excede o limite, eleve via Configuracoes -> API e Integracoes -> Tokens MDS -> Override de Rate Limit.

Configuracao do validador

O mds-provider-validator do OMF (e o equivalente interno do Populus) espera:

VerificacaoValor
URL basehttps://fleets.levyelectric.com/api/mds/<subaccountId>/provider/v2/
AuthAuthorization: Bearer <token>
JWKShttps://fleets.levyelectric.com/api/mds/<subaccountId>/.well-known/jwks.json
Versao da spec2.0.1
Content-Typeapplication/vnd.mds+json;version=2.0

Execute o validador voce mesmo antes de entregar a uma cidade:

mds-provider-validator \
  --base "https://fleets.levyelectric.com/api/mds/<subaccountId>/provider/v2" \
  --auth "Bearer <token>" \
  --version 2.0.1 \
  --jwks "https://fleets.levyelectric.com/api/mds/<subaccountId>/.well-known/jwks.json"

Um run limpo reporta Passed: all endpoints conform. Quaisquer falhas sao mostradas com o campo e endpoint problematicos e devem ser corrigidas antes de compartilhar a URL com uma cidade.

Solucao de problemas

  • 401 em toda requisicao -- token bearer ausente ou revogado. Emita um novo em Configuracoes.
  • Validador falha no campo version -- confirme que o envelope de resposta reporta 2.0.1, nao 2.0.0. A versao e uma constante em src/lib/mds/v2/response.ts.
  • Header MDS-JWT ausente em uma resposta -- o par de chaves JWKS falhou em ser gerado. Visite /api/mds/<subaccountId>/.well-known/jwks.json diretamente para forcar um lazy mint, depois tente novamente.
  • current_speed_limit_kph sempre 0 -- o veiculo nao tem posicao conhecida recente, ou nenhuma zona de operador / geofence de politica o contem. Verifique que uma amostra GPS recente existe em vehicle_events.

Veja Solucao de Problemas para a checklist completa.

Proximos passos