Guides
Delivery companies
Offer your delivery service at checkout with its price, and report each shipment so the merchant and the customer can follow it.
What your app needs
| You want to | Scope | Where |
|---|---|---|
| Appear at checkout with your price | shipping.options:write | POST /delivery-options |
| Report the company, tracking number and stage | orders.shipment:write | PATCH /orders/{id}/shipment |
| See paid orders, items, weight and amounts | orders:read | GET /orders and the order.paid event |
| Get the recipient's name, phone and address | customers:read | Inside the order |
| Get the store's pickup address | store:read | GET /store |
| Tell the customer about a stage | customers.notify:write | POST /orders/{id}/notifications |
Offer delivery at checkout
Send your whole list. It replaces what your app sent before.
curl -X POST "https://larm.sa/stores/$STORE_ID/v1/delivery-options" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"options":[{"key":"one-hour","company_name":"Fast Courier","label":"Delivery within an hour","eta":"Within an hour","price":"25.00","cities":[]}]}'- The merchant decides. A new option stays off until the merchant turns it on in shipping settings. It goes back to off when you change its price or company name; other edits keep it on.
- The price is fixed. Each option has one price from 0 to 1000 SAR, sent as a string. Larm does not call your server for a live rate.
- Cities. An empty
citieslist means every city in Saudi Arabia. To limit an option, list each city in Arabic, the way customers write it in their address; an English name does not match. Options are not offered for addresses outside Saudi Arabia. - It can leave checkout. Your options stop showing when your app is suspended or uninstalled, or the merchant revokes the scope.
Read enabled from GET /delivery-options to see what the merchant turned on.
When a customer chooses your option
The price is added to the order's totals.shipping, and the order carries your option:
"delivery": {
"source": "app",
"app_id": "1f2e3d4c-5b6a-4978-8695-a4b3c2d1e0f9",
"option_id": "one-hour",
"label": "Delivery within an hour",
"carrier": "Fast Courier",
"status": "pending",
"tracking_number": null,
"tracking_url": null,
"updated_at": "2026-11-02T09:30:00.000Z"
}Listen for order.paid and start delivery only when delivery.app_id is your app. delivery shows any shipment, whoever handles it, and delivery.source says who: app, merchant or larm. It is null before any shipment.
Items carry sku, options and weight_grams, and with customers:read the order carries customer.phone and shipping_address. Collect from pickup_address in GET /store.
Report the shipment
curl -X PATCH "https://larm.sa/stores/$STORE_ID/v1/orders/200123/shipment" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"status":"out_for_delivery","tracking_number":"FC-20145","tracking_url":"https://track.example.com/FC-20145","label_url":"https://labels.example.com/FC-20145.pdf"}'status | What happens |
|---|---|
shipped | The customer sees it on the way. The first movement sends the shipping notice once |
out_for_delivery | The customer sees it out for delivery |
delivery_attempted | The customer sees that the attempt failed |
delivered | The order is completed and the customer is told it arrived. No update is accepted after this |
returned | The customer sees it returned. Any refund is the merchant's decision |
carrier, tracking_number, tracking_url and label_url keep their last value when you omit them. carrier is required only when the order has no delivery option of yours. Both links must be https. The merchant prints the label from the order. Only your own reply carries label_url: other apps and the customer never see it.
Other apps with orders:read receive every change as order.shipment.updated.
Tell the customer
Your first shipped or out_for_delivery sends the shipping notice by email and text message, once. For the later stages, send a text message yourself:
curl -X POST "https://larm.sa/stores/$STORE_ID/v1/orders/200123/notifications" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"channel":"sms","template":"out_for_delivery"}'The templates are order_shipped, out_for_delivery and delivered. Each goes once per order, the merchant pays for it from their message package and can turn it off, and the wording is fixed. To say more, send an email with your own text. See Notify the order customer.
Who owns a shipment
The first to report owns it. You receive SHIPMENT_OWNED_ELSEWHERE when the merchant recorded the shipment or corrected yours, or when another app reported it. The merchant can always correct a shipment, and yours stops updating from then on.
Money
The customer pays your price with the order, and it stays with the merchant in their settlement. Larm charges nothing on these orders and does not book them with its own carriers. Bill the merchant under your own agreement.