Skip to main content

Overview

Keep customers on your site when they set up a recurring payment method. Instead of redirecting them to a HitPay-hosted page, use generate_embed: true to receive a link or setup instructions directly in the API response — ready to render in your own UI.
Embedded Recurring APMs

Supported Payment Methods

Payment MethodCodeResponse type
Shopee Payshopee_paydirect_link (web URL)
GrabPaygrabpay_directdirect_link (web URL)
Touch ‘N Gotouch_n_godirect_link (web URL)
GIROgiroinstructions
The payment method determines what the API returns — you don’t choose. Redirect-based APMs return a direct_link; GIRO returns manual setup instructions.

How It Works

1

Create a Recurring Billing with generate_embed: true

Call POST /v1/recurring-billing with generate_embed: true and exactly one payment_methods[] entry. The API initiates the APM setup immediately and returns direct_link or instructions inline.
2

Present the Link or Instructions

Render the returned data in your UI: show the link as a button or display the setup steps for GIRO.
3

Customer Completes Setup

The customer taps the link or follows the GIRO instructions.
4

Receive Webhooks

HitPay fires recurring_billing.method_attached and recurring_billing.subscription_updated when the payment method is linked and the subscription activates. If a charge is made, charge.created is fired — listen to this event to confirm a successful payment.

Step 1: Create a Recurring Billing

Endpoint

POST /v1/recurring-billing

Request Parameters

When using generate_embed: true, you must specify exactly one entry in payment_methods[]. For redirect-based methods (shopee_pay, grabpay_direct, touch_n_go), redirect_url is also required.
ParameterDescriptionExample
nameRequired. Name for this billing session.Spotify Premium
customer_emailRequired. Customer’s email address.paul@hitpayapp.com
customer_nameRequired. Customer’s name.Paul
amountRequired. Amount to display (minimum 1.00).9.90
save_payment_methodSet to true to save the payment method.true
currencyCurrency code.sgd
payment_methods[]Required. Exactly one method when using generate_embed.grabpay_direct
generate_embedSet to true to receive a link or instructions inline.true
redirect_urlRequired for redirect-based methods (shopee_pay, grabpay_direct, touch_n_go). Not required for giro.https://example.com/success
descriptionDescription shown to the customer.Spotify Membership
referenceYour internal reference ID for this customer or session.cust_123
send_emailSend email receipt to customer. Default: false.true
customer_phone_numberRequired for shopee_pay. Customer’s phone number.91234567
customer_phone_number_country_codeRequired for shopee_pay. Country code of the phone number.65

Example Requests

curl --location --request POST 'https://api.sandbox.hit-pay.com/v1/recurring-billing' \
--header 'X-BUSINESS-API-KEY: your_api_key' \
--header 'X-Requested-With: XMLHttpRequest' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'name=Spotify Premium' \
--data-urlencode 'customer_email=tan@example.com' \
--data-urlencode 'customer_name=Tan Ah Kow' \
--data-urlencode 'amount=9.90' \
--data-urlencode 'currency=sgd' \
--data-urlencode 'save_payment_method=true' \
--data-urlencode 'payment_methods[]=shopee_pay' \
--data-urlencode 'generate_embed=true' \
--data-urlencode 'customer_phone_number=91234567' \
--data-urlencode 'customer_phone_number_country_code=65' \
--data-urlencode 'redirect_url=https://merchant.com/billing/complete'

Step 2: Present the Response in Your UI

The response includes all the standard recurring billing fields plus one of the following objects depending on the payment method. Render direct_link_url as a button (e.g. “Authorise with Shopee Pay”). On mobile, use direct_link_app_url to open the payment app directly if available.
{
  "id": "9741164c-06a1-4dd7-a649-72cca8f9603a",
  "customer_name": "Tan Ah Kow",
  "customer_email": "tan@example.com",
  "name": "Spotify Premium",
  "cycle": "save_card",
  "cycle_repeat": null,
  "cycle_frequency": null,
  "currency": "sgd",
  "amount": 9.9,
  "status": "scheduled",
  "save_payment_method": 1,
  "payment_methods": ["shopee_pay"],
  "redirect_url": "https://merchant.com/billing/complete",
  "direct_link": {
    "direct_link_url": "https://shopeepay.sg/u/account-linking-agreement_sg?client_id=abc123...",
    "direct_link_app_url": "shopeesg://main?apprl=%2Frn%2FTRANSFER_PAGE%3F..."
  },
  "created_at": "2026-04-01T15:00:00",
  "updated_at": "2026-04-01T15:00:00"
}
FieldTypeDescription
direct_link_urlstringWeb redirect URL. Always present. Use this on desktop or as a fallback on mobile.
direct_link_app_urlstring | nullApp deep link for mobile app-to-app flows. Present for Shopee Pay; null for GrabPay and Touch ‘N Go.

