curl --request GET \
--url https://api.listo.delivery/v1/webhook_deliveries \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.listo.delivery/v1/webhook_deliveries"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.listo.delivery/v1/webhook_deliveries', 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://api.listo.delivery/v1/webhook_deliveries",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.listo.delivery/v1/webhook_deliveries"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.listo.delivery/v1/webhook_deliveries")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.listo.delivery/v1/webhook_deliveries")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "whd_8d2e5f1a7c3b9046a1b2c3d4",
"event_id": "evt_9pQ2vX7mKdR4tYb1nZ3sLwCe",
"event_type": "delivery.status_changed",
"attempt": 1,
"resent": false,
"url": "https://hooks.example.com/listo/live",
"status_code": 200,
"error_message": null,
"response_body": "ok",
"duration_ms": 84,
"succeeded": true,
"created_at": "2026-08-01T12:00:00Z"
},
{
"id": "whd_8d2e5f1a7c3b9046a1b2c3d4",
"event_id": "evt_9pQ2vX7mKdR4tYb1nZ3sLwCe",
"event_type": "delivery.status_changed",
"attempt": 1,
"resent": false,
"url": "https://old.example.com/hook",
"status_code": 200,
"error_message": null,
"response_body": "ok",
"duration_ms": 84,
"succeeded": true,
"created_at": "2026-08-01T09:00:00Z"
}
],
"has_more": false,
"cursor": null
}List webhook delivery attempts
Every attempt Listo made to POST an event to your webhook URL, newest
first, keyset-paginated: the URL, the status your endpoint answered with,
the first 500 characters of its body, how long it took and whether it
counted as a success. An event has one attempt per try: the first send,
each automatic retry, and each resend you asked for (resent: true).
Filter by event_id (the attempts for one event), status
(failed or succeeded), created_after and created_before. An
event_id that is not one of yours is 404 not_found, so an empty page
always means that event had no attempts.
A status_code of null means nothing answered at all (a timeout, a
refused connection, a certificate error) and error_message says which.
An event with no attempts has not been sent yet, or had no endpoint configured for its mode
when it happened.
curl --request GET \
--url https://api.listo.delivery/v1/webhook_deliveries \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.listo.delivery/v1/webhook_deliveries"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.listo.delivery/v1/webhook_deliveries', 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://api.listo.delivery/v1/webhook_deliveries",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.listo.delivery/v1/webhook_deliveries"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.listo.delivery/v1/webhook_deliveries")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.listo.delivery/v1/webhook_deliveries")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "whd_8d2e5f1a7c3b9046a1b2c3d4",
"event_id": "evt_9pQ2vX7mKdR4tYb1nZ3sLwCe",
"event_type": "delivery.status_changed",
"attempt": 1,
"resent": false,
"url": "https://hooks.example.com/listo/live",
"status_code": 200,
"error_message": null,
"response_body": "ok",
"duration_ms": 84,
"succeeded": true,
"created_at": "2026-08-01T12:00:00Z"
},
{
"id": "whd_8d2e5f1a7c3b9046a1b2c3d4",
"event_id": "evt_9pQ2vX7mKdR4tYb1nZ3sLwCe",
"event_type": "delivery.status_changed",
"attempt": 1,
"resent": false,
"url": "https://old.example.com/hook",
"status_code": 200,
"error_message": null,
"response_body": "ok",
"duration_ms": 84,
"succeeded": true,
"created_at": "2026-08-01T09:00:00Z"
}
],
"has_more": false,
"cursor": null
}Authorizations
Your API key, sent as Authorization: Bearer <key>. Live and test keys are separate; the key you send decides which world the call acts in. To try calls, use a test key (it starts with lst_test_): no real courier is sent and no real money moves, but webhooks fire and the dropoff.phone you give can receive WhatsApp messages, so use your own number. A live key (it starts with lst_live_) books and charges real deliveries.
Query Parameters
Only the attempts to deliver one event, by its evt_ id. An id that is not one of your events in this mode is 404 not_found.
Only attempts that failed (failed) or succeeded (succeeded). Any other value matches nothing.
failed, succeeded Only attempts made at or after this instant (ISO-8601). A value that does not parse is 422 validation_failed with param: "created_after".
Only attempts made at or before this instant (ISO-8601). A value that does not parse is 422 validation_failed with param: "created_before".
The cursor of the previous page, to read the next one. Opaque: never build or parse one.