TOVRReference

REST API overview

The TOVR REST API is a narrow, OAuth2-authenticated surface over tovr.eu/api/v1: ingest and read shipments, read chains, vehicles, matches, quotes and outreach, follow what changes, price lanes, and authenticate.

The TOVR REST API lets external systems push freight into TOVR and read it back. It is deliberately narrow: mostly reads, versioned under /api/v1. Shared conventions (bearer format, error envelope, rate limits, versioning) are in API conventions.

Base URL

EnvironmentBase URL
Productionhttps://tovr.eu/api/v1
Staginghttps://staging.tovr.eu/api/v1

Authentication

Every endpoint (except the token endpoint itself) requires a bearer token obtained via the OAuth 2.0 client-credentials flow:

  1. Create a client application in the dashboard to get a client_id and client_secret.
  2. Exchange them for an access token at the token endpoint (expires_in is 3,600 seconds, one hour).
  3. Send Authorization: Bearer <token> on each request.

The platform validates the token and injects your organization and client context — so request bodies never carry an org identifier; it is inferred from the token.

Resources

This is every endpoint under /api/v1. Every endpoint other than the token endpoint requires the scope shown; a client application is granted scopes when it is created.

ResourceEndpointsScope
ShipmentsGET /shipments · GET /shipments/{id}shipments:read
POST /shipments · PATCH /shipments/{id}shipments:write
InvoicesGET /invoices · GET /invoices/{id}invoices:read
Freight chainsGET /chains · GET /chains/{id}chains:read
VehiclesGET /vehicles · GET /vehicles/{id} · GET /vehicles/{id}/availabilitiesvehicles:read
MatchesGET /matches · GET /matches/{id}matches:read
Quotes (carrier bids)GET /quotes · GET /quotes/{id}quotes:read
Outreach timelineGET /outreach · GET /outreach/{id}outreach:read
Change feedGET /eventsevents:read
GET /events/stream (server-sent events)events:stream
WebhooksGET /webhook_endpoints · GET /webhook_endpoints/{id}webhooks:read
POST /webhook_endpoints · PATCH/DELETE /webhook_endpoints/{id} · POST /webhook_endpoints/{id}/rotate_secretwebhooks:write
PricingPOST /estimate · POST /estimate/batchestimate
MarketGET /market/overviewmarket
TokenPOST /oauth2/tokennone

Everything except shipments and webhook endpoints is read-only: there is no API to create or change a chain, vehicle, match, quote or outreach entry. A few notes on what the read-only resources return:

  • Vehicles lists your own fleet plus trucks published on the exchange; ownership on each row says which. /availabilities is a live contract that currently returns an empty list, because no connected telematics provider reports availability windows yet.
  • Matches and quotes are visible to both sides. own_side (matches) and own_role (quotes) say which side you are. A match carries shipment ids, not freight; fetch the freight through GET /shipments/{id}.
  • Chains in a list omit shipment_ids and stops (they are null). Fetch one chain by id to get them.
  • Outreach is the timeline of interactions (when, which channel, which direction, what kind). It does not include message content or names. ?chain_id= narrows it to one chain.
  • Invoices are records of invoices your ERP issued, not invoices TOVR issues — no PDF, no due date, no payment state. invoices:read is deliberately separate from shipments:read, so an organization can let a factoring integration read what it billed without handing over the whole shipment book.

Client applications are created and rotated in the TOVR dashboard, under Settings → Developer, not over the API. The /oauth2/client_applications endpoints that used to be documented here were authenticated by a browser session rather than by a bearer token — so they were never callable by an API client in the first place — and they scoped by creator rather than by organization, which is not what this page claimed.

There are no carrier or shipper directory endpoints. The table above is the whole API.

The pricing and market endpoints changed on 2026-08-25. They used to run on an older request path with their own error bodies and, because rate limiting lives on the shared path, with no rate limit or monthly quota at all. They now behave like every other endpoint: the shared error envelope, X-Request-Id on every response, the RateLimit-* headers, and an entry in the generated OpenAPI document.

This is a breaking change to the errors — validation failures moved from 400 to 422, scope denials changed body shape, and 429/402 are newly reachable. Every 2xx body is unchanged. Read 2026-08-25-apex-pricing-and-market-routes before upgrading a client.

They still do not honour Idempotency-Key: all three are reads that write nothing, so a key on one would be a cache with no invalidation.

Staying in sync

GET /shipments answers what is true now. To keep a mirror current without re-reading the whole book, use the change feed — poll GET /events with a cursor, or receive the same events as webhooks. Both carry an id and a type rather than a row, so there is exactly one place that decides what your organization may read.

Data model

A shipment payload is a nested tree — stops, cargo, costs, identifiers. Its shape is described in the domain-model reference; what the entities mean is in TOVR › Concepts › Domain model.

/loads has been removed. It was an API-only second model of the same freight: nothing in the product read it, and everything it expressed is already expressible as cargo on the shipment. Send line items as cargo.items[] on POST /shipments instead. Consignment splitting, if you need it, arrives additively on that same array rather than as a separate resource.

On this page