Skip to main content
This walks the happy path of the public API. Every call here has a live playground in the API Reference — you can run them from the page with a test key.
All examples use test mode. Test and live are physically separate database schemas; a sk_test_ key can never touch live data. See Modes.

1. Authenticate

Every merchant request carries a secret API key as a bearer token. The key prefix selects the mode.
export DURO_KEY="sk_test_•••••••••••••••••••"
export DURO_API="https://api.useduro.com"

2. Create a plan

A plan is the thing customers subscribe to: an amount, an interval, and optional recovery knobs (trialDays, maxCycles).
curl -s $DURO_API/v1/plans \
  -H "Authorization: Bearer $DURO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Pro Monthly",
    "amount": 500000,
    "currency": "NGN",
    "interval": "month",
    "intervalCount": 1,
    "trialDays": 0
  }'
Amounts are in minor units (kobo). 500000 = ₦5,000.00. Intervals: hour, day, week, month, quarter, biannual, year.

3. Create a customer

curl -s $DURO_API/v1/customers \
  -H "Authorization: Bearer $DURO_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "ada@example.com", "phone": "2348012345678", "merchantRef": "EXT-001" }'
merchantRef is your own ID for this customer — you can later look them up by it (GET /v1/customers/ref/EXT-001) and fetch their transactions without ever storing a Duro ID.

4. Subscribe them

curl -s $DURO_API/v1/subscriptions \
  -H "Authorization: Bearer $DURO_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "customerId": "cus_•••", "planId": "plan_•••" }'
The subscription is now live. When currentPeriodEnd passes, the billing worker picks it up automatically: it generates an invoice, charges the gateway, and either advances the period (success) or hands the failure to the recovery engine.

5. Listen for what happens

You don’t poll. You subscribe to events. Webhook endpoints are configured in the dashboard (Developers → Webhooks) — add your URL, pick the events, and copy the signing secret (shown once). Duro then delivers signed, retried events for the whole lifecycle to your server.
1

Add an endpoint in the dashboard

Developers → Webhooks → Add endpoint. Enter your https:// URL and choose the events to receive (e.g. subscription_payment_success, subscription_payment_failed, subscription_payment_recovered).
2

Store the signing secret

Shown once on creation. You’ll use it to verify the Duro-Signature header on every delivery.
3

Verify and handle

Recompute the HMAC and compare in constant time — see Webhook events.

The whole loop, on a timeline

That’s the entire product in one diagram. The rest of these docs explain every arrow.

Inline checkout instead

Don’t want to manage subscriptions server-side? Drop in duro.pay() and let the popup do identity, payment, and tokenisation.

Full API reference

Interactive playground for every endpoint, with auth, pagination, idempotency, and the event catalog.