hayat help
Help › Industry workspaces

Shipping: merchant API, webhooks, COD payouts and proof of delivery

shipping.hayaterp.com/shipping/merchant-api ↗

For courier companies on Hayat — give merchants an API key to book and track parcels from their own website, push status changes to their webhook, pay many merchants' COD in one batch, and keep a photo and signature as proof of delivery.

These are additions to the Shipping workspace for courier companies. Merchants (your account customers) can book parcels from their own website, app or Hayat itself, get every status change pushed to them, and receive their COD in payout batches with an advice. Riders keep a photo and the receiver's signature with each delivery, and the consignment note carries a QR of the tracking page.

The screens are in Shipping: Merchant API & webhooks and COD payout batches, and on shipping.hayaterp.com in the same menu.

Who does what

Permission Typical person Can do
Shipping settings, ports, riders, tariffs and shipping reports (shipping.manage) Shipping admin, IT Make and revoke API keys; set up, test and retry merchant webhooks.
Shipping invoices, receipts, carrier bills, COD remittance and merchant billing (shipping.accounts) Shipping accounts Post COD payout batches and send payout advice.
Rider: own runsheet, delivery status, COD collected (shipping.delivery) Rider Take the delivery photo and signature in Hayat Shipping.
See jobs, parcels, voyages and the shipping dashboard (shipping.view) Counter, operations See the proof of delivery of a delivered parcel.

API keys

Shipping → Merchant API & webhooks → + API key.

  1. Choose the Merchant — a shipping customer with a courier account — and a Name (Website).
  2. Tick the Scopes — parcels.write (book, cancel), parcels.read (list, track, quote), cod.read (COD statement), webhooks.manage (set its own webhook). All four are ticked for a new key.
  3. Optional: Expires on.
  4. Create key. The New key (hsm_…) is shown once — Copy it and give it to the merchant safely. Hayat keeps only a fingerprint and the hint (hsm_…1a2b).
Merchant API keys and webhooks
Merchant API keys and webhooks

The list shows each key's merchant, hint, scopes, when and from where it was last used, its expiry and status. Revoke stops a key at once. The merchant app Hayat Shipping has Merchant API keys in its menu too (all scopes, no expiry).

The merchant API

Base address: https://<your server>/api/courier-api/v1 (for Hayat's own server, https://api.hayaterp.com/api/courier-api/v1). Every call sends the header X-Api-Key: hsm_…. A key sees only its own merchant's parcels.

Call Scope What it does
GET /me – The merchant and the key's scopes.
GET /cities – Destination cities.
POST /quote parcels.read The charges for a parcel: freight, COD fee, total.
POST /parcels parcels.write Book a parcel.
GET /parcels?from=&to=&status=&open=&page= parcels.read The merchant's parcels, paged.
GET /parcels/{code} parcels.read One parcel, by tracking code, CN number or the merchant's own reference.
GET /parcels/{code}/track parcels.read Status and every tracking event.
POST /parcels/{code}/cancel parcels.write Cancel while it is Booked and not invoiced.
GET /cod?from=&to= cod.read COD waiting, collected and paid out (up to one year).
GET / PUT / DELETE /webhook webhooks.manage The merchant's own webhook address.

Answers: 401 for a missing, wrong, revoked or expired key; 403 when the key lacks the scope or Shipping is switched off for your business.

Book a parcel

Booking follows the counter's rules: the merchant needs a courier account; at most 500 kg and 100 pieces; pickup from today up to 14 days ahead. The charges come from the merchant's own tariff, else the standard one, and are billed to the merchant's account. One pickup request is made per merchant and day, and your staff are notified.

```http POST /api/courier-api/v1/parcels X-Api-Key: hsm_… Content-Type: application/json

{ "reference": "ORD-10452", "service": "Overnight", "originCity": "Karachi", "receiverName": "Sana Iqbal", "receiverPhone": "03001234567", "receiverAddress": "House 12, Street 4, Gulberg III", "destinationCity": "Lahore", "contents": "Clothes", "pieces": 1, "weightKg": 0.8, "declaredValue": 4500, "codAmount": 4500, "remarks": "Call before delivery", "pickupDate": "2026-10-24" } ```

The answer gives the CN number, the 12-digit tracking code, the charges and two links — the shared consignment note (with the tracking QR) and the public tracking page:

json { "duplicate": false, "number": "SCN-…", "trackingCode": "…", "reference": "ORD-10452", "status": "Booked", "statusText": "Booked", "freight": 250, "codFee": 45, "charges": 295, "codAmount": 4500, "labelUrl": "https://my.hayaterp.com/d/…", "trackingUrl": "https://shipping.hayaterp.com/track/…", "pickup": { "number": "SPU-…", "date": "2026-10-24", "timeWindow": null } }

service is Overnight, SameDay or Economy. Send the merchant's own reference every time: booking the same reference again does not make a second parcel — it answers "duplicate": true with the earlier parcel.

