Skip to main content

Overview

In addition to our unified API, Terminal can stream normalized data directly to a Kafka cluster you operate. This enables:
  • Low-latency ingestion into your event-driven systems and stream processors
  • Routing the same data to your existing Kafka consumers, sinks, and downstream warehouses

How it Works

Terminal ingests data from telematics providers on an ongoing basis and normalizes it into our Common Models. As records are ingested or updated, Terminal produces them as events to topics on your Kafka cluster. Terminal authenticates to your cluster using credentials you provide (see Authentication) and produces records as soon as they are ingested or updated.

Delivery model

Kafka delivery is a continuous, push-based stream:
  • Real-time: records are produced to your topics shortly after Terminal ingests or updates them, without waiting for a schedule.
  • Per-model topics: you map each Common Model you want delivered to a topic name on your cluster. Terminal produces records for that model only to the configured topic.
  • At-least-once: records can occasionally be redelivered (for example, after retries or recovery). Use the keys described in Message format to deduplicate downstream if your use case requires exactly-once semantics.
  • Backfills: when you onboard a new connection or request historical data, Terminal will produce existing records to the same topics so your consumers see a consistent stream.

Message format

Each Kafka record contains:
  • Value: an Avro encoded MessageWrapper event. The schema mirrors Terminal’s webhook event structure so the same downstream code can consume both.
  • Key: a UTF-8 encoded string derived from the configured partition keys for the topic.
  • Topic: the topic name you configured for that model.
The MessageWrapper record has the following shape:
Top-level fields:
  • eventType: insert for a newly ingested record, modify for an update to an existing record.
  • model: the Common Model name (for example, Vehicle, VehicleLocation, Trip).
  • detail: a record where exactly one field is populated, matching model. Each field follows the canonical Common Model schema.
In addition to the fields documented in the Common Models, every record includes a connectionId field that identifies the source connection.
Getting the Avro schemas. Terminal will share the .avsc schema files for the MessageWrapper and every Common Model you subscribe to. Reach out to your Terminal contact and we will send the latest schema bundle, which you can register in a schema registry, use for code generation, or load directly with Avro deserializers in any language. A self-serve download and schema registry compatibility are on the roadmap.

Partition keys

Each topic has a configurable list of partition key components. Terminal builds the record key by joining the selected components with a colon (:), and Kafka uses that key to assign records to partitions consistently. Available components:
  • CONNECTION: the connectionId of the source connection.
  • PRIMARY_KEY: the model’s own primary identifier (for example, vehicleId for Vehicle, tripId for Trip).
  • FOREIGN_KEY: the related entity’s identifier (for example, vehicleId for a VehicleLocation or VehicleStatLog). Useful for keeping all activity for a single vehicle on the same partition.
If multiple components are configured, the resulting key looks like conn_01ARZ.../veh_01ARZ.... If a record has no value for any of the configured components, the key falls back to a sentinel value so the record is still produced. Choose components based on your downstream ordering and parallelism needs. A common choice for time-series models is [CONNECTION, FOREIGN_KEY] so that all events for a given vehicle on a given connection land on the same partition in order.

Ordering guarantees

Terminal does not provide global ordering guarantees on Kafka delivery. There are two reasons:
  • Provider ingestion is not strictly ordered. Telematics providers expose data through APIs and webhooks that can return events out of order, especially during catch-up after a sync delay.
  • The replication pipeline is change-data-capture based and parallel, so the order in which records reach the producer is not the order in which they were originally generated by the device.
To improve practical ordering, Terminal applies a short windowed sort before producing to your topics:
  • Records are grouped by the configured partition key and sorted within a tumbling time window (currently 30 seconds, capped at 50,000 records per window).
  • Within that window, records for the same partition key are produced in event-time order. Across windows, or across different partition keys, no ordering is implied.
The windowed sort is configurable as an ordering block on the destination. Today it is a single on/off toggle (enabled) and defaults to false, the 30-second window and 50,000-record cap are fixed. Enable it if you want Terminal to apply the per-partition sort before produce, or leave it off to have records flow through with the lowest possible latency and handle ordering entirely on your consumer side. This is best-effort smoothing, not a contract. Consumers that require strict ordering, exactly-once semantics, or de-duplication should still:
  • Pick a partition key that aligns with the entity you order around (for example, [CONNECTION, FOREIGN_KEY] for time-series models keeps all activity for a vehicle on one partition).
  • Apply their own windowing or buffering by event timestamp on the consumer side.

Topic options

You manage topics on your own cluster. For each Common Model you want delivered, you provide:
  • The topic name Terminal should produce to.
  • The partition key components for that topic.
  • Whether to include raw provider data alongside the normalized payload.
Topic-level controls (partition count, replication factor, retention, compaction, ACLs) remain on your side. Make sure each topic exists before enabling the destination, and that the credentials you give Terminal have produce permissions on it.

Reference implementation

