Skip to main content
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.
  • A registered webhook endpoint. See Webhook Setup to register your URL and obtain your signing key.

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.
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"
      }
    }
  }'
amount is always specified in minor units. See Monetary Amounts for details.
The response includes a session_url for the customer to complete checkout, and a customer_id that was created for this customer.
{
  "id": "ps_eLtQXMBUErQF5i",
  "type": "first_in_series",
  "status": "active",
  "payment_status": "unpaid",
  "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.
{
  "id": "wh_e5cf73f1b3e4451c8c474fe56bfc688d",
  "type": "payment_session.completed",
  "data": {
    "id": "ps_eLtQXMBUErQF5i",
    "type": "first_in_series",
    "status": "completed",
    "payment_status": "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.

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.
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.
{
  "id": "ps_aWICss5eVG0IWZ",
  "type": "next_in_series",
  "status": "active",
  "payment_status": "unpaid",
  "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 for the full list of test cards and error scenarios.