Skip to main content

Developer Guide – Integrating with Delyva API

You are here:
Estimated reading time: 6 min

Overview: This guide explains how to integrate with Delyva’s delivery API across two models (Store/Marketplace and SaaS/Platform) and covers the key endpoints to quote services, create/process orders, print labels, track deliveries, embed a live map with ETA, and receive webhooks. Examples use curl, Node.js, and PHP. .


Table of Contents

  1. Integration Models
  2. Recommended Settings for SaaS/Platform
  3. Base URL & Authentication
  4. Quickstart
  5. Price Quote
  6. Create Order (Draft)
  7. Process / Confirm Order
  8. Get Order Details
  9. Print Label
  10. Cancel Order
  11. Webhooks
  12. Embeddable Live Map with ETA
  13. Add-Ons: COD & Insurance
  14. Error Handling
  15. Common Service Types
  16. Sandbox vs Production
  17. Postman Collection Snippet

1) Integration Models

Store / Marketplace

  • One Delyva account managed by the system owner.
  • All merchants use the owner’s account (shared credentials).
  • Billing is direct between system owner and Delyva.

SaaS / Platform

  • Each merchant/subscriber has their own Delyva account and credentials.
  • Billing is direct between each merchant and Delyva.
  • Revenue share: SaaS platform earns 1% of order amount (handled by Delyva).

2) Recommended Settings for SaaS/Platform

Create a settings screen for each merchant to store their Delyva configuration:

  • API Parameters
    • Company code — text
    • Company ID — text
    • User ID — text
    • Customer ID — text/number
    • Item Type — select (PARCEL/PACKAGE/BULKY)
  • Checkout Rates
    • Enable/Disable — checkbox
    • Checkout Rates Adjustment
      • Adjustment type — select: Mark-up / Discount
      • Percentage rate — number (0–100)
      • Flat rate — number (0–100)
      • Formula: Delivery rate = service price + (% of service price) + flat rate
    • Free shipping threshold — number (0 = disable)

3) Base URL & Authentication

Base URL: https://api.delyva.app/v1.0

Headers (all requests):

Content-Type: application/json
X-Delyvax-Access-Token: <YOUR_API_KEY>

Get your API Key under Customer Portal → Settings → API Integrations. For webhook verification, retrieve apiSecret from GET /user → user.apiSecret.


4) Quickstart

  1. Create/locate your API Key in the portal.
  2. (Optional) Get apiSecret via GET /user.
  3. Run a Price Quote.
  4. Create Order with process: false (draft).
  5. Process the draft when shipment is ready.
  6. Get Order Details to read consignmentNo.
  7. Print Label (PDF).
  8. Subscribe to Webhooks for status updates.
  9. Embed Live Map with ETA (only for hyperlocal delivery – eg: Instant delivery, same-day delivery, or own fleet delivery).

5) Price Quote (Get services & rates)

curl

curl -X POST "https://api.delyva.app/v1.0/service/instantQuote" \
  -H "Content-Type: application/json" \
  -H "X-Delyvax-Access-Token: $DELYVA_API_KEY" \
  -d '{
    "customerId": 123,
    "origin": {"address1":"28 Jalan 5","city":"Kajang","state":"Selangor","postcode":"43000","country":"MY"},
    "destination": {"address1":"F-11-19 Pacific Place","city":"Petaling Jaya","state":"Selangor","postcode":"47301","country":"MY"},
    "weight": {"unit":"kg","value":0.9},
    "itemType": "PARCEL"
  }'

Node.js (axios)

const axios = require('axios');

(async () => {
  const res = await axios.post(
    'https://api.delyva.app/v1.0/service/instantQuote',
    {
      customerId: 123,
      origin: { address1: "28 Jalan 5", city: "Kajang", state: "Selangor", postcode: "43000", country: "MY" },
      destination: { address1: "F-11-19 Pacific Place", city: "Petaling Jaya", state: "Selangor", postcode: "47301", country: "MY" },
      weight: { unit: "kg", value: 0.9 },
      itemType: "PARCEL"
    },
    { headers: { "X-Delyvax-Access-Token": process.env.DELYVA_API_KEY } }
  );
  console.log(res.data);
})();

PHP (cURL)

<?php
$ch = curl_init('https://api.delyva.app/v1.0/service/instantQuote');
$data = [
  "customerId" => 123,
  "origin" => ["address1" => "28 Jalan 5", "city" => "Kajang", "state" => "Selangor", "postcode" => "43000", "country" => "MY"],
  "destination" => ["address1" => "F-11-19 Pacific Place", "city" => "Petaling Jaya", "state" => "Selangor", "postcode" => "47301", "country" => "MY"],
  "weight" => ["unit" => "kg", "value" => 0.9],
  "itemType" => "PARCEL"
];
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Content-Type: application/json',
    'X-Delyvax-Access-Token: ' . getenv('DELYVA_API_KEY')
  ],
  CURLOPT_POSTFIELDS => json_encode($data)
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;

Example Response (truncated)