These are the conventions we recommend when standing up a new Kafka destination. They are not enforced and you can deviate where it makes sense for your stack, but starting from these defaults makes most consumer patterns straightforward. Topics
  • One topic per Common Model, named with a stable prefix you control (for example, terminal.vehicle, terminal.vehicle-location, terminal.trip).
  • Replication factor 3 for production clusters.
  • Partition count sized for your largest model. For most fleets, 12 to 24 partitions on VehicleLocation and VehicleStatLog is a good starting point. Entity topics (Vehicle, Driver, Trip) can be smaller (3 to 6).
  • Retention sized for your replay window. 7 days of retention on time-series topics covers most operational replays. Entity topics work well as standard topics with longer retention rather than compacted, since Terminal emits both insert and modify events and consumers usually want the history.
Partition keys
  • Time-series models (VehicleLocation, VehicleStatLog, SafetyEvent, FaultCodeEvent, Trip, HOSLog): [CONNECTION, FOREIGN_KEY]. This pins all activity for a given vehicle (or driver) on a given connection to one partition, which preserves the ordering window’s benefit and gives you natural per-vehicle parallelism on the consumer side.
  • Entity models (Vehicle, Driver, Device, Group, Trailer): [CONNECTION, PRIMARY_KEY]. Updates to the same entity always land on the same partition.
  • Aggregate models (HOSDailyLog, IFTAVehicleMonth, VehicleUtilizationDay): [CONNECTION, FOREIGN_KEY] if you join them by vehicle, otherwise [CONNECTION, PRIMARY_KEY].

Sandbox environment

Kafka delivery is not currently available in the sandbox environment. To validate your consumer end-to-end, work with our team to set up a production destination against a non-production Kafka cluster you control.

Setup and configuration

Setup checklist

The fastest path to a working Kafka destination, in order:
  1. Create the topics on your cluster. Use the conventions in Reference implementation if you don’t already have a standard.
  2. Provision a SASL user dedicated to Terminal (for example, terminal-producer) and capture the username and password.
  3. Grant ACLs to that user: Write and Describe on each topic. See Required ACLs.
  4. Decide on network connectivity: public internet, AWS PrivateLink, or AWS MSK VPC. Gather the corresponding identifiers (egress IP allow-list, VPC Endpoint Service name, or MSK cluster ARN). See Network connectivity.
  5. Send the destination config (template in Share your destination details) to your Terminal contact.

Prepare your Kafka cluster

  1. Identify the bootstrap servers Terminal will connect to (for example, b-1.your-cluster.kafka.us-east-1.amazonaws.com:9096,b-2.your-cluster.kafka.us-east-1.amazonaws.com:9096).
  2. Decide which Common Models you want delivered, and create one topic per model on your cluster with the partition count, replication factor, and retention that fit your use case.
  3. Choose how Terminal will reach your cluster: public internet, AWS PrivateLink, or AWS MSK VPC peering. See Network connectivity for details.

Authentication

Terminal authenticates with your cluster over SASL.
  • Security protocol: SASL_SSL (default). All traffic is encrypted in transit using TLS to your brokers’ certificates.
  • SASL mechanism: SCRAM-SHA-512 (default). SCRAM-SHA-256 is also supported on request.
  • Credentials: a username and password that Terminal uses to authenticate. Provision a dedicated user for Terminal so you can rotate or revoke access independently of other consumers.
The credentials you provide are stored encrypted at rest in Terminal and are only used to authenticate the replication producer to your cluster.

Required ACLs

Grant the Terminal user the following ACLs on your cluster:
  • Write on each topic Terminal will produce to.
  • Describe on each topic Terminal will produce to (used to verify topic existence and metadata).
  • IdempotentWrite on the cluster (used so the producer can dedupe in-flight retries).
The exact command depends on your broker tooling. On an Apache Kafka or MSK cluster using kafka-acls.sh, this looks like:
Repeat the topic ACL command for each topic Terminal will produce to.

Network connectivity

Terminal supports three ways to reach your cluster.
The simplest setup. Terminal connects to your brokers over the public internet using the bootstrap servers you provide. All traffic is encrypted with SASL_SSL.Use this option if your brokers are publicly reachable and you are comfortable allowing inbound connections from Terminal’s egress IPs. Contact our team for the current list of egress IPs to allow-list at your network boundary.

Share your destination details

The fastest way to send us your configuration is to fill out the JSON template below and share it with your Terminal contact (over your shared Slack channel or by email). Send the password through a secure channel separately. We’ll confirm everything before provisioning.
Notes on the template:
  • Replace network with one of the variants below if you are not using public internet.
  • Add or remove entries under topics for the Common Models you want delivered. The key (Vehicle, VehicleLocation, etc.) must match the Common Model name exactly.
For the full list of configuration options, see Configuration options. Our team is here to help recommend the best settings for your needs.
Self-service destination management through the Terminal dashboard is coming soon.

Configuration options