Tokenised Remote Storage

Tokenisation is the replacement of sensitive payment information with a unique identifier (a token).

Therefore in WHMCS, a tokenised payment gateway module is one where the sensitive payment data is stored remotely by the payment gateway. This reduces the risk of data breaches because it means that unauthorized access to the local system does not risk exposing customer’s sensitive payment information.

Creating a Token Gateway

Payment gateways can operate tokenisation platforms in a variety of ways.

Capture Token Exchange

At its simplest, a payment gateway may exchange or return a token for you to use for future charges following a regular capture being performed.

For payment gateways that function in this way, you should return the token along with the result from the capture function. WHMCS will then automatically purge the locally stored payment details and replace them with the token.

The following return parameters are supported.

Parameter Type Description
status string One of either success, pending, declined
declinereason string The reason for a decline
transid string The Transaction ID returned by the payment gateway
fee float The transaction fee returned by the payment gateway
rawdata string or array The raw data returned by the payment gateway for logging to the gateway log to aid in debugging
gatewayid string The token returned by the payment gateway

Example

function yourmodulename_capture($params) {
    $gatewayid = $params['gatewayid'];
    $cardnum = $params['cardnum'];
    
    if ($gatewayid) {
        // Make API call to perform capture using the token here
        // Dummy response assumed below in $response variable.        

        return [
            'status' => 'success',
            'transid' => $response['transaction_id']
            // Return a value in gatewayid to update the token only if required
            'gatewayid' => $response['token'],
            'rawdata' => $response,
        ];
    } else {
        // Make API call to perform capture using the card number here
        // Dummy response assumed below in $response variable.
        $response = [];

        return [
            'status' => 'success',
            'transid' => $response['transaction_id']
            'gatewayid' => $response['token'],
            'rawdata' => $response,
        ];
    }
}

Remote Storage

For payment gateways where tokens have to be created and managed separately from capture attempts, you should use the remote storage method within your WHMCS gateway module.

This function will override the default behaviour when entering new, updating an existing, or deleting credit card details.

The following parameters are passed into the storeremote function.

Parameter Type Description
action string One of either create, update, or delete
gatewayid string The token for the pay method to be updated
cardtype string The card type (Visa, MasterCard, etc..)
cardnum string The card number
cardexp int The card expiry date (Format: MMYY)
cardstart int The card start date (Format: MMYY)
cardissuenum int The card issue number

The following return parameters are supported.

Parameter Type Description
status string One of either success or error
rawdata string or array The raw data returned by the payment gateway for logging to the gateway log to aid in debugging
gatewayid string The token returned by the payment gateway

Example

function yourmodulename_storeremote($params) {
    $action = $params['action'];
    $gatewayid = $params['gatewayid'];
    $cardtype = $params['cardtype'];
    $cardnum = $params['cardnum'];
    $cardexp = $params['cardexp'];
    $cardstart = $params['cardstart'];
    $cardissuenum = $params['cardissuenum'];

    switch ($action) {
        case 'create':
            // Make API call to create a token here
            $postfields = [
                'cardnumber' => $cardnum,
                'cardexpiry' => $cardexp,
                'cardcvv' => $params['cccvv'],
            ];
        
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, 'https://www.example.com/api/store');
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $response = curl_exec($ch);
            curl_close($ch);
        
            $data = json_decode($response);

            return [
                'status' => 'success',
                'gatewayid' => $data->remote_id,
            ];
            break;
        case 'update':
            // Make API call to update a token here
            $postfields = [
                'remote_id' => $gatewayid,
                'cardexpiry' => $cardexp,
            ];
        
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, 'https://www.example.com/api/update');
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $response = curl_exec($ch);
            curl_close($ch);
        
            $data = json_decode($response);
            return [
                'status' => 'success',
                'gatewayid' => $data->remote_id,
            ];
            break;
        case 'delete':
            // Make API call to delete a token here
            $postfields = [
                'remote_id' => $gatewayid,
            ];
        
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, 'https://www.example.com/api/delete');
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $response = curl_exec($ch);
            curl_close($ch);
        
            $data = json_decode($response);
            return [
                'status' => 'success',
            ];
            break;
    }
}