PUDO API – Developer Documentation

Postman collection → OpenAPI spec →

Introduction

A standalone Pick Up Drop Off (PUDO) platform integration API. Connect your courier, e-commerce, or logistics system directly to our network of local drop-off points.

This documentation aims to provide all the information you need to work with our API.

Authenticating requests

All external API requests must be signed using HMAC-SHA256. Three headers are required on every request:

Header Description
X-PUDO-Key Your API key (starts with PUDO_)
X-PUDO-Timestamp Current Unix timestamp in seconds (requests older than 5 minutes are rejected)
X-PUDO-Signature HMAC-SHA256 signature (see below)

How to generate the signature

The signature is computed as:

HMAC-SHA256( timestamp + raw_request_body, api_secret )
  • timestamp is the same value you send in X-PUDO-Timestamp
  • raw_request_body is the raw JSON string (or empty string for GET requests)
  • api_secret is the secret shown once on your integration detail page

JavaScript example

const crypto = require('crypto');

const timestamp = Math.floor(Date.now() / 1000).toString();
const body = JSON.stringify({ pudo_point_id: 1, customer_name: "John Doe" /* ... */ });

const signature = crypto
  .createHmac('sha256', YOUR_API_SECRET)
  .update(timestamp + body)
  .digest('hex');

fetch('https://your-domain.com/api/v1/packages/ingest', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-PUDO-Key': YOUR_API_KEY,
    'X-PUDO-Timestamp': timestamp,
    'X-PUDO-Signature': signature,
  },
  body,
});

PHP example

$timestamp = (string) time();
$body      = json_encode($payload);
$signature = hash_hmac('sha256', $timestamp . $body, $apiSecret);

$response = Http::withHeaders([
    'X-PUDO-Key'       => $apiKey,
    'X-PUDO-Timestamp' => $timestamp,
    'X-PUDO-Signature' => $signature,
])->post('/api/v1/packages/ingest', $payload);

Note: You can retrieve your API key and secret from the Integration Partners page in the admin panel after your account is approved.

PUDO Points

List All PUDO points

GET
https://pudo.2pointapp.com
/api/v1/pudo-points/all
requires authentication

Find all active PUDO points. Use query parameters to filter by branch or cold storage availability.

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

branch_ref
string

Filter by branch reference.

Example:
accra-main
cold_storage
boolean

Filter by cold storage availability.

Example:
true
Example request:
curl --request GET \
    --get "https://pudo.2pointapp.com/api/v1/pudo-points/all?branch_ref=accra-main&cold_storage=1" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
 "status": "success",
 "data": [
   {
     "id": 1,
     "name": "Shell Station East Legon",
     "address": "Boundary Road, Accra",
     "lat": "5.63410000",
     "lng": "-0.15230000",
     "has_cold_storage": true,
     "currency": "GHS",
     "price": 5.00,
     "operating_hours": {
      "mon": "08:00-20:00",
     "tue": "08:00-20:00",
   }
  }
]

List Nearby PUDO points

GET
https://pudo.2pointapp.com
/api/v1/pudo-points
requires authentication

Find active PUDO points near a location or within a branch.

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

lat
number

Latitude of the search center.

Example:
5.6037
lng
number

Longitude of the search center.

Example:
-0.187
radius
integer

Search radius in KM. Default: 10.

Example:
25
branch_ref
string

Filter by branch reference.

Example:
accra-main
cold_storage
boolean

Filter by cold storage availability.

Example:
true
Example request:
curl --request GET \
    --get "https://pudo.2pointapp.com/api/v1/pudo-points?lat=5.6037&lng=-0.187&radius=25&branch_ref=accra-main&cold_storage=1" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
 "status": "success",
 "data": [
   {
     "id": 1,
     "name": "Shell Station East Legon",
     "address": "Boundary Road, Accra",
     "lat": "5.63410000",
     "lng": "-0.15230000",
     "distance": 2.4,
     "has_cold_storage": true
     "currency": "GHS",
    "price": 5.00
   }
 ]
}

Get PUDO point details

GET
https://pudo.2pointapp.com
/api/v1/pudo-points/{id}
requires authentication

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the PUDO point.

Example:
1
Example request:
curl --request GET \
    --get "https://pudo.2pointapp.com/api/v1/pudo-points/1" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
Headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
    "message": "Invalid API key"
}

Packages

List packages

GET
https://pudo.2pointapp.com
/api/v1/packages
requires authentication

Retrieve packages that have been ingested into the PUDO system by your integration.

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

status
string

Filter by package status (e.g., pending, dropped, ready, picked_up).

Example:
ready
limit
integer

Limit the number of results. Default: 15.

Example:
10
Example request:
curl --request GET \
    --get "https://pudo.2pointapp.com/api/v1/packages?status=ready&limit=10" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "status": "success",
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 1,
                "tracking_number": "PUDO-12345678",
                "external_booking_ref": "BK-9921",
                "pudo_point_id": 1,
                "customer_name": "John Doe",
                "status": "pending",
                "payment_status": "unpaid",
                "created_at": "2024-03-08T10:00:00.000000Z"
            }
        ],
        "total": 1
    }
}

Get package details

GET
https://pudo.2pointapp.com
/api/v1/packages/{tracking_number}
requires authentication

Retrieve the details and statuses for a specific package using its tracking number.

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

tracking_number
string
required

The PUDO tracking number of the package.

Example:
PUDO-12345678
Example request:
curl --request GET \
    --get "https://pudo.2pointapp.com/api/v1/packages/PUDO-12345678" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "status": "success",
    "data": {
        "id": 1,
        "tracking_number": "PUDO-12345678",
        "external_booking_ref": "BK-9921",
        "pudo_point_id": 1,
        "customer_name": "John Doe",
        "status": "pending",
        "payment_status": "unpaid",
        "created_at": "2024-03-08T10:00:00.000000Z"
    }
}
{
    "status": "error",
    "message": "Package not found."
}

Ingest a new package

POST
https://pudo.2pointapp.com
/api/v1/packages/ingest
requires authentication

Submit a package from your system to a PUDO point. The package will start in 'pending' status.

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://pudo.2pointapp.com/api/v1/packages/ingest" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"pudo_point_id\": 1,
    \"external_booking_ref\": \"BK-9921\",
    \"customer_name\": \"John Doe\",
    \"customer_email\": \"john@example.com\",
    \"customer_phone\": \"+233240000000\",
    \"cold_storage\": false,
    \"notes\": \"Fragile electronics\",
    \"payment_status\": \"unpaid\",
    \"payment_method\": \"cod\",
    \"amount_to_collect\": \"15.50\"
}"
Example response:
{
    "status": "success",
    "message": "Package ingested successfully",
    "data": {
        "tracking_number": "PUDO-12345678",
        "status": "pending"
    }
}

Webhooks

Register Webhook

POST
https://pudo.2pointapp.com
/api/v1/webhooks/register
requires authentication

Register a URL to receive status updates when a package status changes. We will POST to this URL with an HMAC signature.

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://pudo.2pointapp.com/api/v1/webhooks/register" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"webhook_url\": \"https:\\/\\/api.mycompany.com\\/pudo\\/webhook\"
}"
Example response:
{
    "status": "success",
    "message": "Webhook registered successfully",
    "data": {
        "webhook_url": "https://api.mycompany.com/pudo/webhook"
    }
}

Handle incoming status webhooks from 2PointLogistics.

POST
https://pudo.2pointapp.com
/api/v1/webhooks/logistics/status
requires authentication

Headers

X-PUDO-Key
Example:
{YOUR_AUTH_KEY}
X-PUDO-Timestamp
Example:
required Current Unix timestamp in seconds. Example: 1709845200
X-PUDO-Signature
Example:
required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2...
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://pudo.2pointapp.com/api/v1/webhooks/logistics/status" \
    --header "X-PUDO-Key: {YOUR_AUTH_KEY}" \
    --header "X-PUDO-Timestamp: required Current Unix timestamp in seconds. Example: 1709845200" \
    --header "X-PUDO-Signature: required HMAC-SHA256(timestamp + raw_body, api_secret). Example: a3f5c2..." \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"event\": \"architecto\",
    \"tracking_number\": \"architecto\",
    \"status\": \"architecto\",
    \"eta_to_pickup_minutes\": 16,
    \"eta_to_dropoff_minutes\": 16
}"