curl --request POST \
--url https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"status": "assigned"
}
'import requests
url = "https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition"
payload = { "status": "assigned" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({status: 'assigned'})
};
fetch('https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'status' => 'assigned'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition"
payload := strings.NewReader("{\n \"status\": \"assigned\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"status\": \"assigned\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"status\": \"assigned\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"statusCode": 200,
"message": "<string>",
"data": {
"id": "dlv_3f1a821cdb58498cbb52f4706545a089",
"environment": "live",
"simulated": true,
"status": "in_transit",
"recipient": {
"id": "rcp_3f1a821cdb58498cbb52f4706545a089",
"phone_number": "<string>",
"name": "<string>"
},
"pickup": {
"name": "<string>",
"contact": "<string>",
"address": "<string>",
"latitude": 0,
"longitude": 0
},
"dropoff": {
"id": "adr_78de60204f574a64be88ba9bd94a049f",
"address": "<string>",
"latitude": 123,
"longitude": 123,
"label": "<string>",
"municipality": "<string>",
"delivery_notes": "<string>"
},
"payment": {
"type": "cod",
"goods_value": 123
},
"vehicle_type": "bike",
"currency": "GHS",
"requires_custom_quote": true,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"external_id": "<string>",
"reference": "H-RS83223",
"delivery_instructions": "<string>",
"delivery_fee": 1,
"tracking_url": "<string>",
"simulation": {
"scenario": "failed_then_retried",
"status": "running",
"step": 3,
"steps_total": 8,
"next_step_at": "2026-10-02T10:15:05Z"
}
}
}Advance a sandbox delivery
Advances a simulated delivery through an allowed forward transition and emits the same webhook contract used for live lifecycle changes. This endpoint is available only on the sandbox server and accepts only test keys.
While an automatic simulation is running on the delivery this returns
409 SIMULATION_RUNNING. Stop the simulation first.
curl --request POST \
--url https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"status": "assigned"
}
'import requests
url = "https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition"
payload = { "status": "assigned" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({status: 'assigned'})
};
fetch('https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'status' => 'assigned'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition"
payload := strings.NewReader("{\n \"status\": \"assigned\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"status\": \"assigned\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.developer.haulstow.co/v1/test-helpers/deliveries/{delivery_id}/transition")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"status\": \"assigned\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"statusCode": 200,
"message": "<string>",
"data": {
"id": "dlv_3f1a821cdb58498cbb52f4706545a089",
"environment": "live",
"simulated": true,
"status": "in_transit",
"recipient": {
"id": "rcp_3f1a821cdb58498cbb52f4706545a089",
"phone_number": "<string>",
"name": "<string>"
},
"pickup": {
"name": "<string>",
"contact": "<string>",
"address": "<string>",
"latitude": 0,
"longitude": 0
},
"dropoff": {
"id": "adr_78de60204f574a64be88ba9bd94a049f",
"address": "<string>",
"latitude": 123,
"longitude": 123,
"label": "<string>",
"municipality": "<string>",
"delivery_notes": "<string>"
},
"payment": {
"type": "cod",
"goods_value": 123
},
"vehicle_type": "bike",
"currency": "GHS",
"requires_custom_quote": true,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"external_id": "<string>",
"reference": "H-RS83223",
"delivery_instructions": "<string>",
"delivery_fee": 1,
"tracking_url": "<string>",
"simulation": {
"scenario": "failed_then_retried",
"status": "running",
"step": 3,
"steps_total": 8,
"next_step_at": "2026-10-02T10:15:05Z"
}
}
}Authorizations
A business-bound HaulStow API key. Send
Authorization: Bearer hsg_live_key_... to the live server or a
hsg_test_key_... key to the sandbox server. Never expose this key in a browser.
Headers
Optional caller correlation ID. Use 1–128 ASCII letters, digits, ., _,
-, or :. Invalid values are replaced. The accepted/generated value is
returned in the response.
1 - 128^[A-Za-z0-9._:-]+$A unique key for this logical mutation. Retained for 24 hours.
8 - 255Path Parameters
^dlv_[a-f0-9]{32}$"dlv_3f1a821cdb58498cbb52f4706545a089"
Body
assigned, picked_up, in_transit, delivered, failed, cancelled, outsourced 