This is a Money In operation. Each cycle charge transfers funds from the customer’s tokenized card to your Singapay Payment Gateway account.
API Version
v2.0
Base Path
/api/v2.0/recurring/plansAuth
Bearer Token (JWT)
Channel
Credit Card (recurring)
Subscription lifecycle
Plan status lifecycle
| Status | Description |
|---|---|
pending_card_linking | Plan created, awaiting customer to complete card linking via payment_link_url. |
pending_payment | Card linked, awaiting scheduled start (schedule.start_time is in the future). |
active | Subscription running — cycles auto-charged on schedule. |
paused | Merchant-initiated pause from the dashboard. No charges while paused. |
suspended | Auto-suspended after retries exhausted (when failed_payment_action = stop_plan). |
cancelled | Cancelled by merchant or auto-cancelled on hard failure during initial card linking. Terminal state. |
completed | All scheduled cycles charged (only for plans with total_interval set). |
Initial card linking — auto-cancel on hard failure
When an auto-cancel occurs:- The bill for that cycle moves to
cancelled - The plan transitions from
pending_payment/pending_card_linkingdirectly tocancelled - The active payment link is expired — the customer cannot complete a charge against the cancelled plan
- A
subscription.plan.status_changedwebhook fires withplan.metadata.cancellation_reason = initial_linking_failed
Plans created with
charge_immediately = false are not affected by this rule. To re-attempt after a hard failure, create a new plan.Amount vs. items
A plan is either amount-only or itemized — never both. This is enforced on both Create and Update.Amount-only
Send
amount. The entire recurring charge is a single line item — simple and straightforward.Itemized
Send
items[]. The per-cycle charge is the sum of quantity × unit_price across all items.Retry policy
When a cycle charge fails, Singapay automatically retries based on the plan’s configured policy.| Field | Type / Range | Description |
|---|---|---|
retry_policy.max_attempts | integer, 1–5 | Automatic retry attempts after the initial charge fails. |
retry_policy.interval_days | integer, 1–7 | Days to wait between consecutive retry attempts. |
retry_policy.failed_payment_action | continue_plan | stop_plan | Behavior after retries exhausted. continue_plan keeps the subscription running on the next cycle; stop_plan suspends it. |
Error reference
HTTP status codes
HTTP status codes
| Code | Description |
|---|---|
200 | Success (show, update, cancel) |
201 | Created (create plan) |
400 | Bad Request — validation or business rule error |
401 | Unauthorized — invalid or missing token |
404 | Plan or account not found |
409 | Plan cannot be updated or already cancelled |
422 | Validation error — missing field, amount/items conflict, etc. |
500 | Internal server error |
Singapay response codes
Singapay response codes
| Code | Description | HTTP Status |
|---|---|---|
SP000 | Success | 200 / 201 |
SP002 | General failure (internal error) | 500 |
SP020 | Merchant account not found | 404 |
SP100 | Subscription plan not found | 404 |
SP101 | Subscription plan already cancelled | 409 |
SP102 | Subscription plan cannot be updated in current state | 409 |
Important notes
Card-only channel
Card-only channel
Subscriptions run exclusively on credit card recurring. The initial card linking uses one-time 3DS; all subsequent cycle charges use the tokenized card silently — no customer action needed.
Minimum amount
Minimum amount
The per-cycle charge must clear the card channel minimum. Plans below this floor are rejected on both Create and Update with a
422 validation error.Plan identifiers
Plan identifiers
subscription_id is a globally unique merchant-supplied identifier across all plans for the merchant. merchant_reff_no is an optional, non-unique label for grouping and reporting — echoed back on every cycle webhook.Upgrade semantics (PATCH)
Upgrade semantics (PATCH)
A PATCH that changes
amount or items triggers the full upgrade flow — the existing plan is closed and a new plan is created with parent_plan_id pointing at it, plus an optional proration and a fresh payment link.A PATCH that only changes name, merchant_reff_no, or metadata patches the plan in place without creating a new plan.IP whitelisting required
IP whitelisting required
All Merchant API routes require IP whitelisting. Ensure your server IP is registered for the merchant account before making any API calls.
Available endpoints
Create Recurring Plan
Register a new plan. Returns a
payment_link_url for the customer’s one-time card linking.Get Recurring Plan
Fetch current plan state — status, schedule progress, next payment date, retry policy, and lineage.
Update or Upgrade Plan
Patch cosmetic fields in place, or change amount / items to trigger the upgrade flow with a new plan and optional proration.
Cancel Plan
Stop a plan immediately. Active plans go through the lifecycle service; pending plans are cancelled outright.
All endpoints require authentication. See Authentication.
Changelog
| Date | Description |
|---|---|
| 2026-04-20 | Initial documentation — Subscription Merchant API v2.0 (create, show, update/upgrade, cancel) + Subscription Cycle webhook. |
