Skip to main content
POST
/
api
/
v2.0
/
recurring
/
plans
Create Plan
curl --request POST \
  --url https://sandbox-payment-b2b.singapay.id/api/v2.0/recurring/plans \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --header 'X-PARTNER-ID: <api-key>' \
  --data '
{
  "name": "Monthly Pro Subscription",
  "customer_name": "John Doe",
  "customer_email": "john.doe@example.com",
  "customer_phone": "081234567890",
  "account_id": "01K5G4FZZ18DMK0M5QTR8Y9QY9",
  "schedule": {
    "interval": 1,
    "interval_unit": "month",
    "start_time": "2026-07-01T00:00:00+07:00",
    "total_interval": 12
  },
  "subscription_id": "SUB-2026-0001",
  "merchant_reff_no": "REF-0001",
  "amount": 150000,
  "currency": "IDR",
  "items": [
    {
      "item_name": "Pro Plan License",
      "quantity": 1,
      "unit_price": 50000,
      "item_type": "subscription"
    }
  ],
  "customer_id": "CUST-001",
  "payment_type": "credit_card",
  "return_url": "https://merchant.example.com/subscription/return",
  "retry_policy": {
    "max_attempts": 3,
    "interval_days": 1,
    "failed_payment_action": "continue_plan"
  },
  "retry_count": 3,
  "retry_interval_days": 1,
  "failed_payment_action": "continue_plan",
  "charge_immediately": false,
  "allow_manual_payment": true,
  "allow_user_notification": true,
  "metadata": {
    "description": "Pro plan monthly billing"
  }
}
'
{
  "response_code": "SP000",
  "response_message": "Successfully",
  "data": {
    "id": "9f8b6c2e-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
    "name": "Monthly Pro Subscription",
    "amount": "150000",
    "currency": "IDR",
    "created_at": "2026-06-09T10:00:00+07:00",
    "schedule": {
      "interval": 1,
      "interval_unit": "month",
      "current_interval": 1,
      "total_interval": 12,
      "start_time": "2026-07-01T00:00:00+07:00",
      "previous_payment_at": null,
      "next_payment_at": "2026-07-01T00:00:00+07:00"
    },
    "status": "active",
    "payment_type": "credit_card",
    "retry_policy": {
      "max_attempts": 3,
      "interval_days": 1,
      "failed_payment_action": "continue_plan"
    },
    "metadata": {
      "description": "Pro plan monthly billing",
      "extra": []
    },
    "subscription_id": "SUB-2026-0001",
    "merchant_reff_no": "REF-0001",
    "payment_link_url": "https://pay.singapay.id/sub/9f8b6c2e",
    "parent_plan_id": null,
    "created_from": null
  }
}

Authorizations

Authorization
string
header
required

JWT issued by POST /api/v1.1/access-token/b2b. Send Authorization: Bearer <token>.

X-PARTNER-ID
string
header
required

Merchant API key (Credential.api_key). Required on every request.

Body

application/json

Payload for CreateSubscriptionPlanRequest. Exactly one of amount or items must be present (mutually exclusive). Per-cycle charge (amount-only or sum of quantity * unit_price) must be at least IDR 10,000 when greater than zero (ChannelType::MIN_CARD_AMOUNT_IDR).

name
string
required

Human-readable plan name.

Maximum string length: 255
Example:

"Monthly Pro Subscription"

customer_name
string
required

Full name of the subscribing customer.

Maximum string length: 191
Example:

"John Doe"

customer_email
string<email>
required

Customer email address.

Maximum string length: 191
Example:

"john.doe@example.com"

customer_phone
string
required

Customer contact phone number.

Maximum string length: 50
Example:

"081234567890"

account_id
string
required

Account ULID owned by the authenticated merchant.

Maximum string length: 50
Example:

"01K5G4FZZ18DMK0M5QTR8Y9QY9"

schedule
object
required

Billing schedule that controls how often and how many times the plan charges the customer.

subscription_id
string | null

Stored in sub_plans.reference_id; must be unique on that column when provided.

Maximum string length: 100
Example:

"SUB-2026-0001"

merchant_reff_no
string | null

Optional merchant reference number for reconciliation.

Maximum string length: 255
Example:

"REF-0001"

amount
number

Per-cycle charge in IDR. Use without items for amount-only plans.

Required range: x >= 0
Example:

150000

currency
string | null

ISO 4217 currency code. Defaults to IDR.

Required string length: 3
Example:

"IDR"

items
object[]

Use without amount for itemized plans; per-cycle total = sum of quantity * unit_price.

Minimum array length: 1
customer_id
string | null

Optional merchant-side customer identifier.

Maximum string length: 100
Example:

"CUST-001"

payment_type
enum<string> | null

Preferred payment instrument for the plan.

Available options:
credit_card,
gopay
Example:

"credit_card"

return_url
string<uri> | null

URL the customer is redirected to after completing payment setup.

Maximum string length: 2048
Example:

"https://merchant.example.com/subscription/return"

retry_policy
object | null

Optional retry policy applied to every cycle when a charge fails.

retry_count
integer | null
deprecated

Deprecated — use retry_policy.max_attempts.

Required range: 1 <= x <= 5
Example:

3

retry_interval_days
integer | null
deprecated

Deprecated — use retry_policy.interval_days.

Required range: 1 <= x <= 7
Example:

1

failed_payment_action
enum<string> | null
deprecated

Deprecated — use retry_policy.failed_payment_action.

Available options:
continue_plan,
stop_plan
Example:

"continue_plan"

charge_immediately
boolean | null

Charge the first cycle immediately on creation instead of waiting for start_time.

Example:

false

allow_manual_payment
boolean | null

Allow the customer to pay bills manually via the payment link.

Example:

true

allow_user_notification
boolean | null

Send subscription notifications (reminders, receipts) to the customer.

Example:

true

metadata
object | null

Free-form metadata stored with the plan.

Response

SP000 Successfully — plan created (data is RecurringPlanData).

Merchant v2 envelope returned on a successful plan operation (SP000). Used by create (HTTP 201), show, update, and cancel (HTTP 200). The data.upgrade block is present only on an upgrade/downgrade.

response_code
string
required

SingaPay custom business response code.

Example:

"SP000"

response_message
string
required

Human-readable label paired with response_code.

Example:

"Successfully"

data
object
required

data object shape from SubscriptionPlanResource (success responses).