Armada Back to API home
Recommended for all new integrations

Automated Ordering API v2

A merchant-centric integration model for creating deliveries, estimating fees, managing branches, reading wallet status, and receiving structured webhooks using HMAC-signed requests.

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.

Unified Key Model

One merchant-level key per integration surface instead of separate branch-bound credentials.

Flexible Formats

Use branch-to-location or location-to-location requests depending on your operational flow.

Operational Visibility

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.

Authorization: Key main_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-Armada-Timestamp: 1744300800000
X-Armada-Signature: a1b2c3d4e5f6...
  • 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_format and destination_format: declare how each side is represented.
  • payment.amount and payment.type: represent collection or paid amount flow.
  • scheduled_date: optional ISO datetime for scheduled orders.

Read and cancel

  • GET /v2/deliveries/:id returns the latest order snapshot.
  • POST /v2/deliveries/:id/cancel requests 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"
  }'
Create delivery response
{
  "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

pending

Accepted and waiting for dispatch.

accepted

Assigned and acknowledged by Armada.

en_route

Driver is moving through the active delivery flow.

completed

Delivery completed successfully.

failed

Delivery could not be completed.

canceled

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

FormatRequired payload fields
branch_formatbranch_id
location_formatcontact_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"
    }
  }'
Example response
{
  "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/branches
GET /v2/branches
GET /v2/branches/:id
PUT /v2/branches/:id
DELETE /v2/branches/:id
Create branch body
{
  "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 = v2
  • x-armada-key-id = key identifier
  • x-armada-key-type = main
  • x-armada-timestamp = ISO timestamp
  • x-armada-webhook-id = unique webhook request id
  • x-armada-webhook-topic = topic name

Topics

  • order.updated — fired on any delivery status change
  • order.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

accepteden_routecompletedfailedcanceled
Order update payload example
{
  "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.