Instructions (instructions) — GIRO

Display the steps as a numbered list. Make the reference value copyable so the customer can paste it into their banking portal.
{
  "id": "9741164c-06a1-4dd7-a649-72cca8f9603b",
  "customer_name": "Lim Wei",
  "customer_email": "lim@example.com",
  "name": "Spotify Premium",
  "cycle": "save_card",
  "cycle_repeat": null,
  "cycle_frequency": null,
  "currency": "sgd",
  "amount": 9.9,
  "status": "scheduled",
  "save_payment_method": 1,
  "payment_methods": ["giro"],
  "instructions": {
    "reference": "RPSHISXMB1E",
    "steps": [
      "Log in to your DBS/POSB Internet Banking Account on the Web",
      "Click on Pay > Add GIRO Arrangement",
      "Under Billing Organisation, select HitPay",
      "Add RPSHISXMB1E as Bill Reference",
      "Enter 0 under Payment Limit",
      "Click on Next and hit Submit"
    ]
  },
  "created_at": "2026-04-01T15:00:00",
  "updated_at": "2026-04-01T15:00:00"
}
FieldTypeDescription
referencestringThe bill reference the customer enters in their banking portal.
stepsstring[]Ordered setup instructions. Display as a numbered list.

Step 3: Customer Completes Setup

Shopee Pay / GrabPay / TNG

Customer taps the link or is redirected to the provider’s authorisation page, then returns to your redirect_url.

GIRO

Customer logs in to DBS/POSB internet banking and follows the displayed steps. This may take 1–3 business days to activate.

Step 4: Handle Webhooks

Register Your Webhook

  1. Navigate to Developers > Webhook Endpoints in your dashboard
  2. Click New Webhook
  3. Enter a name and your webhook URL
  4. Select the events you want to receive:
    • recurring_billing.method_attached — Payment method successfully linked
    • recurring_billing.subscription_updated — Subscription status changes (e.g., scheduledactive)
    • charge.created — A charge was successfully processed.
  5. Save your webhook configuration

Webhook Payload

When a payment is completed, HitPay sends a JSON payload to your registered webhook URL with the following headers:
HTTP HeaderDescription
Hitpay-SignatureHMAC-SHA256 signature of the JSON payload, using your salt value
Hitpay-Event-Typecompleted
Hitpay-Event-Objectpayment_request
User-AgentHitPay v2.0

Validating the Webhook

To ensure the webhook is authentic, validate the Hitpay-Signature header:
  1. Receive the JSON payload and Hitpay-Signature from the request
  2. Use your salt value (from the dashboard) as the secret key
  3. Compute HMAC-SHA256 of the JSON payload using your salt
  4. Compare the computed signature with Hitpay-Signature - they must match
function validateWebhook($payload, $signature, $salt) {
    $computedSignature = hash_hmac('sha256', $payload, $salt);
    return hash_equals($computedSignature, $signature);
}

// Usage
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_HITPAY_SIGNATURE'];
$salt = 'your_salt_from_dashboard';

if (validateWebhook($payload, $signature, $salt)) {
    $data = json_decode($payload, true);
    // Process the payment confirmation
    // Mark order as paid
} else {
    http_response_code(401);
    exit('Invalid signature');
}

FAQs

No. generate_embed defaults to false. If you don’t send it, the API behaves exactly as before — returning the HitPay hosted page url. No migration required.
No. Generate embed only works for APMs.
Existing webhook retry logic applies. You can also check the recurring billing status via GET /v1/recurring-billing/{id} — if the method is linked, status will be active.
  • Change the base URL to https://api.hit-pay.com/v1/
  • Update API keys and salt values from the production dashboard
  • Ensure the APM provider is onboarded in your production account
  • Register your webhook URL in production and subscribe to recurring_billing.method_attached and recurring_billing.subscription_updated