Track a parcel

http GET /api/courier-api/v1/parcels/ORD-10452/track X-Api-Key: hsm_…

json { "number": "SCN-…", "trackingCode": "…", "status": "Delivered", "statusText": "Delivered", "deliveredAt": "2026-10-25T14:32:00+05:00", "receivedBy": "Sana", "failReason": null, "events": [ { "at": "2026-10-24T11:05:00+05:00", "status": "PickedUp", "label": "Picked up", "city": "Karachi", "note": null }, { "at": "2026-10-25T14:32:00+05:00", "status": "Delivered", "label": "Delivered", "city": "Lahore", "note": null } ] }

GET /cod answers waiting (COD still with riders), collected (collected, not paid out), payouts (paid out), their totals and the charges deducted.

Webhooks to merchants

A merchant with a webhook gets a push for every new tracking event of its parcels, within about a minute.

  1. Webhooks → + Webhook (or the merchant calls PUT /webhook). Choose the Merchant, the Address (https) and tick On. Save.
  2. The Webhook secret is shown once, with the signature rule — Copy it for the merchant. Issue a new signing secret on an existing webhook replaces it.
  3. Test sends a ping at once and shows the merchant server's answer.

Each push is a POST of JSON:

```http POST https://merchant.example/hooks/hayat Content-Type: application/json X-Hayat-Event: parcel.status X-Hayat-Delivery: 6f1c… X-Hayat-Timestamp: 1761384720 X-Hayat-Signature: sha256=9b2e…

{ "event": "parcel.status", "at": "2026-10-25T14:32:00+05:00", "trackingCode": "…", "number": "SCN-…", "reference": "ORD-10452", "status": "Delivered", "statusText": "Delivered", "city": "Lahore", "note": null, "codAmount": 4500, "codCollected": 4500, "deliveredAt": "2026-10-25T14:32:00+05:00", "receivedBy": "Sana", "failReason": null, "attempts": 1 } ```

The merchant checks X-Hayat-Signature = "sha256=" + hex(HMAC_SHA256(secret, X-Hayat-Timestamp + "." + raw body)) and rejects pushes older than 5 minutes. Any 2xx answer counts as accepted. Otherwise the push is tried again after 2, 4, 8… minutes (at most 12 hours apart), up to 12 times; a webhook that fails 50 times in a row is Switched off.

Log shows every delivery — event, status, tries, the next try and the answer — with Retry.

COD payout batches

When a rider collects COD, that money is owed to the merchant. Shipping → COD payout batches pays many merchants at once.

  1. Owed to merchants lists each merchant with collected COD not paid out: pay-to details, parcels, COD, Charges to deduct, Net and the oldest parcel.
  2. Tick merchants (each may get its own reference), or tick none to pay everyone owed.
  3. Choose the Date, Method (Bank, Raast, JazzCash), Reference and Notes, then Pay n merchant(s) or Pay everyone owed.
COD payout batches
COD payout batches

For each merchant the batch (SCP-…) makes an ordinary COD remittance (SCR-…), all in one step: account parcels not billed yet are billed, open courier invoices are taken out of the COD, and the net is paid. Open a batch to Send payout advice to all — by each merchant's usual channel, SMS, WhatsApp or email — or send and copy one merchant's advice. The advice lists each parcel (CN, tracking, receiver, city, delivered date, COD), the COD collected, the charges deducted, the net paid, the method and the reference. The Hayat Shipping app shows COD payouts (To pay and Batches) and sends the advice, but the batch itself is paid from the web.

Proof of delivery

In Hayat Shipping, when the rider records Delivered, the delivery sheet has Take photo and Signature (the receiver signs in the white box, then Use this signature). Both are optional and are sent with the delivery; the photo is checked before anything is posted.

  • On the web, a delivered parcel in Delivery status shows Proof of delivery: received by, the time, the rider, who recorded it, the photo and the signature. The app shows the same card on the parcel.
  • The public tracking page shows Delivered to the receiver's first name and the time, and the signature. The photo is never public, and the proof opens only by the 12-digit tracking code (not by the CN number, which runs in order).

QR on the consignment note

The printed or shared consignment note now ends with a QR of the public tracking link and the tracking code, so the receiver can scan it to follow the parcel.

Workflow

Merchant API booking and webhook pushes
Merchant API booking and webhook pushes
A COD payout batch
A COD payout batch

Where the money goes

Event Debit Credit
Parcel booked through the API — (charges billed to the merchant's account later)
COD collected by the rider 1010 Cash 2300 Customer advances (owed to the merchant)
Batch: unbilled parcels billed 1140 Client receivables 4520 Courier & delivery revenue
Batch: open courier invoices taken out of the COD 2300 Customer advances 1140 Client receivables
Batch: net COD paid 2300 Customer advances the method's account (1020 Bank, Raast or JazzCash)

See the Shipping workspace for the rest.