Recurring Billing

Recurring Billing APIs are the simplest way to start collecting your monthly or yearly subscription fees automatically.

This API integration includes 4 Steps

3336

Step 1 - Create a subscription plan

A subscription plan consists of basic information like plan name, amount, and frequency. An example of a subscription plan could be “Spotify Premium” which is SGD 9.90 monthly.

HTTP Request

POST 'https://api.sandbox.hit-pay.com/v1/subscription-plan'

Query Parameters

Mandatory fields are name, cycle and amount. Remember to include header Content-Type: application/x-www-form-urlencoded
ParameterDescriptionExample
namePlan nameSpotify Premium
descriptionThe description of the subscription planSpotify Monthly Subscription
cycleBilling frequency (weekly / monthly / yearly / custom / save_card). If cycle = custom then the user has to send the fields cycle_repeat and cycle_frequencymonthly
cycle_repeat[This field is only applicable when cycle = custom] It's the number of times the cycle will repeat.4
cycle_frequency[This field is only applicable when cycle = custom] It's the frequency of the cycle [day / week / month / year]week
currencyCurrency related to the recurring billingSGD
amountAmount related to the recurring billing9.90
referenceArbitrary reference number that you can map to your internal reference number. This value cannot be edited by the customerXXXX123
curl --location --request POST 'https://api.sandbox.hit-pay.com/v1/subscription-plan' \
--header 'X-BUSINESS-API-KEY: meowmeowmeow' \
--header 'X-Requested-With: XMLHttpRequest' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'name=Spotify Premium' \
--data-urlencode 'description=Spotify Monthly Subscription' \
--data-urlencode 'currency=SGD' \
--data-urlencode 'amount=9.90' \
--data-urlencode 'cycle=monthly' \
--data-urlencode 'reference=spotify_premium_2022'
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.staging.hit-pay.com/v1/subscription-plan', [
  'form_params' =>[
    'name' => 'Spotify Premium',
    'description' => 'Spotify Monthly Subscription',
    'currency' => 'SGD'
    'amount' => 9.90,
    'cycle' => 'monthly',
    'reference' => 'spotify_premium_2022'
  ],
  'headers' => [
    'Content-Type' => 'application/x-www-form-urlencoded',
    'X-Requested-With' => 'XMLHttpRequest',
    'accept' => 'application/json',
    'x-api-key' => 'meowmeowmeow',
  ],
]);

echo $response->getBody();

Response

{
    "id": "973ee344-6737-4897-9929-edbc9d7bf433",
    "name": "Spotify Premium",
    "description": "Spotify Monthly Subscription",
    "cycle": "monthly",
    "cycle_repeat": null,
    "cycle_frequency": null,
    "currency": "sgd",
    "amount": 9.90,
    "reference": "spotify_premium_2022",
    "created_at": "2022-09-12T14:19:26",
    "updated_at": "2022-09-12T14:19:26"
}

Step 2 - Create a recurring billing for the customer

Once your customer has decided to start the subscription this endpoint will create the recurring billing request.
Since this is a server-to-server communication, if you have a mobile or Web client that communicates with your REST API, you must have a new endpoint E.g. /create-subscription or reuse an existing endpoint. This endpoint will be responsible for making the recurring billing API call to hitpay.

HTTP Request

POST 'https://api.sandbox.hit-pay.com/v1/recurring-billing'

Query Parameters

Mandatory fields areplan_id, customer_email and start_date. If you would like to create a subscription without a plan you have to send plan_id = null and the following mandatory fields name, cycle, amount, customer_email and start_date. Remember to include header Content-Type: application/x-www-form-urlencoded
ParameterDescriptionExample
plan_idSubscription plan id created from step 1973ee344-6737-4897-9929-edbc9d7bf433
customer_emailCustomer email[email protected]
customer_nameCustomer namePaul
start_dateBilling start date (YYYY-MM-DD) in SGT2022-11-11
amountBy default, the amount from the subscription plan will be used. You can use this parameter for discounts for specific customers.7.90
currencyCurrency related to the recurring billingSGD
payment_methods[]Choice of payment methods you want to offer the customergiro, card
redirect_urlURL where hitpay redirects the user after the users enters the card details and the subscription is active. Query arguments reference  (subscription id) and  status  are sent alonghttps://spotify.com/subscription-completed
referenceArbitrary reference number that you can map to your internal reference number. This value cannot be edited by the customerXXXX123
webhookOptional URL value to which hitpay will send a POST request when there is a new charge or if there is an error charging the cardhttps://webhoo.site/test
send_emailHitpay to send email receipts to the customer. Default value is falsetrue
times_to_be_chargedHow many times to charge the customer3
curl --location --request POST 'https://api.sandbox.hit-pay.com/v1/recurring-billing' \
--header 'X-BUSINESS-API-KEY: meowmeowmeow' \
--header 'X-Requested-With: XMLHttpRequest' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'plan_id=973ee344-6737-4897-9929-edbc9d7bf433' \
--data-urlencode '[email protected]' \
--data-urlencode 'customer_name=Paul' \
--data-urlencode 'start_date=2022-11-11' \
--data-urlencode 'redirect_url=https://spotify.com/subscription-completed' \
--data-urlencode 'reference=cust_id_123' \
--data-urlencode 'payment_methods[]=giro' \
--data-urlencode 'payment_methods[]=card' \
--data-urlencode 'webhook=https://webhoo.site/test' \
--data-urlencode 'send_email=true' \
--data-urlencode 'times_to_be_charged=3'

