Skip to main content
This guide walks through the bill model: creating a customer, creating an account under that customer, raising a bill against the account with a specific amount due and due date, and handling the payment webhook. This model is suited for merchants who issue discrete invoices, where each bill represents a specific charge with its own lifecycle and payment status.

Prerequisites

  • A test API key. See Authentication.
  • A registered webhook endpoint. See Webhook Setup to register your URL and obtain your signing key.

Step 1: Create a customer

Create the top-level customer record.
curl -X POST https://api.momentpay.net/billing/customers \
  -H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "external_reference": "UCR1234567890",
    "name": "John Doe",
    "email": "john.doe@example.com"
  }'
The response returns an id. Store this to reference the customer when creating the account.
{
  "id": "bcus_H4jp6KnU5cPw263v1jyz4",
  "external_reference": "UCR1234567890",
  "name": "John Doe",
  "email": "john.doe@example.com"
}

Step 2: Create an account

Create an account under the customer. Bills will be raised against this account.
curl -X POST https://api.momentpay.net/billing/accounts \
  -H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": "bcus_H4jp6KnU5cPw263v1jyz4",
    "external_reference": "UAR1234567890",
    "name": "Primary Account"
  }'
The response returns an id. Store this to reference the account when creating the bill.
{
  "id": "bacc_H4jp6KnU5cPw263v1jyz4",
  "external_reference": "UAR1234567890",
  "customer_id": "bcus_H4jp6KnU5cPw263v1jyz4",
  "name": "Primary Account"
}
Steps 1 and 2 can be combined into a single request.

Instead of passing a customer ID when creating an account, pass a customer object with the same fields used in the create customer request.

Moment creates the customer first and then creates the account. See Create Account.

Step 3: Create a bill

Raise a bill against the account with an amount_due, bill_date, and due_date.
curl -X POST https://api.momentpay.net/billing/bills \
  -H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account": "bacc_H4jp6KnU5cPw263v1jyz4",
    "external_reference": "UBR1234567890",
    "currency": "ZAR",
    "amount_due": 2000,
    "bill_date": "2025-01-01",
    "due_date": "2025-01-31"
  }'
amount_due is specified in minor units. See Monetary Amounts for details.
The response returns an id and an initial status of unpaid. Store the id to match against the payment webhook.
{
  "id": "bill_H4jp6KnU5cPw263v1jyz4",
  "external_reference": "UBR1234567890",
  "customer_id": "bcus_H4jp6KnU5cPw263v1jyz4",
  "account_id": "bacc_H4jp6KnU5cPw263v1jyz4",
  "status": "unpaid",
  "amount_due": 2000,
  "amount_paid": 0,
  "amount_remaining": 2000,
  "bill_date": "2025-01-01",
  "due_date": "2025-01-31"
}
Bills can also be raised directly against a customer without an account.

To do so, replace "account" with "customer" in the request body and use the customer id from Step 1.

In that case, the response will only include customer_id and not account_id.
All three steps can be combined into a single create bill request.

Instead of passing an account ID, pass an account object — and nest a customer object within it.

Moment creates the customer, then the account, then the bill in sequence. See Create Bill for the customer object and Create Bill for the account object.

Step 4: Present the bill for payment

Present the bill for payment using Electronic Bill Presentment or a Payment Request.

Step 5: Handle the payment webhook

When payment is received against the bill, Moment sends an obligation.amount_applied event.
{
  "id": "evt_2341234567890abcdef",
  "type": "obligation.amount_applied",
  "data": {
    "id": "ob_N2a38DJQWPL8K4X42354234",
    "amount": 2000,
    "currency": "ZAR",
    "payment_id": "pay_1313235234843nmafdsa",
    "account_id": "bacc_H4jp6KnU5cPw263v1jyz4"
  }
}
Use data.account_id to identify which account the bill belongs to, and data.amount to update the bill’s payment status.
If the bill was raised directly against a customer, the event will include customer_id instead of account_id.
Before processing, verify the event signature. See Webhook Verification. Respond with a 2xx status code to acknowledge receipt.

Next steps

Quickstart: Customer Balance

Track a single running balance directly on a customer.

Quickstart: Account Balance

Track balances across multiple sub-accounts within a customer.

Electronic Bill Presentment

Present bills to customers via a hosted payment page.

Uploading Bills

Ingest bills in bulk via SFTP or file integration.

Common Operations

Examples for updating customer balances, account balances, and bills.