Hazchem On The Go
Hazchem Connect Developers

Hazchem Connect API

Book, track and prove healthcare logistics from your own systems: lab LIS, pharmacy dispensing software, wholesaler order systems and hospital platforms. REST and JSON over HTTPS, signed webhooks, sandbox first.

Quick start

In this demo build the sandbox runs on this site at /api/v1. Use the published sandbox key hz_test_console_demo; other keys are refused.

curl
# Sandbox base URL (this demo build serves it on the same site)
export HZ_BASE="https://portal.haz-chem.co.za/api/v1"
export HZ_KEY="hz_test_console_demo"   # the published sandbox key

# 1. Check the sandbox is up (no key needed)
curl $HZ_BASE/health

# 2. Price a same-day specimen run, 25 km
curl -X POST $HZ_BASE/quotes \
  -H "x-api-key: $HZ_KEY" \
  -H "content-type: application/json" \
  -d '{"sku":"HZ-LAB-04","km":25,"priority":"same_day"}'

# 3. Book it (Idempotency-Key makes retries safe)
curl -X POST $HZ_BASE/jobs \
  -H "x-api-key: $HZ_KEY" \
  -H "Idempotency-Key: 7d1c5a7e-3f0b-4d55-9b0e-2c1b8f4a6e11" \
  -H "content-type: application/json" \
  -d '{"quote_id":"q_8k2m4p1x9z","pickup_site_id":"cli-0","dropoff_site_id":"lab-0"}'

# 4. Track it
curl $HZ_BASE/tracking/HZ-SBX1001 -H "x-api-key: $HZ_KEY"

Authentication

OAuth2 client credentials for machine-to-machine integrations: exchange your client id and secret for a short-lived JWT (15 minutes) carrying the scopes you need, then send Authorization: Bearer <token>.

Token request
curl -X POST https://api.haz-chem.co.za/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=$HZ_CLIENT_ID -d client_secret=$HZ_CLIENT_SECRET \
  -d scope="quotes:write jobs:write tracking:read"

# => {"access_token":"eyJ...","token_type":"Bearer","expires_in":900,"scope":"quotes:write jobs:write tracking:read"}

API keys are allowed for low-risk read scopes and EDI uploads. Send them in the x-api-key header. Sandbox keys start with hz_test_, live keys with hz_live_; a live key on the sandbox is refused.

ScopeGrantsTypical holder
quotes:writeCreate quotes and read service levelsPharmacy, wholesaler, e-commerce
jobs:write / jobs:readCreate, update, cancel, STAT upgrade; read jobsAll B2B clients
tracking:readTracking URL, ETA, driver first name and photo, vehicleAll clients, white-label pages
custody:read / temperature:readCustody events, seals, temperature tracesLabs, hospitals, wholesalers, auditors
pod:read / certificates:readPOD artefacts and certificatesClients and auditors
invoices:readInvoices and statementsFinance systems
admin:users / admin:sitesUsers, sites, cost centres, policiesHR and ERP systems
webhooks:manageRegister endpoints, rotate secrets, replay eventsIntegrators
partner:orders / partner:stockPharmacy quotes, order readiness, stock feedsPartners, wholesalers
telemetry:writeTemperature and telematics ingestionLogger gateways, CarTrack

Sandbox key and data

The sandbox accepts one published key: hz_test_console_demo. Any other hz_test_ value is refused with 401 invalid_api_key; live keys are refused with 403.

Quotes, jobs and cancellations you create are private to your caller (the key plus your hazchem-sandbox-session header, or your IP address when you send none) and expire after 6 hours without activity. Seeded sample jobs are shared and read-only: changing one creates a private copy for you.

Environments

EnvironmentBase URLKeysData
Sandbox/api/v1 on this site (dedicated host at launch)hz_test_console_demoFictional sites and jobs; no vehicles move; your data expires after 6 h idle
Livehttps://api.haz-chem.co.za/v1hz_live_... or OAuth2Real jobs, billed per the price book; hosted in South Africa

Idempotency

Every POST accepts an Idempotency-Key header and POST /v1/jobs requires one. Sending the same key again within 24 hours returns the original response with idempotent-replayed: true, so a network retry never double-books a STAT run.

Rate limits

Sandbox: 60 requests per minute per caller. Live: 600 requests per minute per client with burst allowance. Every response carries x-ratelimit-limit and x-ratelimit-remaining; over the limit you get 429 with a retry time. Use webhooks instead of polling for tracking.

Versioning and errors

The major version is in the path (/v1). Additive changes (new fields, new events) are non-breaking. Breaking changes ship as /v2 with a deprecation header and direct notice to registered developers before /v1 is withdrawn.

Amounts are integers in cents with currency: "ZAR" and a vat_inclusive flag. Times are ISO 8601. Errors use RFC 9457 problem+json with a stable code and a request_id to quote to support.

Error response
HTTP/1.1 422 Unprocessable Entity
content-type: application/problem+json

{
  "type": "https://portal.haz-chem.co.za/developers#errors-unknown_sku",
  "title": "Unknown SKU",
  "status": 422,
  "code": "unknown_sku",
  "detail": "No service HZ-LAB-99 in price book 2026.10-v1.0.",
  "request_id": "req_4gbktuz9ei"
}
StatusCodeMeaning
400idempotency_key_requiredIdempotency-Key required
400invalid_bodyInvalid body
400invalid_jsonInvalid JSON
401missing_api_keyMissing API key
401invalid_api_keyInvalid API key
403live_key_on_sandboxLive key used on sandbox
404not_foundEndpoint not found
404job_not_foundJob not found
404quote_not_foundQuote not found
404tracking_not_foundTracking reference not found
404certificate_not_foundCertificate not found
409already_cancelledAlready cancelled
409already_deliveredAlready delivered
409in_custodyParcel in custody
409certificate_pendingCertificate not issued yet
410quote_expiredQuote expired
422invalid_priorityInvalid priority
422invalid_timingInvalid timing
422not_a_deliveryNot a delivery service
422reason_requiredReason required
422unknown_siteUnknown site
422unknown_skuUnknown SKU
429rate_limitedToo many requests

Data minimisation: the API returns only the fields a scope needs. Medicine names never appear in courier or tracking scopes.