{
  "services": [
    { "serviceCompany": { "companyCode": "JNT-NDD", "name": "J&T Express Next-Day" }, "price": { "amount": 7.90, "currency": "MYR" } },
    { "serviceCompany": { "companyCode": "GRAB-INSTANT", "name": "GrabExpress Instant" }, "price": { "amount": 12.50, "currency": "MYR" } }
  ]
}

Tip: Save services[i].serviceCompany.companyCode to use when creating the order.


6) Create Order (Draft)

POST /v1.0/order
{
  "customerId": 123,
  "process": false,
  "serviceCode": "GRAB-INSTANT",
  "source": "your-system",
  "extId": "vendor-123",
  "referenceNo": "ORDER-2025-0001",
  "note": "Handle with care",
  "waypoint": [
    {
      "type": "PICKUP",
      "scheduledAt": "2025-09-09T12:00:00+0800",
      "inventory": [
        { "name": "Mee Kari", "type": "PARCEL", "price": {"amount":"10.50","currency":"MYR"}, "weight": {"value":1,"unit":"kg"},
          "dimension": {"unit":"cm","width":10,"length":15,"height":5}, "quantity":1 }
      ],
      "contact": { "name":"Test Sender","email":"[email protected]","phone":"60124433300",
        "address1":"157, Jalan Ampang","city":"Kuala Lumpur","state":"Wilayah Persekutuan","postcode":"55000","country":"MY",
        "coord":{"lat":"3.013478","lon":"101.779682"} }
    },
    {
      "type": "DROPOFF",
      "scheduledAt": "2025-09-09T13:00:00+0800",
      "inventory": [
        { "name": "Mee Kari", "type": "PARCEL", "price": {"amount":"10.50","currency":"MYR"}, "weight": {"value":1,"unit":"kg"},
          "dimension": {"unit":"cm","width":10,"length":15,"height":5}, "quantity":1 }
      ],
      "contact": { "name":"Mr Receiver","email":"[email protected]","phone":"60124433300",
        "address1":"MRT Sungai Jernih (SBK33)","address2":"1, Kampung Sungai Kantan","city":"Kajang","state":"Selangor","postcode":"43000","country":"MY",
        "coord":{"lat":"3.11100853226846","lon":"101.58726936290537"} }
    }
  ]
}

Example Response (truncated)

{ "id": 9876543, "statusCode": 100, "serviceCode": "GRAB-INSTANT" }

Save the id for processing, label printing, and tracking.


7) Process / Confirm Order

POST /v1.0/order/9876543/process
{ "serviceCode": "GRAB-INSTANT", "originScheduledAt": "2025-09-09T12:00:00+0800", "destinationScheduledAt": "2025-09-09T13:00:00+0800" }

Example Response

{ "id": 9876543, "statusCode": 200, "message": "Order processed" }

8) Get Order Details

GET /v1.0/order/9876543

Example Response (truncated)

{
  "id": 9876543,
  "statusCode": 210,
  "consignmentNo": "MYJNT123456789",
  "trackingNo": "DLV-ABC12345",
  "personnel": { "name": "Driver Ali", "phone": "60123456789" }
}

Single:

GET /v1.0/order/9876543/label?companyId=123

Multiple:

GET /v1.0/order/111,222,333/label?companyId=123

Packing list:

GET /v1.0/order/9876543/label?companyId=123&packingList=true

10) Cancel Order

POST /v1.0/order/9876543/cancel
{}

Response

{ "id": 9876543, "statusCode": 90, "message": "Order cancelled" }

Rules (summary):

  • Courier (NDD): cancel before statusCode 110 or contact support after label printed.
  • Instant/Same-Day: cancel before statusCode 200 (after driver accepts).


11) Webhooks

You can use webhook subscriptions to receive notifications about particular events. After you’ve subscribed to a webhook, you can let your app execute code immediately after specific events occur, instead of having to make API calls periodically to check their status. For example, you can rely on webhooks to trigger an action in your app when order tracking has been updated, or when an order is updated. By using webhook subscriptions you can make fewer API calls overall, which makes sure that your apps are more efficient and update quickly.

How it works?

After you configure a webhook subscription, the events that you specified will trigger a webhook notification each time they occur. This notification contains a JSON payload, and HTTP headers that provide context. For example, the order.created webhook includes the following headers:

X-Delyvax-Event: order.created
X-Delyvax-Hmac-Sha256: 0eGwdG9HEY/jFARUIr0BlYxhrp2dFRb5T3+ceQ3YUso=

Your application needs to respond with 200 (Success) within 30 seconds or it will assume the request has failed and will retry POSTing again several times an hour. DelyvaX will stop trying after 10 failed attempts.

Verifying webhook

Webhooks are verified by calculating a digital signature. Each webhook request includes a base64-encoded X-Delyvax-Hmac-SHA256 header, which is generated using the user’s apiSecret (user.apiSecret) along with the data sent in the request.

To verify that the request came from DelyvaX, compute the HMAC digest according to the following algorithm and compare it to the value in the X-Delyvax-Hmac-SHA256 header. If they match, then you can be sure that the webhook was sent from DelyvaX.

POST /v1.0/webhook/subscribe
{
  "event": "order_tracking.update",
  "url": "https://yourapp.com/webhooks/delyva",
  "secret": "<shared-secret>"
}

