Authentication

All API requests require a Bearer token in the Authorization header:

HTTP Header
Authorization: Bearer tk_test_your_key_here
Test vs Live keys: Test keys (tk_test_*) work in sandbox mode. Live keys (tk_live_*) create real deliveries.

Quick Start

Get live delivery tracking running in 5 minutes.

Step 1: Create a delivery

When a customer places an order, create a delivery to get a tracking URL:

typescript
const response = await fetch('https://trackkitapi-production.up.railway.app/v1/deliveries', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer tk_test_your_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    pickup:  { address: 'Chicken Republic, Yaba, Lagos, Nigeria' },
    dropoff: { address: '12 Adeola Odeku, VI, Lagos, Nigeria' },
    externalId: 'ORDER-9842',
    metadata: {
      customerName: 'Tunde',
      items: ['Jollof Rice x2', 'Chicken x1']
    }
  })
})

const delivery = await response.json()
// { id, trackingCode: "TK-J8K2M1", trackingUrl, status: "PENDING", eta }

// Send tracking link to customer
sendSMS(customer.phone, `Track your order: ${delivery.trackingUrl}`)

Step 2: Assign a driver

typescript
await fetch(`https://trackkitapi-production.up.railway.app/v1/deliveries/${delivery.id}/assign`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer tk_test_your_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ driverId: 'driver_456' })
})

Step 3: Stream driver location

Call this from the driver app every 5-10 seconds:

typescript — driver app
navigator.geolocation.watchPosition(async (pos) => {
  await fetch(`https://trackkitapi-production.up.railway.app/v1/deliveries/${deliveryId}/location`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer tk_test_your_key',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      lat: pos.coords.latitude,
      lng: pos.coords.longitude,
      speed: pos.coords.speed,
      heading: pos.coords.heading
    })
  })
}, null, { enableHighAccuracy: true })

Step 4: Customer sees live tracking

The customer clicks the tracking URL and sees a real-time map with driver location, ETA countdown, status updates, and your branding. No code needed on the customer side.

Step 5: Receive webhooks

typescript
await fetch('https://trackkitapi-production.up.railway.app/v1/webhooks', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer tk_test_your_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://yourapp.com/webhooks/trackkit',
    events: ['delivery.status_changed', 'delivery.driver_assigned']
  })
})

Deliveries API

Full CRUD for deliveries with automatic geocoding, routing, and ETA calculation.

POST/v1/deliveriesCreate delivery
GET/v1/deliveriesList deliveries
GET/v1/deliveries/:idGet delivery
PATCH/v1/deliveries/:id/statusUpdate status
POST/v1/deliveries/:id/locationUpdate driver location
POST/v1/deliveries/:id/assignAssign driver

Create Delivery — Request Body

json
{
  "pickup":     { "address": "Yaba Tech, Lagos, Nigeria" },
  "dropoff":    { "address": "Victoria Island, Lagos, Nigeria" },
  "externalId": "ORDER-123",        // optional: your own order ID
  "driverId":   "driver_456",      // optional: assign immediately
  "metadata":   { "any": "data" }  // optional: arbitrary JSON
}
You can pass lat/lng instead of address for pickup/dropoff. If only an address is provided, it's geocoded automatically via Nominatim. Append "Nigeria" for best results with Lagos addresses.

Status Transitions

valid statuses
CONFIRMED · DRIVER_ASSIGNED · PICKUP_EN_ROUTE · PICKED_UP · DELIVERING · ARRIVING · DELIVERED · CANCELLED

Drivers API

Manage your driver fleet. Track online status and location.

POST/v1/driversCreate driver
GET/v1/driversList drivers
GET/v1/drivers/:idGet driver
POST/v1/drivers/:id/locationUpdate location
PATCH/v1/drivers/:id/statusSet online/offline

Create Driver

json
{
  "name":       "Emeka Obi",
  "phone":      "+2348012345678",   // optional
  "externalId": "DRV-100"            // optional: your own driver ID
}

Webhooks

Get notified when delivery events happen. All payloads are signed with HMAC-SHA256.

POST/v1/webhooksRegister webhook
GET/v1/webhooksList webhooks
DELETE/v1/webhooks/:idDelete webhook

Webhook Payload

json
{
  "event": "delivery.status_changed",
  "data": {
    "id": "clx7abc123",
    "trackingCode": "TK-J8K2M1",
    "status": "DELIVERED",
    "previousStatus": "ARRIVING"
  },
  "timestamp": "2026-03-20T14:30:00Z",
  "id": "wh_1710940200_abc123"
}

Verify Signature

Every webhook includes an x-trackkit-signature header:

typescript
const signature = request.headers['x-trackkit-signature']
const expected = crypto
  .createHmac('sha256', webhookSecret)
  .update(JSON.stringify(request.body))
  .digest('hex')

if (`sha256=${expected}` !== signature) {
  return res.status(401).send('Invalid signature')
}
EVENTFIRED WHEN
delivery.createdNew delivery created
delivery.status_changedStatus transitions
delivery.driver_assignedDriver assigned to delivery
delivery.location_updatedDriver location update received

Live Tracking

Customers can track deliveries in real-time via WebSocket or the tracking URL.

Tracking URL

Every delivery returns a trackingUrl. Share it with your customer via SMS, WhatsApp, or email. They see a live map with driver location, ETA, and status — branded with your logo and colors.

WebSocket

Connect to the WebSocket endpoint for real-time updates in your own UI:

javascript
const ws = new WebSocket('wss://trackkitapi-production.up.railway.app/ws/track/TK-J8K2M1')

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data)

  if (msg.type === 'location') {
    // { lat, lng, heading, speed, eta, distance }
    updateMap(msg.data)
  }
  if (msg.type === 'status') {
    // { status: "DELIVERING", eta: 8 }
    updateStatus(msg.data)
  }
}

Status Flow

PENDINGCONFIRMEDDRIVER_ASSIGNEDPICKUP_EN_ROUTEPICKED_UPDELIVERINGARRIVINGDELIVERED
Any status can also transition to CANCELLED

Rate Limits

Rate limits are enforced per tenant (API key), not per IP address.

PLANDELIVERIES/MOAPI CALLS/MINWEBHOOKS
Free5001001
Growth ($49/mo)5,0005005
Scale ($199/mo)50,0002,00020
Managed (custom)Unlimited10,000100
When you exceed the delivery limit, the API returns 429 limit_exceeded. Delivery counts reset automatically on the 1st of each month.

JavaScript / TypeScript SDK

The official SDK wraps the REST API and WebSocket for easy integration.

bash
npm install trackkit-sdk
typescript
import TrackKit from 'trackkit-sdk'

const tk = new TrackKit({ apiKey: 'tk_live_your_key' })

// Create a delivery
const delivery = await tk.deliveries.create({
  pickup:  { address: 'Yaba Tech, Lagos, Nigeria' },
  dropoff: { address: 'Victoria Island, Lagos, Nigeria' },
  metadata: { orderId: 'ORD-123' }
})

// Update driver location
await tk.deliveries.updateLocation(delivery.id, {
  lat: 6.4738, lng: 3.3952, speed: 35
})

// Real-time tracking
const unsub = tk.realtime.subscribe(delivery.trackingCode, {
  onLocation: (data) => console.log('Driver at:', data.lat, data.lng),
  onStatus:   (data) => console.log('Status:', data.status),
})
Published on npm as trackkit-sdk. Supports both CommonJS and ESM. Full TypeScript types included.