Skip to main content

Quickstart

This walkthrough takes you from zero to a working integration in about 30 minutes. By the end you'll have:

  • An approved merchant account
  • A funded wallet
  • An API key
  • A successful test shipment in sandbox

1. Create an account

Go to merchant.dodo.co.tz/register and fill in:

  • Business name — appears on receipts and rider apps
  • Business email — receives approval, billing, and webhook notifications
  • Phone — E.164 format: +255712345678
  • Password — minimum 8 characters, mixed case + a digit

You'll receive a verification email. Click the link to confirm your email address.

2. Wait for approval

Every merchant is reviewed manually before going live. Approval usually takes less than one business day.

During this window:

  • You can log in to the dashboard
  • You cannot generate API keys or fund a wallet yet
  • We may call the phone number you registered with to verify

You'll get a Your Dodo account is approved email when you can proceed.

3. Generate your sandbox API key

Always integrate against sandbox first. In the dashboard:

  1. Toggle the environment switch (top-right) to Sandbox.
  2. Go to Settings → API Keys.
  3. Click Generate API Key.
  4. Copy the key (dk_test_…) — it's shown only once. Store it somewhere safe.

Store it as an environment variable on your server:

export DODO_API_KEY="dk_test_a1B2c3D4e5F6g7H8i9J0kLmNoPqRsTuVw"
tip

Get a production key the same way after switching the dashboard environment toggle to Live. Production keys start with dk_live_.

4. Fund your wallet

Every shipment is paid for by debiting your Dodo wallet — no per-order checkout, no payment URLs, no customer-facing redirects.

In the dashboard:

  1. Go to Wallet → Top Up.
  2. Enter an amount in TZS. Minimum top-up in sandbox: 5,000 TZS.
  3. Choose a method (M-Pesa, Tigo Pesa, Airtel Money, or card).
  4. Complete the Selcom checkout. In sandbox, use the test credentials.

Your wallet balance updates within seconds. Keep an eye on Wallet → Low-balance alerts to avoid declined shipments — when the balance falls below your threshold, we email you.

5. Get a price quote

Now your backend can talk to Dodo. Start with a rate quote — this is a read-only check, no charges or DB writes.

curl -X POST https://sandbox.dodo.co.tz/api/v1/merchant/shipments/rates \
-H "X-API-Key: $DODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"pickup_latitude": -6.7924,
"pickup_longitude": 39.2083,
"dropoff_latitude": -6.7600,
"dropoff_longitude": 39.2400,
"items": [
{ "description": "Food order", "weight_kg": 2.5, "quantity": 1 }
]
}'

You'll get back the detected shipment type, the vehicle Dodo will use, and itemized pricing:

{
"shipment_type": "same_city",
"vehicle_id": 1,
"vehicle_name": "Motorcycle",
"first_mile_fee": 3727,
"transit_fee": 0,
"last_mile_fee": 0,
"handling_fee": 0,
"service_fee": 373,
"fragile_surcharge": 0,
"total_amount": 4100,
"distance_km": 5.2,
"estimated_delivery_hours": 1
}

total_amount (TZS 4,100 here) is what will be debited from your wallet when you create the shipment.

See Rate Quotes for the full reference.

6. Create your first shipment

When you're ready to dispatch:

curl -X POST https://sandbox.dodo.co.tz/api/v1/merchant/shipments \
-H "X-API-Key: $DODO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sender_name": "My Restaurant",
"sender_phone": "+255712345678",
"pickup_address": "Malaika Restaurant, Samora Ave, Dar es Salaam",
"pickup_latitude": -6.7924,
"pickup_longitude": 39.2083,
"receiver_name": "Jane Doe",
"receiver_phone": "+255765432109",
"dropoff_address": "Apartment 4B, Msasani, Dar es Salaam",
"dropoff_latitude": -6.7600,
"dropoff_longitude": 39.2400,
"items": [
{ "description": "Food order — 2 containers", "weight_kg": 2.5, "quantity": 1 }
],
"payment_source": "wallet",
"merchant_reference": "your-internal-order-id-123"
}'
warning

payment_source: "wallet" is required. Without it the API will try to issue a Selcom checkout URL — not what you want for S2S.

The response confirms creation and payment in one shot:

{
"id": 12345,
"shipment_number": "SHP-20260515-A1B2C3",
"tracking_code": "DODO7K9M2P4QR8",
"status": "confirmed",
"total_amount": 4100,
"payment_status": "paid",
"merchant_reference": "your-internal-order-id-123",
"created_at": "2026-05-15T10:30:00Z",
...
}

Store id (integer) so you can match webhook events to your records. Share tracking_code with your customer.

See Create a Shipment for the full reference.

7. Subscribe to webhooks

While shipments can be polled with GET /merchant/shipments/{id}, webhooks are how you get real-time updates.

In the dashboard:

  1. Go to Settings → Webhooks → Add endpoint.
  2. Enter your URL: https://yourapp.com/webhooks/dodo.
  3. Select events you want — at minimum: shipment.created, shipment.paid, delivery.picked_up, delivery.delivered, delivery.failed, shipment.cancelled.
  4. Click Save. Copy the signing secret — you'll use it to verify incoming requests.

Your endpoint must:

  • Accept POST with JSON body
  • Verify X-Dodo-Signature (HMAC-SHA256 of "{timestamp}.{raw_body}")
  • Return a 2xx within 30 seconds

See Webhooks for the full payload reference and verification code in Node.js, Python, and PHP.

8. Testing in sandbox

Sandbox behaves exactly like production except:

  • No real money moves — wallet top-ups use Selcom sandbox credentials
  • A simulated rider auto-progresses your shipment through every status within ~2 minutes
  • You can fast-forward the lifecycle from the dashboard (Shipments → Detail → Simulate)

Selcom sandbox test credentials:

MethodPhone / CardResult
M-Pesa+255652000001Success
M-Pesa+255652000099Failure
Card5555 5555 5555 4444, any future expiry, CVV 123Success
Card4000 0000 0000 0002Failure

When you're ready to go live, regenerate keys in the Live environment and switch your base URL to https://api.dodo.co.tz/api/v1. Everything else is identical.

Next steps