List of Supported Webhook Events

Event Descriptions
order.created Order successfully created. (statusCode = 100)
order.failed Order failed to create.
order.updated Order details have updated. Returns full order object (same as GET /order/{id}).
order_tracking.update There is a new tracking activity.
order_tracking.change Same as order_tracking.update event, but only triggered when statusCode changed.

Example payload (order_tracking.update)

{
  "event": "order_tracking.update",
  "timestamp": "2025-09-09T12:35:10+0800",
  "orderId": 9876543,
  "trackingNo": "DLV-ABC12345",
  "statusCode": 320,
  "status": "Out for delivery",
  "proof": null,
  "signature": "base64-hmac-with-apiSecret"
}

Node.js verification

const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());

app.post('/webhooks/delyva', (req, res) => {
  const payload = JSON.stringify(req.body);
  const signature = req.headers['x-delyvax-hmac-sha256'];
  const expected = crypto.createHmac('sha256', process.env.DELYVA_API_SECRET)
    .update(payload).digest('base64');
  if (signature !== expected) return res.status(401).send('Invalid signature');
  // handle event...
  res.send('ok');
});

app.listen(3000, () => console.log('listening'));

Simulate Webhook Updates (Testing)

For sandbox testing, you can simulate webhook events against your own test orders without waiting for a real courier status update.

Use the Delyva Sandbox Webhook Simulator:

https://dx-integration-sandbox.pages.dev/

How it works:

  • Enter your test consingmentNo or trackingNo.
  • Select the event (e.g. Pickup Success, Out for Delivery, Delivered).
  • Send the simulated event — it will POST a webhook payload to your subscribed endpoint.
  • Verify your system receives and processes the update as expected.

This is useful for end-to-end testing of webhook handling before going live.

12) Embeddable Live Map with ETA

Show this when:

  • On the way to pick up — after driver is accepted/assigned and before pickup is completed.
  • On the way to deliver — after pickup is completed and before delivered/failed/cancelled.

URL:

https://my.delyva.app/track/rmap?trackingNo={order.consignmentNo}

iframe example

<iframe
  src="https://my.delyva.app/track/rmap?trackingNo=MYJNT123456789"
  style="width:100%;height:520px;border:0;"
  allowfullscreen
  loading="lazy"></iframe>

Branding: Custom pin icons/branding available for DelyvaNow+ and DelyvaX subscribers.


13) Add-Ons: COD & Insurance

Quote with add-ons (re-quote specific service to get adjusted price):

"serviceAddon": [
  { "id": -1, "value": "500" },   // COD amount (e.g., 500 MYR)
  { "id": -3, "value": "400" }    // Insurance value (e.g., 400 MYR)
]

Create order with add-ons:

"cod": { "currency": "MYR", "amount": 500 },
"insurance": { "currency": "MYR", "amount": 400 }

14) Error Handling

{
  "error": true,
  "code": "VALIDATION_ERROR",
  "message": "destination.postcode is required",
  "details": { "destination.postcode": ["required"] }
}

15) Common Service Types

  • NDD — Next Day Delivery (pickup)
  • NDD-DROP — Next Day Delivery (drop-off)
  • COD-NDD — NDD with COD (pickup)
  • COD-NDD-DROP — NDD with COD (drop-off)
  • INSTANT — ~1–2 hours
  • SD — Same day (~3–4 hours)
  • INTERNATIONAL
  • MOTO — Motorcycle transport

16) Sandbox vs Production

  • API Base: https://api.delyva.app/v1.0
  • Production Portal: https://my.delyva.app/customer
  • Sandbox/Dev Portal: https://trydx.delyva.app/customer
  • CDN (labels/assets): https://cdn.delyva.app

17) Postman Collection Snippet (Import)

{
  "info": {
    "name": "Delyva API Examples",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "Instant Quote",
      "request": {
        "method": "POST",
        "header": [
          {"key":"Content-Type","value":"application/json"},
          {"key":"X-Delyvax-Access-Token","value":"{{apiKey}}"}
        ],
        "body": {
          "mode": "raw",
          "raw": "{\\n  \\"customerId\\": 123,\\n  \\"origin\\": {\\"address1\\": \\"28 Jalan 5\\", \\"city\\": \\"Kajang\\", \\"state\\": \\"Selangor\\", \\"postcode\\": \\"43000\\", \\"country\\": \\"MY\\"},\\n  \\"destination\\": {\\"address1\\": \\"F-11-19 Pacific Place\\", \\"city\\": \\"Petaling Jaya\\", \\"state\\": \\"Selangor\\", \\"postcode\\": \\"47301\\", \\"country\\": \\"MY\\"},\\n  \\"weight\\": {\\"unit\\": \\"kg\\", \\"value\\": 0.9},\\n  \\"itemType\\": \\"PARCEL\\"\\n}"
        },
        "url": { "raw": "https://api.delyva.app/v1.0/service/instantQuote",
          "protocol":"https","host":["api","delyva","app"],"path":["v1.0","service","instantQuote"] }
      }
    }
  ]
}
Views: 3135