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

# Quickstart: Recurring Payments

> Accept recurring payments with the Payment Sessions API

This guide walks through setting up recurring payments using the Payment Sessions API. The first charge uses a `first_in_series` session to collect payment and save the customer's payment method under a mandate. Each subsequent charge uses a `next_in_series` session, which a merchant initiates and processes programmatically without any customer interaction.

## Prerequisites

* A test API key. See [Authentication](/api-reference/getting-started/authentication).
* A registered webhook endpoint. See [Webhook Setup](/api-reference/webhooks/setup) to register your URL and obtain your signing key.

***

## Mandate types

A mandate is the customer's consent to authorize future charges on their payment method. When you create a `first_in_series` session, Moment establishes a mandate that defines the boundaries and constraints for all subsequent `next_in_series` payments.

By default, Moment creates an `on_demand` mandate for `first_in_series` sessions if `mandate_options` is not provided. You can explicitly set the mandate type using the `mandate_options` parameter:

* **on\_demand**: For merchant-initiated payments with no fixed schedule. Use this type for wallet top-ups, and usage-based billing. The customer consents to payments within defined constraints (such as amount limits and validity period), but recurrence is not required as part of the consent.

* **scheduled**: For recurring payments on an explicit cadence. The customer consents to payments at a specific frequency defined by `recurrence` (for example, weekly or monthly). Use this type when the payment schedule is part of the customer agreement.

See [mandate\_options](/api-reference/collect/payment_sessions/create#body-options-one-of-1-mandate-options) in the API reference for the full configuration options, including amount constraints, validity periods, and recurrence settings.

***

## Supported payment methods

The following payment methods support recurring payments:

| Payment Method  | Countries  | Supported Mandate Types  | Requirements                                               |
| --------------- | ---------- | ------------------------ | ---------------------------------------------------------- |
| **Cards**       | ZA, ZM, NG | `on_demand`, `scheduled` | None                                                       |
| **Capitec Pay** | ZA         | `scheduled` only         | Requires `recurrence` to be specified in `mandate_options` |

<Note>
  Capitec Pay supports Variable Recurring Payments (VRP) for scheduled mandates only. You must provide a `recurrence` value when creating a `first_in_series` session for Capitec Pay.
</Note>

***

## Part 1: Set up the mandate

### Step 1: Create a first\_in\_series session

Create the session server-side. The customer must be present to complete this step. They will authorise their payment method for future charges via the hosted checkout.

```bash theme={"system"}
curl -X POST https://api.momentpay.net/collect/payment_sessions \
  -H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "first_in_series",
    "amount": 5000,
    "currency": "ZAR",
    "options": {
      "customer": {
        "name": "Alex",
        "email": "alex@example.com"
      }
    }
  }'
```

<Note>
  `amount` is always specified in minor units. See [Monetary Amounts](/api-reference/getting-started/monetary_amounts) for details.
</Note>

The response includes a `session_url` for the customer to complete checkout, and a `customer_id` that was created for this customer.

```json theme={"system"}
{
  "id": "ps_eLtQXMBUErQF5i",
  "type": "first_in_series",
  "status": "active",
  "payment_status": "unpaid",
  "payment_outcome": "not_started",
  "amount": 5000,
  "currency": "ZAR",
  "customer_id": "cus_J17pnG25nuvKu",
  "session_url": "https://checkout.momentpay.net/cktaoPzVYDN0rI7FH",
  "created_at": "2025-03-18T14:13:51.379Z",
  "updated_at": "2025-03-18T14:13:51.379Z"
}
```

### Step 2: Launch the checkout

Redirect your customer to the `session_url`. During checkout, the customer completes their payment and authorises Moment to charge their payment method for future payments under the mandate.

### Step 3: Capture the customer and payment method IDs

When the customer completes checkout, Moment sends a `payment_session.completed` event. The `data` object includes both a `customer_id` and a `payment_method_id`. Store both, as you will need them for every subsequent charge.

```json theme={"system"}
{
  "id": "wh_e5cf73f1b3e4451c8c474fe56bfc688d",
  "type": "payment_session.completed",
  "data": {
    "id": "ps_eLtQXMBUErQF5i",
    "type": "first_in_series",
    "status": "completed",
    "payment_status": "paid",
    "payment_outcome": "paid",
    "amount": 5000,
    "currency": "ZAR",
    "customer_id": "cus_J17pnG25nuvKu",
    "payment_method_id": "pmt_izWG6Vcvy4VYiU",
    "payment_id": "pay_87C7PAP35KcdpzAgckBvB"
  }
}
```

Verify the event signature before processing. See [Webhook Verification](/api-reference/webhooks/verification).

***

## Part 2: Collect recurring payments

### Step 4: Create a next\_in\_series session

Use the `customer_id` and `payment_method_id` from Part 1. The customer is not present and the payment is processed immediately without any checkout step.

```bash theme={"system"}
curl -X POST https://api.momentpay.net/collect/payment_sessions \
  -H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "next_in_series",
    "amount": 5000,
    "currency": "ZAR",
    "options": {
      "customer": "cus_J17pnG25nuvKu",
      "payment_method": "pmt_izWG6Vcvy4VYiU"
    }
  }'
```

There is no `session_url` in the response. The payment processes automatically and a `payment_id` is returned immediately.

```json theme={"system"}
{
  "id": "ps_aWICss5eVG0IWZ",
  "type": "next_in_series",
  "status": "active",
  "payment_status": "unpaid",
  "payment_outcome": "not_started",
  "amount": 5000,
  "currency": "ZAR",
  "customer_id": "cus_J17pnG25nuvKu",
  "payment_id": "pay_87C7PAP35KcdpzAgckBvB",
  "created_at": "2025-03-19T07:18:22.986Z",
  "updated_at": "2025-03-19T07:18:22.986Z"
}
```

### Step 5: Handle the completion webhook

Moment sends a `payment_session.completed` event once the payment is processed, with the same structure as in Part 1.

Repeat Step 4 for each subsequent charge on the schedule your application manages.

***

## Testing

Use test card `4242 4242 4242 4242` with any future expiry date and any 3-digit CVC for the `first_in_series` checkout. See [Integration Testing](/api-reference/getting-started/testing) for the full list of test cards and error scenarios.

***
