subbydocs
Visit Subby Start building

Quickstart

Create a plan, a customer and a sandbox subscription with Subby's subscription engine in about 10 minutes. No real money moves.

Use the sandbox to create a plan, add a customer, collect a test payment method through hosted checkout, and watch the subscription engine mark the subscription active. Nothing here costs money or counts toward your bill.

Before you start

  1. Create a Subby account or sign in.
  2. Open Dashboard → Developers → API keys and make sure the environment switch is set to Sandbox.
  3. Copy your secret key. It starts with sk_test_.

Keep secret keys on your server. Never put them in a mobile app, browser code or a public repository.

Set the key as an environment variable so the examples below work as written:

export SUBBY_SECRET_KEY="sk_test_xxxxxxxxxxxxxxxxxxxxxxxx"
export SUBBY_BASE_URL="https://sandbox-api.mysubbyapp.com/v1"

Step 1 — Check your key

curl "$SUBBY_BASE_URL/account" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY"

You should see your account with "livemode": false. This is a GET request, so it is never metered.

Step 2 — Create a plan

A plan describes what you sell and how often you charge. Amounts are in kobo (₦1 = 100 kobo), so 500000 is ₦5,000.

curl "$SUBBY_BASE_URL/plans" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a1e-plan-pro-monthly" \
  -d '{
    "name": "Pro Monthly",
    "amount": 500000,
    "currency": "NGN",
    "billing_cycle": "monthly",
    "trial_days": 0,
    "retry_logic": { "enabled": true, "max_attempts": 3, "retry_intervals_days": [1, 3, 7], "escalation_on_failure": "pause_service" },
    "reminders": { "enabled": true, "channels": ["whatsapp", "sms", "email"], "pre_due_days": [3], "post_due_days": [1, 3] }
  }'
const res = await fetch(`${process.env.SUBBY_BASE_URL}/plans`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SUBBY_SECRET_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': '6f1c2a1e-plan-pro-monthly',
  },
  body: JSON.stringify({
    name: 'Pro Monthly',
    amount: 500000,
    currency: 'NGN',
    billing_cycle: 'monthly',
    retry_logic: { enabled: true, max_attempts: 3, retry_intervals_days: [1, 3, 7], escalation_on_failure: 'pause_service' },
    reminders: { enabled: true, channels: ['whatsapp', 'sms', 'email'], pre_due_days: [3], post_due_days: [1, 3] },
  }),
});
const { data: plan } = await res.json();
console.log(plan.id); // plan_...
import os, requests

res = requests.post(
    f"{os.environ['SUBBY_BASE_URL']}/plans",
    headers={
        "Authorization": f"Bearer {os.environ['SUBBY_SECRET_KEY']}",
        "Idempotency-Key": "6f1c2a1e-plan-pro-monthly",
    },
    json={
        "name": "Pro Monthly",
        "amount": 500000,
        "currency": "NGN",
        "billing_cycle": "monthly",
        "retry_logic": {"enabled": True, "max_attempts": 3, "retry_intervals_days": [1, 3, 7], "escalation_on_failure": "pause_service"},
        "reminders": {"enabled": True, "channels": ["whatsapp", "sms", "email"], "pre_due_days": [3], "post_due_days": [1, 3]},
    },
)
plan = res.json()["data"]
print(plan["id"])  # plan_...

Save the returned id (it starts with plan_).

Step 3 — Create a customer

curl "$SUBBY_BASE_URL/customers" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Ada Okafor",
    "email": "ada@example.com",
    "phone": "+2348000000001",
    "metadata": { "your_user_id": "u_1024" }
  }'

Save the customer id (it starts with cus_). Use metadata to store your own IDs so you can match records later.

+2348000000001 is a sandbox test number. Nudges sent to it are marked delivered. See Testing in sandbox for numbers that simulate failures.

Step 4 — Start a checkout session

Checkout sessions give you a Subby-hosted page where the customer enters payment details. When they finish, the subscription is created.

curl "$SUBBY_BASE_URL/checkout-sessions" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "subscription",
    "customer": "cus_REPLACE_ME",
    "plan": "plan_REPLACE_ME",
    "success_url": "https://example.com/billing/success",
    "cancel_url": "https://example.com/billing/cancelled"
  }'

The response includes a url. Keep it for now: set up your webhook endpoint in Step 5 first, so you receive the events when checkout completes. Then open the url in your browser and choose Test payment method → Succeeds. Sessions expire after 24 hours.

Step 5 — Listen for webhooks

Create a webhook endpoint so your system hears about the new subscription. For local development, expose your server with a tunnelling tool, then register the URL:

curl "$SUBBY_BASE_URL/webhook-endpoints" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-tunnel.example.com/webhooks/subby",
    "enabled_events": ["subscription.created", "charge.succeeded", "charge.failed", "subscription.past_due", "subscription.paused"]
  }'

The response contains a secret starting with whsec_. It is shown once, so store it now. You'll use it to verify signatures.

Step 6 — Confirm the subscription

curl "$SUBBY_BASE_URL/subscriptions?customer=cus_REPLACE_ME" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY"

You should see one subscription with "status": "active".

What you just used

Request Method Metered in live?
Check account GET No
Create plan POST Yes, 1 write request
Create customer POST Yes, 1 write request
Create checkout session POST Yes, 1 write request
Create webhook endpoint POST Yes, 1 write request
List subscriptions GET No

In sandbox none of these count. In live, this flow uses 4 of your monthly write requests.

Next steps