API B2B

Cote, reserve e acompanhe seus fretes direto do seu ERP ou TMS, sem falar com ninguém. A especificação completa está em OpenAPI 3.1.

Autenticação e ambientes

Envie a chave no header Authorization: Bearer <chave>. Chaves mv_test_ operam no sandbox: os pedidos ficam marcados como teste, nenhum transportador é contatado e nenhum documento fiscal é emitido. Chaves mv_live_ operam em produção. Cada chave tem escopos e um limite por minuto; ao passar do limite a resposta é 429. Uma chave revogada recebe 401 na hora.

Idempotência

Todo POST aceita Idempotency-Key. Repetir a mesma chave com o mesmo corpo devolve a resposta original com Idempotent-Replayed: true; com outro corpo devolve 422; enquanto a primeira chamada ainda roda, 409. Use o ID do pedido no seu sistema como chave.

Endpoints

MétodoCaminhoEscopoO que faz
POST/b2b/quotesquotes:writeCota um frete. Retorna preço firme (contrato ou histórico suficiente) ou indicativo com faixa.
GET/b2b/quotes/{id}quotes:writeConsulta uma cotação e se já foi reservada.
POST/b2b/quotes/{id}/bookorders:writeReserva a cotação e cria o pedido. Cotação firme com contrato de aceite automático já fica confirmada.
GET/b2b/orders/{id}orders:readEstado do pedido (stage), preço e transportador.
POST/b2b/orders/{id}/acceptorders:writeAceita o preço firme enviado para um pedido reservado com preço indicativo.
POST/b2b/orders/{id}/nfeorders:writeAnexa a NF-e (XML ou chave de acesso). Completa peso, valor, remetente e destinatário.
GET/b2b/orders/{id}/trackingorders:readPosições e ETA.
GET/b2b/orders/{id}/documentsorders:readDocumentos do pedido (CT-e, MDF-e, comprovantes).
POST/b2b/orders/{id}/cancelorders:writeCancela enquanto o transporte não começou.

Cotar

curl -X POST https://api.moveraglobal.com.br/v1/b2b/quotes \
  -H "Authorization: Bearer mv_test_xxxxxxxx_..." \
  -H "Idempotency-Key: pedido-erp-4711" \
  -H "Content-Type: application/json" \
  -d '{
    "origin": "Campinas - SP",
    "destination": "Curitiba - PR",
    "vehicle_type": "truck",
    "weight_kg": 9000,
    "cargo_value": 80000
  }'
{
  "id": "34bb41ab-...",
  "mode": "indicative",
  "price": 3100,
  "price_low": 2860,
  "price_high": 3440,
  "currency": "BRL",
  "distance_km": 423.1,
  "components": { "ad_valorem": 150, "gris": 100, "tde": 0, "tolls": 0 },
  "contracted": false,
  "expires_at": "2026-10-06T11:28:49-03:00"
}

mode: "firm" é um preço garantido até expires_at. indicative é uma estimativa: ao reservar, enviamos o preço firme pelo webhook quote.firm e você confirma com POST /b2b/orders/{id}/accept.

Webhooks

Cadastre a URL (HTTPS) no painel. Cada evento chega como POST JSON assinado com HMAC-SHA256 no header X-Movera-Signature: t=<unix>,v1=<assinatura>. Responda 2xx em até 10 s. Falhas são reenviadas até 8 vezes com espera crescente (até 6 h); após 20 eventos seguidos sem sucesso o webhook é desativado. Use o id do evento para descartar duplicados.

{
  "id": "evt_9b1d...",
  "type": "order.confirmed",
  "created_at": "2026-10-05T14:28:49Z",
  "sandbox": true,
  "data": { "order_id": "16577105-...", "previous_state": "proposal_sent", "state": "confirmed" }
}
  • quote.firm — O preço firme de um pedido reservado como indicativo ficou pronto.
  • order.confirmed — Pedido confirmado.
  • carrier.assigned — Transportador definido.
  • pickup.confirmed — Coleta confirmada; a carga está em trânsito.
  • delivered — Entrega registrada.
  • delivery.confirmed — Entrega confirmada com comprovante.
  • payment.confirmed — Pagamento recebido.
  • order.completed — Pedido encerrado.
  • order.cancelled — Pedido cancelado.

Validação da assinatura em Go:

package movera

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"strconv"
	"strings"
	"time"
)

// VerifySignature checks X-Movera-Signature: t=<unix>,v1=<hex hmac-sha256(secret, "<t>.<body>")>.
func VerifySignature(secret, header string, body []byte) bool {
	var ts, sig string
	for _, part := range strings.Split(header, ",") {
		if v, ok := strings.CutPrefix(part, "t="); ok {
			ts = v
		} else if v, ok := strings.CutPrefix(part, "v1="); ok {
			sig = v
		}
	}
	unix, err := strconv.ParseInt(ts, 10, 64)
	if err != nil || time.Since(time.Unix(unix, 0)).Abs() > 5*time.Minute {
		return false
	}
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(ts + "." + string(body)))
	expected := hex.EncodeToString(mac.Sum(nil))
	return hmac.Equal([]byte(expected), []byte(sig))
}

Erros

Os erros têm o formato {"code": "...", "error": "..."}. Os mais comuns: unauthorized (401), forbidden (403), not_found (404), quote_unavailable (409, cotação vencida ou já reservada), duplicate_nfe (409), place_not_resolved e no_price (422).