Partner API
A REST API for rental operators that bill their own renters and need our data and management surface: priced tolls and violations per vehicle, plus cars, drivers, bookings, transponders and GPS devices.
Base URLs
https://owner.myeztoll.comProduction. Partner endpoints are served under the branded host — no raw API host to configure.
https://dev-owner.myeztoll.comSandbox for integration testing. Same surface, separate data, separate API keys.
Response envelope
Every endpoint answers with the same three fields, so one wrapper in your client handles all of them.
Paging
Every list endpoint returns a page, never a bare array: data is { items, page, pageSize, total, hasMore }. Pass ?page=1&pageSize=100 — pages are 1-based, pageSize defaults to 100 and is capped at 1000. total counts the whole filtered set, so keep asking for the next page while hasMore is true. The short reference lists (/car-types, /states, /toll-providers) stay plain arrays.
Money
Toll and violation rows separate the road cost from our fee: agencyAmount (tolls) and amount (violations) are exactly what the agency charged — the figure you bill your renter — while serviceFee is our flat per-transaction fee, never folded into the road cost. Amounts are in currency (USD unless stated).
Did the renter pay it back?
Every toll and violation row carries renterCharge. Its status is one of not_billed, estimate, pending, charged, declined, invoiced, reimbursed_by_platform, paid_cash, paid_manually or owner_absorbed. amount is what the renter is asked for; paidAmount and chargedAtUtc appear once it is collected, and paymentId names the card charge — tolls collected together share it. A coarse failureReason, the next automatic retry (nextAttemptAtUtc) and collectionsStatus — set while an unpaid debt is with the collections process — complete the picture. Rows inside a booking also carry bookingSource (turo, hqrental, own, …) and bookingSourceReservationId, for example the Turo trip id.
Dates
All timestamps are UTC instants in ISO-8601 (2026-07-31T14:05:00Z). In range queries from is inclusive and to is exclusive; omit them and you get the last 30 days.
GPS & telematics
If your cars carry a GPS device — ours, or one we read from your telematics provider — the /gps endpoints hand you the same feed our own fleet map uses: where every car is right now, the track and the mileage of a car or of a single rental, and whether a device is still healthy. Raw positions are kept for 30 days, so read a rental track or mileage while it is fresh; the priced GPS tolls derived from those tracks are permanent and live with the rest of the money data at /tolls?source=gps.
Integrations: one token, many owners
A platform that serves many owners — a fleet-accounting product, for example — receives ONE integration token instead of a key per owner, and may act only for owners who connected it themselves in their owner portal. Name the owner of each request in the X-Owner-Id header; list the owners you may act for with GET /owners, or receive owner.connected / owner.disconnected webhooks. Without X-Owner-Id only /me, /owners and /webhooks answer — every other endpoint returns 400; an owner who never connected you, or has disconnected, returns 401. For an owner key X-Owner-Id is ignored.
Disputes on your own Stripe account
If you charge your renters on your own Stripe account, we answer their disputes with you. Report each charge with POST /charges — which tolls, violations and fees it covered. When Stripe opens a dispute on it, POST /disputes. We collect the evidence — toll and violation report, driver’s licence, rental agreement, GPS track, messages, and for a duplicate claim the renter’s charge history — and send dispute.evidence_ready. GET /disputes/{id} returns evidence keyed by Stripe’s own evidence field names: pass the text fields through unchanged, and for each { fileId } download the file, upload it to your Stripe account with purpose dispute_evidence and put the resulting file_… id in its place. Then report submitted, and later won or lost, with PATCH /disputes/{id}. We never call your Stripe account.
Webhooks
Instead of polling, register an HTTPS endpoint with POST /webhooks. We POST one JSON event per change — { id, type, createdAtUtc, ownerId, data } — of the types toll.created, toll_charge.updated, violation.created, violation.charge_updated, owner.connected and owner.disconnected. Every call is signed: X-MyEzToll-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")> — verify it with the secret returned when you registered the endpoint, and reject stale timestamps. Answer 2xx quickly; anything else is retried with exponential back-off for about 1.5 days. De-duplicate on the event id, also sent as X-MyEzToll-Event-Id.
Disputes add dispute.evidence_ready, dispute.evidence_failed and dispute.deadline_approaching.
const crypto = require('crypto');
// rawBody: the exact request body as received, before any JSON parsing.
function isGenuine(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false; // stale
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
const given = Buffer.from(parts.v1 || '', 'hex');
return given.length === expected.length && crypto.timingSafeEqual(given, expected);
}Your own ids
Create calls accept an optional externalId — your own identifier for the car, driver or booking. Once set, you can pass your id anywhere ours is accepted, and responses carry it back, so you never have to store a second id map.
Get started
There are two ways to use the API, and the first one is smaller than most integrators expect. Pick the track that matches how much of the rental you want us to know about.
You keep the rental in your own system and only ask us what a plate cost.
- 1Ask support for a sandbox key and a production key.
- 2Register your cars — or match them to existing ones — with
POST /cars. - 3Read
GET /cars/{carId}/tolls?from=&to=andGET /cars/{carId}/violations?from=&to=for one vehicle, orGET /tolls?from=&to=andGET /violations?from=&to=for the whole fleet. Bill your renters from the amounts.
Worth it when you want us to say WHO was driving, and when you want GPS tolls.
- 1Do steps 1 and 2 above.
- 2Create drivers with
POST /driversand rentals withPOST /bookings. - 3Read
GET /bookings/{bookingId}/tollsper rental, and still pollGET /tolls/GET /violationsfor anything outside a booking.
Both return the same row shape and the same money. A period read (
/tolls, /cars/{carId}/tolls) answers “what did this plate cost between these dates” and returns AGENCY tolls only — the ones the toll operator billed to the vehicle. A booking read (/bookings/{bookingId}/tolls) answers “what did this rental cost”: the agency tolls inside the rental window PLUS the GPS tolls computed from the vehicle track, which exist only inside a booking. So the period route never contains GPS tolls — not because they are filtered out, but because without a rental there is nothing to attribute them to.renterCharge on every toll and violation tells you whether and when the renter paid.