Subscriptions
Subscriptions bill a customer's card on a schedule (weekly, monthly, or yearly) after a one-time tokenization step: the customer authorizes their card once on the gateway's hosted page, and the gateway then executes the scheduled charges. Your site never sees the card.
Requirements
- A subscription product: an approved product with all three recurring fields set —
recurring_frequency(WEEKLY|MONTHLY|YEARLY),recurring_intervals,recurring_total_execution_times. Managed in the Merchant Portal like any product. - Product currency must be HKD.
- Your merchant must have the CreditCard network enabled (subscriptions are card-only).
- Exactly one product per enrollment — subscription products can't be mixed into an ordinary cart. (
/pa/checkoutrejects carts containing recurring products.) - The schedule starts on the next calendar day in Asia/Hong_Kong.
- One extra callback endpoint on your site: a payment notify URL that receives each recurring execution result for the life of the schedule.
Enrollment flow
1. Create the subscription intent
Same endpoint as ordinary checkout, different intent_details:
curl -X POST "$BASE/intent" -H "..." -H "Content-Type: application/json" -d '{
"customer_id": 42,
"store_id": 12,
"currency": "HKD",
"amount": "29.90",
"status": "C",
"reference": "5c1d33f7-9d21-4c8a-b7ee-91d5a1b7cdef",
"intent_details": "{\"source\":\"my_site_subscription\",\"merchant_reference\":\"5c1d33f7-9d21-4c8a-b7ee-91d5a1b7cdef\",\"checkout_kind\":\"subscription\",\"payment_network\":\"CreditCard\",\"subscription\":{\"product_id\":301,\"quantity\":1},\"line_items\":[{\"product_id\":301,\"quantity\":1,\"unit_amount\":\"29.90\",\"amount\":\"29.90\"}],\"subject\":\"Subscription Example Plan\"}"
}'
amount is the per-execution charge (unit price × quantity). Note checkout_kind: "subscription" and the single-line snapshot.
2. Request the tokenization launch
curl -X POST "$BASE/recurring/checkout" -H "..." -H "Content-Type: application/json" -d '{
"intent_identifier": "1a2b3c4d-....",
"customer_ip": "203.0.113.10",
"return_url": "https://shop.example.com/pingbiz/sub/return/1a2b3c4d-....",
"notify_url": "https://shop.example.com/pingbiz/sub/notify/1a2b3c4d-....",
"payment_notify_url": "https://shop.example.com/pingbiz/sub/payment-notify",
"subject": "Subscription Example Plan",
"token_valid_date": "2027-08-14"
}'
| Field | Required | Notes |
|---|---|---|
intent_identifier |
Yes | The subscription intent from step 1. |
customer_ip |
Yes | The customer's IP address. |
return_url |
Yes | Browser return after tokenization. |
notify_url |
Yes | Server-to-server tokenization result. |
payment_notify_url |
Yes | Server-to-server endpoint for every future execution — must stay live for the whole schedule. |
subject |
No | Statement/display subject. |
token_valid_date |
No | Card-token expiry hint forwarded to the gateway (YYYY-MM-DD). |
A successful response has accepted: true and a redirect_link (top-level, or under normalized_provider_result.redirect_link / provider_response.payload.redirect_link — check in that order). Redirect the customer's browser to it.
3. Record the tokenization result
When the gateway calls your subscription notify_url (or the browser returns with a signed payload), forward it:
curl -X POST "$BASE/recurring/tokenization/record" -H "..." -H "Content-Type: application/json" -d '{
"intent_identifier": "1a2b3c4d-....",
"payload": { "...raw gateway payload..." }
}'
{
"ok": true,
"checkout": {
"order_id": 123,
"status": "COMPLETE",
"idempotent": false,
"order_items": [ { "recurring_status": "ACTIVE", "recurring_merchant_reference": "…" } ]
}
}
On verified acceptance, Ping Business creates the order with exactly one order item carrying the schedule — no one-time Payment row is created for enrollment. The endpoint is idempotent; forward duplicates safely.
Confirm enrollment the same way as ordinary checkout: poll GET /intents?identifier=... for S, then read the order item and require recurring_status: "ACTIVE" and a non-empty recurring_merchant_reference before showing "subscribed".
Recurring executions
Each time the gateway executes a scheduled charge, it POSTs to your payment_notify_url. Forward every one:
curl -X POST "$BASE/recurring/payment/record" -H "..." -H "Content-Type: application/json" -d '{
"payload": { "...raw gateway payload..." }
}'
{
"ok": true,
"recurring_payment": {
"id": 801,
"order_item_id": 901,
"execution_number": 2,
"amount": "29.90",
"currency": "HKD",
"status": "SUCCESS",
"idempotent": false
}
}
Ping Business verifies the signature, matches the schedule by its merchant reference, and records the execution idempotently. Use these results to grant/extend the customer's entitlement each period.
Subscription state
The order item is the durable view of a subscription:
recurring_status |
Meaning |
|---|---|
PENDING |
Enrollment started, schedule not yet accepted. |
ACTIVE |
Schedule accepted; executions will occur. |
CANCELLED |
Schedule cancelled. |
COMPLETED |
All executions finished. |
ERROR |
Provider reported a schedule error. |
UNKNOWN |
State couldn't be determined — reconcile. |
subscription_details on the order item carries sanitized audit data (raw card/tokenization material is never returned). Read schedules with GET /order_items and watch recurring_status + execution results from your payment_notify_url.