/v3/driver_tracking/scenario/{scenario_id}/gps_points?latest_only=true
Get latest point per run for a scenario (or pass latest_only=false for all points). Accepts API key or Access token.
Vehicle route optimisation, maps and driving times, core operational resources, and real-time driver tracking.
https://api.optimiser.app/v3
Start here
Use an API key from a trusted server to call the API. For example, list your organisation’s scenarios:
curl "https://api.optimiser.app/v3/core/scenarios" \
-H "X-Tarot-API-Key: $TAROT_API_KEY"
import os, requests
response = requests.get(
"https://api.optimiser.app/v3/core/scenarios",
headers={"X-Tarot-API-Key": os.environ["TAROT_API_KEY"]},
)
response.raise_for_status()
scenarios = response.json()
const response = await fetch("https://api.optimiser.app/v3/core/scenarios", {
headers: { "X-Tarot-API-Key": process.env.TAROT_API_KEY },
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const scenarios = await response.json();
Authentication
Give your key a descriptive name and appropriate role, then copy the generated secret when shown once. Store it securely in a server-side secret manager or environment variable. Keys can be rotated with a temporary overlap period and revoked immediately if exposed or no longer needed.
To log a user into an embedded Tarot iframe from your product, see the embedded iframe SSO guide.
If you do not have permission to access that page, contact your Organisation's administrator or . If you do not yet have a Tarot account, visit tarotanalytics.com to start a free trial or book a demo.
Credentials
Every request to Tarot requires exactly one credential in the HTTP headers. Choose the authentication method that matches where your code runs:
X-Tarot-API-Key header. Best for backend microservices, background workers, and server-side scripts.Use a permanent API key for all server-to-server requests originating from a trusted backend environment.
Never embed API keys in browser code, frontend applications, distributed mobile apps, source control, or client-accessible logs.
Use a short-lived access token in the standard Authorization: Bearer <access_token> header for requests originating from browser applications, single-page apps (SPAs), or mobile applications.
Frontend and app clients must not hold permanent API keys because client-side code is accessible to users. Instead, have your secure server exchange its API key for an access token using the exchange endpoint below, and pass that token to your client.
When a trusted server needs to give its browser or mobile client a short-lived credential, use this endpoint to exchange the server-held API key for an access token:
curl -X POST "https://api.optimiser.app/v3/auth/api_key/exchange" \
-H "X-Tarot-API-Key: $TAROT_API_KEY"
import os, requests
response = requests.post(
"https://api.optimiser.app/v3/auth/api_key/exchange",
headers={"X-Tarot-API-Key": os.environ["TAROT_API_KEY"]},
)
response.raise_for_status()
token = response.json()
const response = await fetch(
"https://api.optimiser.app/v3/auth/api_key/exchange",
{
method: "POST",
headers: { "X-Tarot-API-Key": process.env.TAROT_API_KEY },
},
);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const token = await response.json();
The response contains a short-lived JWT and its absolute expiry:
{
"access_token": "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIuLi4ifQ.xxxxxxxxxxxxxxxxxxxx",
"access_token_expiry": "2026-07-17T02:59:58.652Z"
}
The default access_token lifetime is 15 minutes. Callers should always introspect the exp claim within the JWT payload (or read access_token_expiry). We recommend requesting a fresh token approximately 30 seconds before expiry rather than refreshing on every client API call.
access_token and access_token_expiry to its authenticated client using your own secure session/channel./v3/… endpoints with Authorization: Bearer $ACCESS_TOKEN.Never send the API key to the client. The exchange response is marked Cache-Control: no-store; clients should also keep the access token only as long as needed.
Use a runsheet token in the standard Authorization: Bearer <runsheet_token> header for driver-specific operations, such as live driver GPS tracking point ingestion.
The run token (a UUIDv4 string) is returned in the token field of the standard RunSchema on any Core API call that creates or retrieves runs. Most commonly, you obtain it from:
GET /v3/core/runs?scenario_id={scenario_id} (Swagger →)GET /v3/core/runs/{run_id} (Swagger →)POST /v3/core/runs (Swagger →)POST /v3/core/optimise/scenarios/{scenario_id} (Swagger →)Your server exchanges this Run token (UUID) for a runsheet token (JWT) at POST /v3/core/auth/runsheet_token (Swagger →):
curl -X POST "https://api.optimiser.app/v3/core/auth/runsheet_token" \
-H "X-Tarot-API-Key: $TAROT_API_KEY" \
-H "Content-Type: application/json" \
--data '{"token_uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6"}'
import os, requests
response = requests.post(
"https://api.optimiser.app/v3/core/auth/runsheet_token",
headers={"X-Tarot-API-Key": os.environ["TAROT_API_KEY"]},
json={"token_uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6"},
)
response.raise_for_status()
runsheet = response.json()
print("Runsheet token:", runsheet["runsheet_token"])
const response = await fetch(
"https://api.optimiser.app/v3/core/auth/runsheet_token",
{
method: "POST",
headers: {
"X-Tarot-API-Key": process.env.TAROT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
token_uid: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
}),
},
);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const runsheet = await response.json();
console.log("Runsheet token:", runsheet.runsheet_token);
The response returns the runsheet JWT:
{
"runsheet_token": "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIuLi4ifQ.xxxxxxxxxxxxxxxxxxxx"
}
The default runsheet_token lifetime is 90 days. Callers should always introspect the exp claim in the JWT payload to verify expiration before making requests.
Provide this runsheet_token in the Authorization: Bearer <runsheet_token> header when drivers or devices send GPS points to /v3/driver_tracking/gps_points.
API map
| Family | Base path | Allowed methods | Authentication |
|---|---|---|---|
| API-key exchange | /v3/auth/api_key/exchange |
POST | API key only |
| Core resources | /v3/core/* |
GET, POST, PUT, DELETE | API key or Access token |
| Maps & driving times | /v3/osrm/* |
GET | API key or Access token |
| Route Optimisation | /v3/opt/* |
GET, POST | API key or Access token |
| Live driver locations | /v3/driver_tracking/* |
GET, POST | Runsheet token (for driver points) or API key / Access token (for scenario query) |
Core resources
The Tarot Core API exposes full scenario management, orders, jobs, vehicle routing, dispatch, and run operations under the /v3/core/ prefix (forwarded upstream to /api/* on the backend core service).
With hundreds of operations available across orders, scenarios, jobs, runs, and vehicles, consult the interactive Swagger API reference for complete endpoint listings, schema definitions, and parameter documentation.
For a complete integration walkthrough, see Create and edit drivers, Create scenarios and jobs, Retrieve Planned Runs, and Retrieve delivery proofs.
curl "https://api.optimiser.app/v3/core/scenarios" \
-H "X-Tarot-API-Key: $TAROT_API_KEY"
import os, requests
response = requests.get(
"https://api.optimiser.app/v3/core/scenarios",
headers={"X-Tarot-API-Key": os.environ["TAROT_API_KEY"]},
)
response.raise_for_status()
scenarios = response.json()
const response = await fetch("https://api.optimiser.app/v3/core/scenarios", {
headers: { "X-Tarot-API-Key": process.env.TAROT_API_KEY },
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const scenarios = await response.json();
See the Core API reference for request schemas, query filters, and domain models across all core resources.
Maps & driving times
Every standard OSRM service is supported: route, nearest, table, match, trip, and tile.
curl "https://api.optimiser.app/v3/osrm/route/v1/driving/13.388860,52.517037;13.397634,52.529407?overview=false" \
-H "X-Tarot-API-Key: $TAROT_API_KEY"
import os, requests
response = requests.get(
"https://api.optimiser.app/v3/osrm/route/v1/driving/13.388860,52.517037;13.397634,52.529407",
params={"overview": "false"},
headers={"X-Tarot-API-Key": os.environ["TAROT_API_KEY"]},
)
response.raise_for_status()
route = response.json()
const response = await fetch(
"https://api.optimiser.app/v3/osrm/route/v1/driving/13.388860,52.517037;13.397634,52.529407?overview=false",
{
headers: { "X-Tarot-API-Key": process.env.TAROT_API_KEY },
},
);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const route = await response.json();
Supported profiles include driving with standard OSRM query parameters (such as overview, steps, and annotations). Coordinates are formatted as {longitude},{latitude}.
Route Optimisation
Requests to https://api.optimiser.app/v3/opt are forwarded upstream to /v2/* on the GRLS solver. Requests have a generous 10-minute timeout budget and support payloads up to 20MB.
curl -X POST "https://api.optimiser.app/v3/opt/vrp" \
-H "X-Tarot-API-Key: $TAROT_API_KEY" \
-H "Content-Type: application/json" \
--data @request.json
import json, os, requests
with open("request.json") as request_file:
payload = json.load(request_file)
response = requests.post(
"https://api.optimiser.app/v3/opt/vrp",
headers={"X-Tarot-API-Key": os.environ["TAROT_API_KEY"]},
json=payload,
)
response.raise_for_status()
result = response.json()
import { readFile } from "node:fs/promises";
const payload = JSON.parse(await readFile("request.json", "utf8"));
const response = await fetch("https://api.optimiser.app/v3/opt/vrp", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Tarot-API-Key": process.env.TAROT_API_KEY,
},
body: JSON.stringify(payload),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const result = await response.json();
Use the GRLS optimisation documentation for synchronous and asynchronous workflow details, request schemas and response semantics.
Live driver locations
Provides real-time GPS point ingestion and scenario-level tracking queries for active fleet operations.
/scenario/{scenario_id}/gps_points): Authenticate using your server API key (X-Tarot-API-Key) or an Access token (Authorization: Bearer <access_token>, default 15-minute lifetime; introspect exp)./gps_points): Strictly require a driver Runsheet token (Authorization: Bearer <runsheet_token>, default 90-day lifetime; introspect exp) embedding the specific run, scenario, and socket credentials. Always use Authorization: Bearer <token>./v3/driver_tracking/scenario/{scenario_id}/gps_points?latest_only=true
Get latest point per run for a scenario (or pass latest_only=false for all points). Accepts API key or Access token.
/v3/driver_tracking/gps_points?min_range=…&max_range=…
Get recorded GPS points for the authenticated runsheet context within a time window. Requires Runsheet token.
/v3/driver_tracking/gps_points
Create a new GPS point for the authenticated runsheet context. Requires Runsheet token.
When querying driver GPS points (GET /v3/driver_tracking/gps_points), use min_range and max_range to filter points by their recorded timestamp:
| Parameter | Type & Format | Default Value | Description |
|---|---|---|---|
min_range |
ISO 8601 UTC string2026-07-17T00:00:00Z |
8 hours ago (now - 8h) |
Start of the filtering window. Only GPS points recorded at or after this time are returned. |
max_range |
ISO 8601 UTC string2026-07-17T08:00:00Z |
Current time (now) |
End of the filtering window. Only GPS points recorded at or before this time are returned. Must be greater than or equal to min_range. |
Timestamps are parsed in ISO 8601 UTC format (e.g. 2026-07-17T00:00:00Z) and converted to Unix epoch timestamps internally for filtering.
curl "https://api.optimiser.app/v3/driver_tracking/scenario/456/gps_points?latest_only=true" \
-H "X-Tarot-API-Key: $TAROT_API_KEY"
import os, requests
response = requests.get(
"https://api.optimiser.app/v3/driver_tracking/scenario/456/gps_points",
params={"latest_only": "true"},
headers={"X-Tarot-API-Key": os.environ["TAROT_API_KEY"]},
)
response.raise_for_status()
points = response.json()
const url = new URL(
"https://api.optimiser.app/v3/driver_tracking/scenario/456/gps_points",
);
url.searchParams.set("latest_only", "true");
const response = await fetch(url, {
headers: { "X-Tarot-API-Key": process.env.TAROT_API_KEY },
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const points = await response.json();
curl -X POST "https://api.optimiser.app/v3/driver_tracking/gps_points" \
-H "Authorization: Bearer $RUNSHEET_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"run_id": 123,
"scenario_id": 456,
"organisation_id": 789,
"lat": -33.867798,
"lon": 151.166258,
"record_time": "2026-07-17T09:30:00Z"
}'
import os, requests
payload = {
"run_id": 123,
"scenario_id": 456,
"organisation_id": 789,
"lat": -33.867798,
"lon": 151.166258,
"record_time": "2026-07-17T09:30:00Z",
}
response = requests.post(
"https://api.optimiser.app/v3/driver_tracking/gps_points",
headers={"Authorization": f"Bearer {os.environ['RUNSHEET_TOKEN']}"},
json=payload,
)
response.raise_for_status()
const payload = {
run_id: 123,
scenario_id: 456,
organisation_id: 789,
lat: -33.867798,
lon: 151.166258,
record_time: "2026-07-17T09:30:00Z",
};
const response = await fetch(
"https://api.optimiser.app/v3/driver_tracking/gps_points",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.RUNSHEET_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
},
);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
Failure handling
| Status | Meaning |
|---|---|
401 | Missing, malformed or conflicting credentials; or authentication was not accepted for the requested operation. |
404 | No API route is available for the path. |
405 | The route exists but does not allow that method. |
429 | Gateway request or connection limit reached. Back off before retrying. |
502, 503, 504 | Temporary service availability or timeout failure. |
Inspect the response body for operation-specific error details, then retry only when the operation is safe to retry.
Further reading