App Development
Designing an API for Vehicle Telematics Data: Ingestion, Storage, Rate Limits and Versioning
Telematics platforms have two jobs that pull against each other: absorbing bursty device data around the clock, and serving customers an API that is fast, predictable and stable for years. Here is how we design for both, drawing on a NestJS platform that ingests 40 million events a day.

A telematics platform has two very different jobs. On one side, thousands of devices report positions, ignition events and trip data around the clock, often in bursts. On the other, customers and partners build their own products on that data and expect an API that answers quickly, behaves predictably and does not change under them. Most of the design decisions come down to keeping those two sides from interfering with each other.
Through our NestJS development work we built exactly this for a vehicle telematics provider: a fleet telematics API platform that ingests 40 million events a day and serves partners, dashboards and mobile apps from one documented interface. The decisions below come from that project, and most apply to any high-volume device data.
Keep Ingestion Away From the Public API
The most important decision is that devices never talk to the process that answers customers. Device traffic is bursty in ways you cannot control: a mobile network outage ends and thousands of units reconnect at once, each uploading what it buffered, and every morning brings a wave of ignition events. If ingestion and queries share a process or a connection pool, a burst from the field slows every customer's dashboard.
On the telematics platform, devices publish over MQTT and events flow into Kafka, which acts as a shock absorber. Consumers process events at their own pace, with back-pressure, and the public API reads from separate stores. The provider's original Express backend had no such separation, and a single slow query could stall everything. Now a reconnection burst simply makes the queue longer for a while.
A few rules for the ingestion path:
- Acknowledge fast, process later. Accept the message, put it on the queue, and let consumers handle validation and enrichment.
- Expect duplicates. Devices resend when they are unsure a message arrived. Give each event an identity, such as device ID plus sequence number, and make writes idempotent.
- Expect disorder. Buffered events arrive late and out of order. Store both the device timestamp and the time you received it, and never assume the newest message is the latest position.
- Do not trust device clocks blindly. A unit that has lost its time can report dates years in the past. Flag implausible timestamps rather than filing them silently.
Storage Built for Time Series
Position histories grow quickly and are almost always queried by vehicle and time range. An ordinary table with an index copes for a while, then becomes the slowest thing in the system. The platform stores time-series data in PostgreSQL with TimescaleDB, which partitions by time automatically and keeps queries over long histories fast, while remaining ordinary SQL that any PostgreSQL developer can query.
The most frequent question, "where is this vehicle now?", should not touch the history at all. The platform keeps the latest known state of each vehicle in Redis, so that request is a single lookup. Planning those two access patterns separately is work our database development team does up front, because changing storage under tens of millions of rows a day is far harder later.
Decide retention early too. Raw positions every few seconds may only be needed for a few months, while trip summaries and daily totals can be kept for years. Downsampling old data into aggregates keeps storage costs flat and reports fast. Put the retention periods in the API documentation so nobody discovers the limit by accident.
An API Partners Can Build On
A public API is a product in its own right: partners integrate once and expect it to keep working. On the telematics platform the REST endpoints are built with NestJS, with validation, pagination and error formats applied the same way everywhere, and OpenAPI documentation generated from the code so the docs always match the behaviour. Partner integration time fell from weeks to days. Our API development and integration service applies the same principles in other sectors.
Choices that matter for this kind of data:
- Cursor pagination, not page numbers. New events arrive constantly, so offset-based pages shift under the client and rows are skipped or repeated.
- Explicit time ranges with limits. Require a start and end, cap the window per request, and offer a bulk export for anything larger.
- One timestamp format, in UTC. Leave time zones to the client.
- Webhooks for events, the API for state. Partners who care about a trip ending or a vehicle leaving a geofence should be told rather than left polling. The platform sends signed webhooks with retries and a delivery log partners can inspect themselves.
Rate Limits and Metering
Every call on the telematics platform is attributed to an API key, which feeds billing and enforces rate limits fairly across customers. Without that, one badly written integration polling every vehicle every second can degrade the service for everyone else.
Good rate limiting is predictable. Publish the limits, return HTTP 429 with a Retry-After header when a client exceeds them, and include the remaining quota in response headers so well-behaved clients can pace themselves. Limit per key rather than per IP address, because many partners call from shared cloud infrastructure. Give bulk and export endpoints their own limits, and use the metering data to see which endpoints customers actually rely on before changing anything.
Versioning Without Breaking Integrations
A customer's integration is code you do not control and cannot redeploy, so treat any change to a response's shape as potentially breaking. The rules we work to:
- Adding a field or an endpoint is safe; removing or renaming one needs a new version.
- Put the version in the path or a header, and support the previous version for a published period.
- Announce deprecations in the documentation, in response headers, and directly to the key owners still calling the old version, whom metering lets you identify.
- Keep the old interface running behind a gateway while customers migrate.
That last point is how the provider moved off its old backend: the Express API stayed alive behind a gateway while partners migrated, and was retired once they had.
Why NestJS Suited the Job
Raw speed was not the deciding factor. The platform answers with a p95 latency of 38 ms because of its data stores and caching, not its framework. The deciding factor was structure: three teams work on the platform, and before the rebuild they had added endpoints in three different styles. NestJS gives every service the same modules, validation, guards and generated documentation, so any team can work on any service. The services run in Docker on Kubernetes with rolling deployments, set up the way our Docker and Kubernetes work describes, and uptime over the first year was 99.99%. For when that structure is worth adopting, see NestJS vs Express.
If you are planning an API for device data, or your current one struggles every time the fleet reconnects, send us your event volumes and a list of who consumes the data. We will tell you where the bottleneck is likely to be and what to change first.
Frequently Asked Questions
Should telematics devices send data over MQTT or HTTP?
MQTT is usually the better fit for devices. It keeps a lightweight connection open, uses very little data per message, copes well with patchy mobile coverage and supports delivery guarantees. HTTP is simpler to start with and fine for devices that report rarely, but the overhead of a full request per position adds up quickly across thousands of vehicles. Many platforms accept both and normalise them at the ingestion layer.
How long should we keep raw telematics data?
Base it on what customers actually query and any contractual or legal requirements. Raw high-frequency positions are typically needed for weeks or months for trip replay and disputes, while trip summaries, mileage and daily aggregates can be kept for years at a fraction of the storage cost. Whatever you choose, publish it, because customers building reports on your API need to know how far back the data goes.
Should a telematics API offer GraphQL as well as REST?
Sometimes. GraphQL helps when consumers need flexible combinations of vehicles, drivers and trips in one request, such as a dashboard. For high-volume time-series data, REST endpoints with explicit time ranges, cursor pagination and bulk exports are easier to cache, rate limit and meter. A common pattern is REST for partners and data access, with GraphQL used only by your own front ends if it suits them.
How can partners verify that a webhook really came from our platform?
Sign every payload with a secret unique to each partner, usually an HMAC of the body plus a timestamp, and send the signature in a header. The partner recalculates it and rejects anything that does not match or whose timestamp is too old, which also blocks replayed messages. Document a sample verification in common languages, and let partners rotate their secret without downtime.
Can we move an existing telematics backend to NestJS without disrupting customers?
Yes, if it is done in stages. Put a gateway in front of the existing API, build new NestJS services behind it, and move endpoints or consumers across one group at a time while the old interface keeps working. Replaying recorded device traffic against the new ingestion pipeline before switching shows whether it copes with real bursts. Customers only need to change anything when you retire an old API version.