Response

{
    "id": "9741164c-06a1-4dd7-a649-72cca8f9603a",
    "business_recurring_plans_id": "973ee344-6737-4897-9929-edbc9d7bf433",
    "customer_name": "Paul",
    "customer_email": "[email protected]",
    "name": "Spotify Premium",
    "description": "Spotify Monthly Subscription",
    "reference": "cust_id_123",
    "cycle": "monthly",
    "cycle_repeat": null,
    "cycle_frequency": null,
    "currency": "sgd",
    "amount": 9.90,
    "times_to_be_charged": 3,
    "times_charged": 0,
    "status": "scheduled",
    "send_email": false,
    "save_card": 0,
    "redirect_url": "https://github.com/",
    "payment_methods": [
        "giro",
        "card"
    ],
    "created_at": "2022-09-13T16:33:47",
    "updated_at": "2022-09-13T16:33:47",
    "expires_at": "2022-11-11T23:59:59",
    "url": "https://securecheckout.staging.hit-pay.com/973ee344-6737-4897-9929-edbc9d7bf433/recurring-plan/9741164c-06a1-4dd7-a649-72cca8f9603a",
    "webhook": "https://webhoo.site/test"
}

Step 3 - Redirect customer to recurring billing page (One time set up)

Redirect the customer to the “url” value.

2370

Once the customer completes the payment information it will be redirect to “redirect_url”

Step 4: Handle Successful Payment

Webhooks

HitPay will send a Webhook POST request when there is a new charge or if there is an error charging the card.
If you are using HitPay APIs to integrate into your app you must mark your order as paid ONLY after the webhook is received and validated.

  1. Create an endpoint (E.g. /payment-confirmation/webhook) in your server that accepts POST requests. This request is application/x-www-form-urlencoded.
  2. Validate the webhook data using your salt value
  3. Return HTTP status code 200 to Hitpay
  4. Mark your order as paid
payment_id=974f65d6-88ea-42a0-a67a-15acafc4dc66&recurring_billing_id=9741164c-06a1-4dd7-a649-72cca8f9603a&amount=9.90&currency=sgd&status=succeeded&reference=cust_id_123&hmac=7690ff7ab7d88480a480b8be722f6dd12cc58f489da25c504dbe29c04b297418

Webhook fields

Following fields are sent with the webhook request:

ParameterDescription
payment_idPayment ID
recurring_billing_idRecurring billing request ID
amountAmount related to the recurring billing
currencyCurrency related to the recurring billing
statusPayment status (succeeded / failed)
referenceArbitrary reference number that you have mapped during recurring billing request creation
hmacMessage Authentication code of this webhook request

Validate Webhook

Hitpay creates a list of all values from the key-value pairs that we send in the POST request and sort them in the order of their keys alphabetically. We then concatenate all these values together. We then use the HMAC-SHA256 algorithm to generate the signature. The HMAC key for the signature generation is the secret salt from your dashboard under Settings > Payment Gateway > API Keys.

public function generateSignatureArray($secret, array $args) 
    {   
        $hmacSource = [];        

        foreach ($args as $key => $val) {
            $hmacSource[$key] = "{$key}{$val}";
        }    

        ksort($hmacSource);

        $sig            = implode("", array_values($hmacSource));
        $calculatedHmac = hash_hmac('sha256', $sig, $secret); 

        return $calculatedHmac;
    }

Signature Mismatch?

Possible reasons for wrong hmac value generated

  1. Ensure that you are using the correct salt value from the correct environment (Sandbox or Production)
  2. Make sure NOT to include the hamc value when calculating the hmac
  3. Make sure all the values stated above are included in the payload including reference. Use an empty string if the value does not exist

Next Step

Congrats! You have now successfully completed the recurring billing integration.

Refund API: This is an optional API call, you may use this to refund a specific payment.
Production Checklist: Checkout before you go live.
Getting Started: Reference to the API Details