API reference
Base URL https://api.haz-chem.co.za/v1. Endpoints marked Sandbox can be called from the console in this build.
/v1/quotes
quotes:writeSandboxPrice a job from the price book: SKU, distance, priority, timing and parcels. Quotes hold for 15 minutes.
| Parameter | In | Type | Description |
|---|---|---|---|
| sku * | body | string | Price-book SKU, e.g. HZ-LAB-04 (same-day specimen) |
| km | body | number | Route distance. Extras apply beyond the SKU's included km |
| priority | body | enum | scheduled | same_day | stat | critical. STAT upgrades lab and blood SKUs |
| timing | body | enum | standard | after_hours (x1.5) | saturday (x1.3) | sunday (x2.0) |
| parcels | body | integer | R25.00 per additional parcel to the same address |
curl -X POST https://api.haz-chem.co.za/v1/quotes \
-H "Authorization: Bearer $HZ_TOKEN" \
-H "content-type: application/json" \
-d '{"sku":"HZ-LAB-04","km":25,"priority":"same_day","timing":"standard","parcels":1}'{
"sku": "HZ-LAB-04",
"km": 25,
"priority": "same_day",
"timing": "standard",
"parcels": 1
}{
"object": "quote",
"id": "q_8k2m4p1x9z",
"expires_at": "2026-10-12T09:45:00.000Z",
"sku": "HZ-LAB-04",
"priority": "same_day",
"km": 25,
"lines": [
{
"label": "Same-day specimen (4 h window), metro, incl. 15 km",
"amount_cents": 18500
},
{
"label": "Distance 10 km beyond 15 km at R9.00/km",
"amount_cents": 9000
}
],
"amount_cents": 27500,
"vat_cents": 4125,
"total_cents": 31625,
"currency": "ZAR",
"vat_inclusive": false,
"sla_minutes": 240,
"price_book_version": "2026.10-v1.0"
}/v1/quotes
quotes:writeSandboxList recent quotes and the quotable SKUs in the current price book.
curl https://api.haz-chem.co.za/v1/quotes \
-H "Authorization: Bearer $HZ_TOKEN"{
"object": "list",
"price_book_version": "2026.10-v1.0",
"data": [
{
"id": "q_8k2m4p1x9z",
"sku": "HZ-LAB-04",
"total_cents": 31625
}
],
"quotable_skus": [
{
"sku": "HZ-LAB-04",
"name": "Same-day specimen (4 h window), metro, incl. 15 km",
"unit": "per job",
"price_cents": 18500
}
]
}/v1/jobs
jobs:writeSandboxCreate a job from a quote or directly. Idempotency-Key is required; a repeated key returns the original job for 24 h.
| Parameter | In | Type | Description |
|---|---|---|---|
| Idempotency-Key * | header | string | Unique per booking attempt, e.g. a UUID |
| quote_id | body | string | Book an existing quote, or send sku/priority/km instead |
| pickup_site_id * | body | string | Sandbox sites: cli-0..8, lab-0..3, hos-0..3, ph-0..11, whl-0, bb-0 |
| dropoff_site_id * | body | string | Destination site id |
| cost_centre | body | string | Cost centre or expense code for the invoice |
curl -X POST https://api.haz-chem.co.za/v1/jobs \
-H "Authorization: Bearer $HZ_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "content-type: application/json" \
-d '{"sku":"HZ-LAB-05","priority":"stat","pickup_site_id":"cli-0","dropoff_site_id":"lab-0","cost_centre":"STAT"}'{
"sku": "HZ-LAB-05",
"priority": "stat",
"pickup_site_id": "cli-0",
"dropoff_site_id": "lab-0",
"cost_centre": "STAT"
}{
"id": "job-sbx1",
"ref": "HZ-SBX1001",
"object": "job",
"status": "booked",
"sku": "HZ-LAB-05",
"service": "STAT specimen (90-minute)",
"priority": "stat",
"tenant": {
"id": "t-lab",
"name": "Meridian Pathology (sample)"
},
"pickup": {
"site_id": "cli-0",
"name": "Laudium Family Practice"
},
"dropoff": {
"site_id": "lab-0",
"name": "Meridian Central Lab"
},
"parcels": 1,
"seal": null,
"un_number": "UN3373",
"temperature_range_c": null,
"km": 22,
"created_at": "2026-10-12T09:30:00.000Z",
"sla_due": "2026-10-12T11:00:00.000Z",
"delivered_at": null,
"cost_centre": "STAT",
"price": {
"amount_cents": 43100,
"currency": "ZAR",
"vat_inclusive": false
},
"tracking_url": "https://portal.haz-chem.co.za/track/HZ-SBX1001",
"certificate_url": null,
"webhook_events": [
"job.created"
]
}/v1/jobs
jobs:readSandboxList and filter jobs.
| Parameter | In | Type | Description |
|---|---|---|---|
| status | query | enum | booked | assigned | en_route_pickup | collected | in_transit | delivered | exception | cancelled |
| site | query | string | Pickup or drop-off site id |
| limit | query | integer | 1 to 100, default 20 |
curl https://api.haz-chem.co.za/v1/jobs \
-H "Authorization: Bearer $HZ_TOKEN"{
"object": "list",
"total": 16,
"data": [
{
"id": "job-sbx1",
"ref": "HZ-SBX1001",
"object": "job",
"status": "delivered",
"sku": "HZ-LAB-05",
"service": "STAT specimen (90-minute)",
"priority": "stat",
"tenant": {
"id": "t-lab",
"name": "Meridian Pathology (sample)"
},
"pickup": {
"site_id": "cli-0",
"name": "Laudium Family Practice"
},
"dropoff": {
"site_id": "lab-0",
"name": "Meridian Central Lab"
},
"parcels": 1,
"seal": null,
"un_number": "UN3373",
"temperature_range_c": null,
"km": 22,
"created_at": "2026-10-12T09:30:00.000Z",
"sla_due": "2026-10-12T11:00:00.000Z",
"delivered_at": null,
"cost_centre": "STAT",
"price": {
"amount_cents": 43100,
"currency": "ZAR",
"vat_inclusive": false
},
"tracking_url": "https://portal.haz-chem.co.za/track/HZ-SBX1001",
"certificate_url": null
}
],
"has_more": true
}/v1/jobs/{id}
jobs:readSandboxRetrieve one job by id or ref, with legs, parcels and status.
| Parameter | In | Type | Description |
|---|---|---|---|
| id * | path | string | Job id (job-11) or reference (HZ-261012070) |
curl https://api.haz-chem.co.za/v1/jobs/job-11 \
-H "Authorization: Bearer $HZ_TOKEN"{
"id": "job-sbx1",
"ref": "HZ-SBX1001",
"object": "job",
"status": "booked",
"sku": "HZ-LAB-05",
"service": "STAT specimen (90-minute)",
"priority": "stat",
"tenant": {
"id": "t-lab",
"name": "Meridian Pathology (sample)"
},
"pickup": {
"site_id": "cli-0",
"name": "Laudium Family Practice"
},
"dropoff": {
"site_id": "lab-0",
"name": "Meridian Central Lab"
},
"parcels": 1,
"seal": null,
"un_number": "UN3373",
"temperature_range_c": null,
"km": 22,
"created_at": "2026-10-12T09:30:00.000Z",
"sla_due": "2026-10-12T11:00:00.000Z",
"delivered_at": null,
"cost_centre": "STAT",
"price": {
"amount_cents": 43100,
"currency": "ZAR",
"vat_inclusive": false
},
"tracking_url": "https://portal.haz-chem.co.za/track/HZ-SBX1001",
"certificate_url": null,
"custody_events": 1
}/v1/jobs/{id}/cancel
jobs:writeSandboxCancel with a reason. Free before assignment; 50% of base once a driver is assigned. Collected parcels need a return job instead.
| Parameter | In | Type | Description |
|---|---|---|---|
| id * | path | string | Job id or ref |
| reason * | body | string | Shown to Control and on the invoice |
curl -X POST https://api.haz-chem.co.za/v1/jobs/job-11/cancel \
-H "Authorization: Bearer $HZ_TOKEN" \
-H "content-type: application/json" \
-d '{"reason":"Specimen not ready"}'{
"reason": "Specimen not ready"
}{
"id": "job-sbx1",
"ref": "HZ-SBX1001",
"object": "job",
"status": "cancelled",
"sku": "HZ-LAB-05",
"service": "STAT specimen (90-minute)",
"priority": "stat",
"tenant": {
"id": "t-lab",
"name": "Meridian Pathology (sample)"
},
"pickup": {
"site_id": "cli-0",
"name": "Laudium Family Practice"
},
"dropoff": {
"site_id": "lab-0",
"name": "Meridian Central Lab"
},
"parcels": 1,
"seal": null,
"un_number": "UN3373",
"temperature_range_c": null,
"km": 22,
"created_at": "2026-10-12T09:30:00.000Z",
"sla_due": "2026-10-12T11:00:00.000Z",
"delivered_at": null,
"cost_centre": "STAT",
"price": {
"amount_cents": 43100,
"currency": "ZAR",
"vat_inclusive": false
},
"tracking_url": "https://portal.haz-chem.co.za/track/HZ-SBX1001",
"certificate_url": null,
"cancellation": {
"reason": "Specimen not ready",
"fee_cents": 0,
"currency": "ZAR",
"rule": "Cancelled before assignment: no fee"
},
"webhook_events": [
"job.cancelled"
]
}/v1/tracking/{ref}
tracking:readSandboxTracking URL, ETA, driver first name and photo, vehicle and custody milestones. Never includes medicine names.
| Parameter | In | Type | Description |
|---|---|---|---|
| ref * | path | string | Job reference |
curl https://api.haz-chem.co.za/v1/tracking/HZ-261012000 \
-H "Authorization: Bearer $HZ_TOKEN"{
"ref": "HZ-261012000",
"status": "in_transit",
"tracking_url": "https://portal.haz-chem.co.za/track/HZ-261012000",
"eta_minutes": 22,
"driver": {
"first_name": "Sipho"
},
"vehicle": {
"registration": "THE GO 40 GP",
"last_position": {
"lat": -26.0193,
"lng": 27.8903
}
},
"events": [
{
"at": "2026-10-12T09:41:00.000Z",
"type": "sealed",
"note": "Tamper seal applied",
"seal": "HZ-S445330"
}
]
}/v1/jobs/{id}/custody
custody:readLive onlyHash-chained custody events with seals, positions and actors. Live API only.
curl https://api.haz-chem.co.za/v1/jobs/job-11/custody \
-H "Authorization: Bearer $HZ_TOKEN"{
"job_id": "job-11",
"chain_hash": "sha256:7b91e13b...",
"events": [
{
"at": "2026-10-12T08:12:00.000Z",
"type": "scanned",
"by": "Driver",
"note": "2 parcel(s) scanned",
"prev_hash": "sha256:19ac...",
"hash": "sha256:a4f0..."
}
]
}/v1/jobs/{id}/pod
pod:readLive onlyProof of delivery: recipient, signature and photo links, ID or OTP result. Live API only.
curl https://api.haz-chem.co.za/v1/jobs/job-11/pod \
-H "Authorization: Bearer $HZ_TOKEN"{
"job_id": "job-11",
"recipient": "Receiving desk",
"otp_verified": true,
"id_check": "over_14_confirmed",
"signature_url": "https://files.haz-chem.co.za/pod/...sig.png",
"photo_url": "https://files.haz-chem.co.za/pod/...jpg",
"delivered_at": "2026-10-12T10:02:00.000Z"
}/v1/certificates/{id}
certificates:readSandboxProof-of-Custody (POC-) or Proof-of-Cold-Chain (PCC-) certificate JSON with a public, redacted verify link.
| Parameter | In | Type | Description |
|---|---|---|---|
| id * | path | string | POC-0011, PCC-0012 or a delivered job id |
curl https://api.haz-chem.co.za/v1/certificates/job-11 \
-H "Authorization: Bearer $HZ_TOKEN"{
"id": "POC-0011",
"object": "certificate",
"type": "proof_of_custody",
"job_id": "job-11",
"issued_at": "2026-10-12T16:01:55.446Z",
"custody": {
"events": 7,
"seal": "HZ-S445330",
"chain_hash": "sha256:7b91e13b..."
},
"verify_url": "https://portal.haz-chem.co.za/verify/job-11"
}/v1/sites
admin:sitesLive onlySites, receiving hours and cost centres for your organisation. Live API only.
curl https://api.haz-chem.co.za/v1/sites \
-H "Authorization: Bearer $HZ_TOKEN"{
"object": "list",
"data": [
{
"id": "lab-0",
"name": "Meridian Central Lab",
"type": "lab",
"receiving_hours": "24/7",
"cost_centres": [
"Routes - Tshwane"
]
}
]
}/v1/webhooks
webhooks:manageLive onlyRegister a webhook endpoint for selected events. The signing secret is shown once.
curl -X POST https://api.haz-chem.co.za/v1/webhooks \
-H "Authorization: Bearer $HZ_TOKEN" \
-H "content-type: application/json" \
-d '{"url":"https://lis.example.co.za/hazchem/events","events":["job.assigned","pickup.completed","delivery.completed","temperature.excursion"]}'{
"url": "https://lis.example.co.za/hazchem/events",
"events": [
"job.assigned",
"pickup.completed",
"delivery.completed",
"temperature.excursion"
]
}{
"id": "wh_3f9a",
"url": "https://lis.example.co.za/hazchem/events",
"events": [
"job.assigned",
"pickup.completed",
"delivery.completed",
"temperature.excursion"
],
"secret": "whsec_test_...",
"status": "active"
}/v1/health
publicSandboxService status. No key needed.
curl https://api.haz-chem.co.za/v1/health \
-H "Authorization: Bearer $HZ_TOKEN"{
"status": "ok",
"environment": "sandbox",
"api_version": "v1",
"price_book_version": "2026.10-v1.0"
}