Before you start
- Sign up and create an API key under API keys with
rides:readandrides:write. - Set it as an environment variable:
export TTR_API_KEY="tk_live_..." - Save the script below as
create-delivery.mjs.
Create a delivery and print its tracking link
// Create a delivery with the Track That Ride API and print the customer's tracking link.
// Node.js 18+ (built-in fetch). Usage:
// TTR_API_KEY=tk_live_... node create-delivery.mjs
const API = 'https://trackthatride.com/api/v1';
const key = process.env.TTR_API_KEY;
if (!key) throw new Error('Set TTR_API_KEY to an API key with rides:read and rides:write');
async function ttr(path, options = {}) {
const res = await fetch(`${API}${path}`, {
...options,
headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json', ...options.headers },
});
const body = await res.json().catch(() => ({}));
if (!res.ok) {
// Errors carry `error`, and usually `code` (branch on it) and `message`.
throw new Error(`${res.status} ${body.code ?? body.error ?? ''}: ${body.message ?? JSON.stringify(body)}`);
}
return body;
}
// Pickup in two hours; estimated_pickup_time must be in the future.
const pickupAt = new Date(Date.now() + 2 * 60 * 60 * 1000).toISOString();
const ride = await ttr('/rides', {
method: 'POST',
body: JSON.stringify({
customer_name: 'Jane Example',
phone_number: '07700 900123',
email: 'jane@example.com', // the customer is emailed the tracking link
address: '10 Downing Street, London SW1A 2AA',
pickup_address: '1 Example Road, London E1 6AN',
pickup_contact_name: 'Front desk',
pickup_phone: '07700 900456',
estimated_pickup_time: pickupAt,
order_id: 'ORDER-1001',
}),
});
console.log(`Created delivery ${ride.id} (${ride.status})`);
console.log(`Tracking link: https://trackthatride.com/track/${ride.public_tracking_token}`);
// List the five most recent deliveries.
const { rides, pagination } = await ttr('/rides?limit=5&sortBy=created_at&sortOrder=desc');
console.log(`Total: ${pagination.total}. Latest:`);
for (const r of rides) console.log(` #${r.id} ${r.status.padEnd(11)} ${r.customer_name}`);
Run it with node create-delivery.mjs. You should see something like:
Created delivery 123 (pending)
Tracking link: https://trackthatride.com/track/AbC...xyz
Total: 14. Latest:
#123 pending Jane Example
Errors are thrown with the status and the API’s code, for example 401 Invalid API key or
403 Insufficient permissions. The delivery stays pending until a driver is assigned, which you can do in the
dashboard or with POST /api/v1/rides/{id}/assign-driver.
Receive and verify webhooks
Register a webhook (see webhooks) and keep the secret from the response. This server checks the
X-Webhook-Signature header against an HMAC-SHA256 of the raw body before trusting anything in it:
// Receive and verify Track That Ride webhooks. Node.js 18+, no dependencies.
// Usage: TTR_WEBHOOK_SECRET=whsec_... node webhook-receiver.mjs
// Then register https://<your-host>/hooks/ttr with POST /api/v1/webhooks.
import crypto from 'node:crypto';
import http from 'node:http';
const SECRET = process.env.TTR_WEBHOOK_SECRET;
if (!SECRET) throw new Error('Set TTR_WEBHOOK_SECRET to the secret returned when you created the webhook');
function verify(rawBody, header) {
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex');
const received = String(header ?? '');
return received.length === expected.length && crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
}
http
.createServer((req, res) => {
if (req.method !== 'POST' || req.url !== '/hooks/ttr') {
res.writeHead(404).end();
return;
}
const chunks = [];
req.on('data', (c) => chunks.push(c));
req.on('end', () => {
const raw = Buffer.concat(chunks); // sign-check the raw bytes, before parsing
if (!verify(raw, req.headers['x-webhook-signature'])) {
res.writeHead(401).end();
return;
}
let event;
try {
event = JSON.parse(raw.toString('utf8'));
} catch {
res.writeHead(400).end(); // signed but not JSON: reject instead of crashing the process
return;
}
res.writeHead(200).end(); // answer in under 30 seconds; do slow work afterwards
console.log(`${event.event_type} ride ${event.ride_id}: ${event.data?.status ?? ''}`);
if (event.event_type === 'delivery.completed') {
console.log(` delivered; tracking page https://trackthatride.com/track/${event.tracking_code}`);
}
});
})
.listen(3000, () => console.log('Listening on http://localhost:3000/hooks/ttr'));
What we tested
These scripts are kept in the examples/node folder of our repository and run against the live API: a request with an invalid
key returns the API’s 401 error, and the receiver accepts a correctly signed request and rejects a bad signature.