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

# Worked billing samples

> Copy-pasteable request and response samples for the billing endpoints a developer actually calls first: the wallet balance and ledger, top-up checkout, plan checkout, auto top-up, and billing alerts.

## Wallet balance and ledger

`GET /api/v1/billing/balance` returns the prepaid wallet as dollars, whole cents, and micro-cents, alongside the outbound-pause flags billing alerts can set. Poll it before a send to check available funds.

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "balance_usd": 42.5,
      "balance_cents": 4250,
      "balance_micro_cents": 4250000000,
      "credits": 4250,
      "currency": "USD",
      "outbound_paused": false,
      "outbound_block_reason": null,
      "payment_failure_count": 0
    },
    "meta": {
      "request_id": "req_01HZY8EXAMPLE",
      "timestamp": "2026-08-02T12:00:00.000Z"
    }
  }
  ```
</ResponseExample>

`GET /api/v1/billing/transactions` pages through the wallet ledger — top-ups, spend debits, refunds, and adjustments — newest first, with `next_cursor` for paging.

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "transactions": [
        {
          "id": "txn_01H8XGJ",
          "type": "topup",
          "amount_minor": 5000,
          "reference": "stripe_checkout",
          "metadata": null,
          "created_at": "2026-08-02T12:00:00.000Z",
          "expires_at": null,
          "refunded_at": null
        },
        {
          "id": "txn_01H8XGB",
          "type": "debit",
          "amount_minor": -132,
          "reference": "sms_send",
          "metadata": null,
          "created_at": "2026-08-02T11:47:00.000Z",
          "expires_at": null,
          "refunded_at": null
        }
      ],
      "next_cursor": null,
      "has_more": false
    },
    "meta": {
      "request_id": "req_01HZY8EXAMPLE",
      "timestamp": "2026-08-02T12:00:00.000Z"
    }
  }
  ```
</ResponseExample>

## Top up the wallet

`POST /api/v1/billing/balance/top-up` returns a hosted Stripe Checkout URL in the locally-hosted `checkoutUrl` field; the wallet is credited once the payment settles. The `Idempotency-Key` header dedupes retries, so a repeated request returns the same session instead of charging twice.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.orbit.devotel.io/api/v1/billing/balance/top-up" \
    -H "X-API-Key: dv_live_sk_your_key_here" \
    -H "Idempotency-Key: topup-2026-08-02-acme-7" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 5000,
      "currency": "usd",
      "successUrl": "https://app.example.com/billing/success",
      "cancelUrl": "https://app.example.com/billing"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_a1B2c3D4"
    },
    "meta": {
      "request_id": "req_01HZY8EXAMPLE",
      "timestamp": "2026-08-02T12:00:00.000Z"
    }
  }
  ```
</ResponseExample>

## Plan checkout and subscription management

`POST /api/v1/billing/checkout` starts a Stripe Checkout session for a subscription-plan change and returns the hosted `checkoutUrl`; requests are idempotent for 60 seconds per organization and plan, so a double-click returns the same session URL.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.orbit.devotel.io/api/v1/billing/checkout" \
    -H "X-API-Key: dv_live_sk_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "planId": "pro",
      "successUrl": "https://app.example.com/billing/success",
      "cancelUrl": "https://app.example.com/billing/plans"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3"
    },
    "meta": {
      "request_id": "req_01HZY8EXAMPLE",
      "timestamp": "2026-08-02T12:00:00.000Z"
    }
  }
  ```
</ResponseExample>

`POST /api/v1/billing/portal` opens a Stripe customer-portal session so the customer can manage payment methods, subscription, and invoices. Read `GET /api/v1/billing/status` first and only offer this (or plan checkout above) when `can_manage` is true.

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "url": "https://billing.stripe.com/p/session/DYb3GT1"
    },
    "meta": {
      "request_id": "req_01HZY8EXAMPLE",
      "timestamp": "2026-08-02T12:00:00.000Z"
    }
  }
  ```
</ResponseExample>

## Auto top-up configuration

`PUT /api/v1/billing/auto-topup` charges the saved payment method off-session whenever the balance falls to the threshold. `recharge_amount_minor` must exceed `threshold_minor`.

<RequestExample>
  ```bash cURL theme={null}
  curl -X PUT "https://api.orbit.devotel.io/api/v1/billing/auto-topup" \
    -H "X-API-Key: dv_live_sk_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "enabled": true,
      "threshold_minor": 500,
      "recharge_amount_minor": 5000,
      "max_monthly_minor": 50000,
      "currency": "usd"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "enabled": true,
      "threshold_minor": 500,
      "recharge_amount_minor": 5000,
      "max_monthly_minor": 50000,
      "currency": "USD"
    },
    "meta": {
      "request_id": "req_01HZY8EXAMPLE",
      "timestamp": "2026-08-02T12:00:00.000Z"
    }
  }
  ```
</ResponseExample>

## Billing alerts

`POST /api/v1/billing/alerts/` creates a spend or balance threshold. At least one email or SMS recipient is required; `action_on_hit` can be `notify`, `pause_outbound`, or `block_outbound`.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.orbit.devotel.io/api/v1/billing/alerts/" \
    -H "X-API-Key: dv_live_sk_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "80% of monthly budget",
      "threshold_type": "spend_percent",
      "threshold_value": 80,
      "currency": "USD",
      "notify_emails": ["billing@example.com"],
      "action_on_hit": "notify",
      "cooldown_hours": 24,
      "enabled": true
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "data": {
      "alert": {
        "id": "alert_01HZY8ALERT",
        "organization_id": "org_01HZY8ORG",
        "name": "80% of monthly budget",
        "threshold_type": "spend_percent",
        "threshold_value": 80,
        "currency": "USD",
        "notify_emails": [
          "billing@example.com"
        ],
        "notify_sms_numbers": "[]",
        "action_on_hit": "notify",
        "last_triggered_at": null,
        "cooldown_hours": 24,
        "enabled": true,
        "created_by": "user_01HZY8USER",
        "created_at": "2026-08-01T09:00:00.000Z",
        "updated_at": "2026-08-01T09:00:00.000Z"
      }
    },
    "meta": {
      "request_id": "req_01HZY8EXAMPLE",
      "timestamp": "2026-08-02T12:00:00.000Z"
    }
  }
  ```
</ResponseExample>

These samples compound; the auto-generated per-operation entries below always carry the full parameter table even where a sample here already covers the op.
