Build delivery into anything
A clean REST API with predictable JSON responses, idempotent keys, and HMAC-signed webhooks. Integrate in hours, not weeks.
curl -X POST https://daas.errand4me.com/api/v1/deliveries \
-H "x-api-key: em_live_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"pickup_address": "15 Independence Ave, Accra",
"dropoff_address": "42 Ring Road East, Accra",
"dropoff_contact_name": "Jane Doe",
"dropoff_contact_phone": "+233209876543"
}'
# Response
{
"success": true,
"data": {
"tracking_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "dispatched",
"price": { "total": 25, "currency": "GHS" }
}
}Two authentication methods
Use API keys for server-to-server integrations. JWT for dashboard sessions.
API Key
Recommended for server-to-server
Keys follow the format em_live_<64-hex-chars> (72 chars total). Generated once — store securely. Revocable at any time.
# All protected endpoints
GET /api/wallet HTTP/1.1
Host: daas.errand4me.com
x-api-key: em_live_a1b2c3d4e5f6...JWT Bearer Token
For dashboard sessions
Login with email/password to receive an access token (8h expiry) and a refresh token. Use Authorization: Bearer <token>.
# Dashboard users
POST /api/auth/login
{ "email": "...", "password": "..." }
# Then use the returned token:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...Up and running in 4 steps
Register your business
Create an account at the DaaS portal. A verification email is sent immediately.
POST https://daas.errand4me.com/api/auth/register
Content-Type: application/json
{
"business_name": "My Store",
"slug": "my-store",
"email": "admin@mystore.com",
"owner_name": "Jane Smith",
"password": "secure-password-min-8-chars"
}Verify email & get approved
Click the link in your email to verify. Your account is reviewed within 24 hours. You'll receive an approval email.
Generate an API key
Log in to your dashboard and generate your first API key. It's shown only once — copy it to your secrets manager.
POST https://daas.errand4me.com/api/keys
Authorization: Bearer <your_access_token>
{ "name": "Production Key" }
# Response: { "key": "em_live_a1b2c3d4..." } ← store this!Send your first delivery
Use your API key to dispatch a delivery. You'll get back a tracking_id and real-time status via webhooks.
const res = await fetch('https://daas.errand4me.com/api/v1/deliveries', {
method: 'POST',
headers: {
'x-api-key': process.env.DAAS_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
pickup_address: '15 Independence Ave, Accra',
dropoff_address: '42 Ring Road East, Accra',
dropoff_contact_name: 'John Doe',
dropoff_contact_phone: '+233209876543',
}),
})
const { data } = await res.json()
console.log(data.tracking_id) // "550e8400-..."
console.log(data.status) // "dispatched"
console.log(data.price.total) // 25Endpoints
Base URL: https://daas.errand4me.com/api
full_service or both planB Requires delivery_api or both plan/auth/register/auth/login/auth/refresh/auth/verify-email/auth/resend-verification/wallet/wallet/transactions/wallet/topup/initialize/wallet/topup/verify/:reference/listings/listings/listings/:id/listings/:id/listings/:id/orders/orders/orders/:id/orders/:id/cancel/v1/deliveries/price-estimate/v1/deliveries/v1/deliveries/v1/deliveries/:id/v1/deliveries/:id/cancel/v1/webhooks/logs/keys/keys/keys/:id/settings/webhook/settings/webhookReal-time event delivery
Configure a HTTPS endpoint and we'll POST signed events for every delivery status change. Retries 3 times on failure.
delivery.createdDelivery accepted and dispatched to carrier networkPOST /v1/deliveries succeedsdelivery.assignedA carrier accepted the errandCarrier manually acceptsdelivery.picked_upCarrier has picked up the packageCarrier marks pickup donedelivery.deliveredDelivery completed successfullyCarrier marks delivery donedelivery.cancelledDelivery was cancelled by business or systemPOST /v1/deliveries/:id/canceldelivery.failedDelivery could not be completedNo carrier found or failed attemptRequest headers
Retry policy
All attempts logged. View via GET /v1/webhooks/logs
Payload shape
{
"event": "delivery.delivered",
"delivery_id": "550e8400-e29b-41d4-a716-446655440000",
"business_id": "biz-uuid-here",
"timestamp": "2026-03-08T10:30:00.000Z",
"data": {
"tracking_id": "550e8400-e29b-41d4-a716-446655440000",
"external_ref": "ORDER-001",
"status": "delivered",
"errand_id": "errand-uuid"
}
}Signature verification
// Node.js — verify incoming webhook signature
const crypto = require('crypto')
function verifyWebhook(rawBody, signature, secret) {
const expected = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
)
}
// Express example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-daas-signature']
if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
const event = JSON.parse(req.body)
console.log(event.event) // "delivery.delivered"
res.sendStatus(200)
})Working examples
Copy-paste ready code for creating deliveries, estimating prices, and cancelling.
import fetch from 'node-fetch' // or built-in fetch in Node 18+
const DAAS_API_KEY = process.env.DAAS_API_KEY
const BASE_URL = 'https://daas.errand4me.com/api'
async function createDelivery(order) {
const res = await fetch(`${BASE_URL}/v1/deliveries`, {
method: 'POST',
headers: {
'x-api-key': DAAS_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
external_ref: order.id,
pickup_address: order.store.address,
pickup_contact_name: order.store.name,
pickup_contact_phone: order.store.phone,
dropoff_address: order.customer.address,
dropoff_contact_name: order.customer.name,
dropoff_contact_phone: order.customer.phone,
package_description: order.items.join(', '),
package_fragile: order.hasFragile,
}),
})
if (!res.ok) throw new Error(`DaaS error: ${res.status}`)
const { data } = await res.json()
return data // { tracking_id, status, price, errand_id }
}
async function getPriceEstimate(pickupLat, pickupLng, dropoffLat, dropoffLng) {
const params = new URLSearchParams({
pickup_lat: pickupLat, pickup_lng: pickupLng,
dropoff_lat: dropoffLat, dropoff_lng: dropoffLng,
})
const res = await fetch(`${BASE_URL}/v1/deliveries/price-estimate?${params}`, {
headers: { 'x-api-key': DAAS_API_KEY },
})
const { data } = await res.json()
return data // { base_fee: 10, distance_fee: 12.5, total: 22.5, currency: "GHS" }
}Ready to integrate?
Sign up, get approved, and generate your API key. No credit card required.
Get API Key — Free