FeaturesPricingIntegrationsDevelopersContactSign in Start free trial
Developers

Build on QuickDispatch.

Two REST APIs, signed webhooks and a sandbox that never texts a real customer. Everything you can do in the dashboard, you can do from code.

Quickstart

Your first consignment in three calls.

01

Get a sandbox key

Couriers create keys under Developers → API keys. Shippers get theirs from their courier. Sandbox keys start qd_test_ and never send real messages.

# every request
Authorization: Bearer qd_test_4f9a0c1b2d3e5f60718293a4

# base URLs
Customer API  https://sandbox.api.quickdispatch.co.uk/v1
Admin API     https://sandbox.api.quickdispatch.co.uk/admin/v1
02

Create a consignment

Send the recipient, the items and how many pieces each arrives in. Use an Idempotency-Key so a retry never creates a duplicate.

curl -X POST https://sandbox.api.quickdispatch.co.uk/v1/consignments \
  -H "Authorization: Bearer $QD_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "reference": "OAK-48213",
  "recipient": {
    "name": "Sarah Khan", "phone": "+447700900123",
    "address": { "line1": "14 Headingley Avenue",
                 "town": "Leeds", "postcode": "LS6 2AB" } },
  "items": [ { "sku": "DIVAN-4FT6-GREY", "pieces": 2 } ],
  "service": { "crew": 2 }
}'

# 201 Created
{ "id": "con_8Kq2Lm", "status": "awaiting_scan", … }
03

Listen for updates

Register a webhook endpoint and verify the QD-Signature header on every event before trusting it.

// Node.js: verify a QuickDispatch webhook
import crypto from 'node:crypto';

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
  const age = Date.now() / 1000 - Number(parts.t);
  if (age > 300) return false; // older than 5 minutes
  const expected = crypto.createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
Conventions

The same rules everywhere.

Keys & scopes

Bearer keys, live and sandbox. Admin keys carry scopes such as routes:write; a missing scope returns 403 insufficient_scope.

Rate limits

120 requests a minute per Customer key, 300 per Admin key. RateLimit-* headers on every response and Retry-After on a 429.

Idempotency

Every POST takes an Idempotency-Key. Retries with the same key return the original result for 24 hours.

Pagination & errors

Lists take limit and starting_after and return has_more. Errors always look like {"error": {"code", "message", "param", "request_id"}}.

Async jobs

Route optimisation returns 202 with a job. Poll GET /jobs/{id} or listen for job.completed. Nothing reaches drivers until you publish.

Webhooks

Events, not polling.

Signed with HMAC-SHA256, retried with back-off for 24 hours, and replayable from the dashboard.

Customer API events
consignment.scannedPieces arrive at the depot
consignment.bookedRecipient booked a slot
consignment.out_for_deliveryOn a van, with tracking URL
consignment.deliveredDelivered with proof
consignment.failed_attemptAttempt failed, rebooking sent
Admin API events
order.scannedEvery piece is in
booking.reply_needs_reviewA reply needs a person
job.completedOptimisation finished
agent.suggestion_createdNew route agent suggestion
run.started · stop.failed · run.completedOn the road

Generate a client in any language.

Both APIs are described in OpenAPI 3.1. Point your favourite generator at the spec, or import it into Postman or Insomnia.

Admin API spec (YAML)Customer API spec (YAML)Talk to the API team