> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useplinth.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 5-minute quickstart

> Create a customer, subscribe them to a plan, and check their access. Three API calls.

<Note>
  The examples on this page use the shared sandbox key `sk_test_DOCS_SHARED_KEY`. You can run them right now — no signup needed. Want your own isolated sandbox? [Get one in 1 call →](/sandbox)
</Note>

<div style={{ display: 'flex', gap: '8px', marginBottom: '24px', flexWrap: 'wrap' }}>
  <a
    href="/sandbox"
    style={{
display: 'inline-flex', alignItems: 'center', gap: '6px',
padding: '7px 14px', background: '#4f46e5', color: '#fff',
borderRadius: '8px', fontSize: '13px', textDecoration: 'none', fontWeight: 500,
}}
  >
    Get my own sandbox →
  </a>

  <span
    style={{
display: 'inline-flex', alignItems: 'center',
padding: '7px 14px', background: '#f3f4f6', color: '#374151',
borderRadius: '8px', fontSize: '13px', fontFamily: 'monospace',
}}
  >
    Using: sk\_test\_DOCS\_SHARED\_KEY
  </span>
</div>

## Before you begin

<Card title="Get an API key" icon="key" href="https://app.useplinth.com/login">
  You need a Plinth API key. If you don't have one yet, get one here. Sandbox keys start with `sk_test_`.
</Card>

## Steps

<Steps>
  <Step title="Create a customer">
    A customer is who you're billing. Create one with a name, email, and optionally your own internal ID (`external_ref`).

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.useplinth.com/v1/customers \
        -H "Authorization: Bearer sk_test_DOCS_SHARED_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "Acme Corp",
          "email": "billing@acme.ng",
          "external_ref": "acme_001"
        }'
      ```

      ```typescript Node.js theme={null}
      import { Plinth } from '@nomba/sdk';

      const client = new Plinth({ apiKey: 'sk_test_DOCS_SHARED_KEY' });

      const customer = await client.customers.create({
        name: 'Acme Corp',
        email: 'billing@acme.ng',
        externalRef: 'acme_001',
      });
      // → { id: 'cus_01JXYZ...', name: 'Acme Corp', ... }
      ```
    </CodeGroup>

    ```json Response theme={null}
    {
      "id": "cus_01JXYZ...",
      "name": "Acme Corp",
      "email": "billing@acme.ng",
      "external_ref": "acme_001",
      "balance_minor": 0,
      "created_at": "2026-06-01T00:00:00Z"
    }
    ```
  </Step>

  <Step title="Subscribe them to a plan">
    Pick a plan from your catalog. The sandbox already has two — `plan_pro` (₦5,000/month, stored as 500000 kobo) and `plan_max` (₦12,000/month, stored as 1200000 kobo).

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.useplinth.com/v1/subscriptions \
        -H "Authorization: Bearer sk_test_DOCS_SHARED_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "customer_id": "cus_01JXYZ...",
          "plan_id": "plan_pro",
          "payment_method_id": "tok_test_visa"
        }'
      ```

      ```typescript Node.js theme={null}
      const subscription = await client.subscriptions.create({
        customerId: 'cus_01JXYZ...',
        planId: 'plan_pro',
        paymentMethodId: 'tok_test_visa',
      });
      ```
    </CodeGroup>

    ```json Response theme={null}
    {
      "id": "sub_01JABC...",
      "customer_id": "cus_01JXYZ...",
      "plan_id": "plan_pro",
      "state": "active",
      "billing_mode": "advance",
      "current_period_start": "2026-06-01T00:00:00Z",
      "current_period_end": "2026-07-01T00:00:00Z",
      "next_bill_at": "2026-07-01T00:00:00Z",
      "created_at": "2026-06-01T00:00:00Z"
    }
    ```
  </Step>

  <Step title="Check their access">
    Before serving a feature, check if the customer has access. The entitlements endpoint tells you what tier they're on — no parsing state machines yourself.

    <CodeGroup>
      ```bash cURL theme={null}
      curl https://api.useplinth.com/v1/customers/cus_01JXYZ.../entitlements \
        -H "Authorization: Bearer sk_test_DOCS_SHARED_KEY"
      ```

      ```typescript Node.js theme={null}
      const access = await client.customers.entitlements('cus_01JXYZ...');
      ```
    </CodeGroup>

    ```json Response theme={null}
    {
      "has_access": true,
      "tier": "full",
      "subscription_state": "active",
      "plan": "Pro"
    }
    ```

    If `has_access` is `true`, let them in. That's it.
  </Step>
</Steps>

## What happens next

Next month, we charge automatically. The subscription's `next_bill_at` date triggers the billing engine — it charges the card on file and marks the invoice paid. If the card declines, dunning kicks in: we retry on a schedule and send you webhooks at every step. You get a `subscription.past_due` event when the first charge fails, `subscription.recovered` if we succeed later, and `subscription.delinquent` if we never do.

## Next steps

<CardGroup cols={2}>
  <Card title="Core concepts" icon="book" href="/core-concepts/subscriptions">
    Understand subscription states, invoices, and the billing lifecycle.
  </Card>

  <Card title="Card billing guide" icon="credit-card" href="/guides/card-billing">
    Full walkthrough: plan creation, tokenisation, renewal handling.
  </Card>

  <Card title="Transfer billing guide" icon="building-columns" href="/guides/transfer-billing">
    Set up virtual accounts for customers who pay by bank transfer.
  </Card>

  <Card title="Webhook reference" icon="webhook" href="/webhook-events">
    Every event type we emit and what the payload looks like.
  </Card>
</CardGroup>
