Overview
v2 replaces the older branch-scoped and app-token-first flow with merchant-level keys. The same key can create deliveries, run estimations, manage branches, inspect wallet state, and configure webhooks.
One merchant-level key per integration surface instead of separate branch-bound credentials.
Use branch-to-location or location-to-location requests depending on your operational flow.
Wallet balance, warning thresholds, delivery events, and driver updates all live in the same integration model.
Authentication
Generate keys from the Armada Business App under Automated Ordering. Each request must include the API key, a millisecond timestamp, and an HMAC-SHA256 signature.
- Base URL:
https://api.armadadelivery.com - The secret is shown only once when the key is created. Store it securely.
- Unsigned, expired, or malformed requests are rejected with
401. - Request bodies must be signed exactly as sent. Any JSON mutation after signing invalidates the request.
Request Signing
Signature formula
Build the payload as timestamp.METHOD.path.body.
Use an empty string for body on requests without a payload.
- Timestamp must be a Unix timestamp in milliseconds.
- Method must match the actual HTTP verb sent to Armada.
- Path must be the request path only, for example
/v2/deliveries. - Timestamp skew greater than 30 seconds is rejected for replay protection.
const crypto = require('crypto');
function createSignature(secret, timestamp, method, path, body = '') {
const payload = `${timestamp}.${method.toUpperCase()}.${path}.${body}`;
return crypto.createHmac('sha256', secret).update(payload).digest('hex');
}
const body = JSON.stringify({
reference: 'order-100245',
origin_format: 'branch_format',
origin: { branch_id: '66af6f6c2f85f4b4c36f2031' },
destination_format: 'location_format',
destination: {
contact_name: 'John Doe',
contact_phone: '+96590000000',
latitude: 29.3759,
longitude: 47.9774,
first_line: 'Salmiya, Block 5, Street 3'
},
payment: { amount: 4.5, type: 'paid' }
});
const timestamp = Date.now().toString();
const path = '/v2/deliveries';
const signature = createSignature(
'your-secret-uuid',
timestamp,
'POST',
path,
body
);
const headers = {
Authorization: 'Key main_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'X-Armada-Timestamp': timestamp,
'X-Armada-Signature': signature,
'Content-Type': 'application/json'
};Orders
Create deliveries with POST /v2/deliveries. The selected formats determine
which fields are required in origin and destination.
Common fields
reference: your idempotent external reference for reconciliation.origin_formatanddestination_format: declare how each side is represented.payment.amountandpayment.type: represent collection or paid amount flow.scheduled_date: optional ISO datetime for scheduled orders.
Read and cancel
GET /v2/deliveries/:idreturns the latest order snapshot.POST /v2/deliveries/:id/cancelrequests cancellation before completion.- Webhook delivery remains the primary way to receive ongoing state changes.
curl -X POST "https://api.armadadelivery.com/v2/deliveries" \
-H "Authorization: Key main_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Armada-Timestamp: 1744300800000" \
-H "X-Armada-Signature: a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"reference": "order-100245",
"origin_format": "branch_format",
"origin": {
"branch_id": "66af6f6c2f85f4b4c36f2031"
},
"destination_format": "location_format",
"destination": {
"contact_name": "John Doe",
"contact_phone": "+96590000000",
"latitude": 29.3759,
"longitude": 47.9774,
"first_line": "Salmiya, Block 5, Street 3"
},
"payment": {
"amount": 4.5,
"type": "paid"
},
"scheduled_date": "2026-04-20T10:30:00Z"
}'{
"code": "A1B2C3",
"status": "pending",
"test_mode": false,
"amount": 4.5,
"delivery_fee": 1.25,
"currency": "KWD",
"created_at": "2026-04-10T07:45:00.000Z",
"customer": {
"name": "John Doe",
"phone": "+96590000000",
"address": "Salmiya, Block 5, Street 3",
"latitude": 29.3759,
"longitude": 47.9774
},
"driver": {
"name": "",
"phone": "",
"latitude": null,
"longitude": null
},
"logistics": {
"estimated_distance": 1200,
"estimated_duration": 900,
"tracking_url": "https://tracking.armadadelivery.com/xxxxxxxx",
"pickup_qr_url": "https://tracking.armadadelivery.com/qr/xxxxxxxx"
}
}Status lifecycle
Accepted and waiting for dispatch.
Assigned and acknowledged by Armada.
Driver is moving through the active delivery flow.
Delivery completed successfully.
Delivery could not be completed.
Delivery was canceled before completion.
Origin & Destination Formats
v2 supports more than a simple branch-to-customer flow. Choose the format pair that matches the real operational handoff you want Armada to run.
Branch to location
Use origin_format = branch_format with origin.branch_id when pickup starts from a saved merchant branch.
This is the standard store-to-customer flow.
Location to location
Use origin_format = location_format and destination_format = location_format when pickup and dropoff are both ad hoc coordinates and contacts.
This covers concierge, courier, and runner-style delivery flows.
Required fields by format
| Format | Required payload fields |
|---|---|
| branch_format | branch_id |
| location_format | contact_name, contact_phone, latitude, longitude, first_line |
Estimation
Call POST /v2/deliveries/estimate with the same origin and destination structure you plan to use for order creation.
This is especially useful for location-to-location flows where pickup does not come from a saved branch.
curl -X POST "https://api.armadadelivery.com/v2/deliveries/estimate" \
-H "Authorization: Key main_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "X-Armada-Timestamp: 1744300800000" \
-H "X-Armada-Signature: a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"origin_format": "location_format",
"origin": {
"contact_name": "Store Runner",
"contact_phone": "+96590000001",
"latitude": 29.3721,
"longitude": 47.9838,
"first_line": "Hawally, Tunisia St"
},
"destination_format": "location_format",
"destination": {
"contact_name": "Jane Doe",
"contact_phone": "+96590000002",
"latitude": 29.3375,
"longitude": 47.9478,
"first_line": "Salwa, Street 1"
}
}'{
"delivery_fee": 1.25,
"estimated_pickup_at": "2026-04-10T08:00:00.000Z",
"estimated_delivery_at": "2026-04-10T08:15:00.000Z"
}Branches
Branches are merchant resources in v2. They are no longer tied to separate branch-scoped keys.
POST /v2/branchesGET /v2/branchesGET /v2/branches/:idPUT /v2/branches/:idDELETE /v2/branches/:id{
"name": "Sharq Branch",
"phone": "+9651801801",
"latitude": 29.3782,
"longitude": 47.9904
}Wallet
Use GET /v2/wallet to retrieve the merchant wallet balance and the low-balance warning level that webhook thresholds can build on.
{
"balance": 24.5,
"warning_balance_level": 10,
"currency": "KWD"
}Per-key low-balance webhook thresholds can be configured from the business app even if the merchant has a broader wallet warning limit.
Webhooks
Webhooks are configured per key from the business app. That makes it possible to route different keys to different environments or downstream systems.
Headers
x-armada-api-version=v2x-armada-key-id= key identifierx-armada-key-type=mainx-armada-timestamp= ISO timestampx-armada-webhook-id= unique webhook request idx-armada-webhook-topic= topic name
Topics
order.updated— fired on any delivery status changeorder.location.updated— recurrent driver location updates while en route (configurable interval)wallet.balance_low— fired when wallet balance drops below the configured threshold
Delivery events
{
"code": "TEST123",
"status": "pending",
"amount": 0,
"delivery_fee": 0,
"currency": "KWD",
"customer": {
"name": "Webhook Tester",
"phone": "+96500000000",
"address": "Test Address",
"latitude": 29.3759,
"longitude": 47.9774
},
"logistics": {
"estimated_distance": 1200,
"estimated_duration": 900,
"tracking_url": "https://tracking.armadadelivery.com/test",
"pickup_qr_url": "https://tracking.armadadelivery.com/test/qr"
}
}Errors & Notes
Common error classes
401: missing key, expired timestamp, or invalid HMAC signature.400: invalid payload shape, unsupported format combination, or required fields missing.404: referenced branch or resource was not found.
Implementation notes
- Keep the exact JSON string used for signing and sending in sync.
- Use estimations before creating scheduled or ad hoc location-to-location deliveries.
- Prefer webhooks for runtime updates instead of polling the delivery resource.