├── .gitignore ├── composer.json ├── LICENSE ├── whmcs.json ├── README.md └── modules └── gateways ├── callback └── merchantgateway.php └── merchantgateway.php /.gitignore: -------------------------------------------------------------------------------- 1 | # PHPUnit 2 | phpunit.xml 3 | 4 | # Composer 5 | composer.phar 6 | composer.lock 7 | vendor/* 8 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "whmcs/sample-merchant-gateway", 3 | "description": "Sample Merchant Gateway Module for the WHMCS Billing Automation Platform", 4 | "keywords": [ 5 | "whmcs", 6 | "web host automation platform", 7 | "merchant gateway module", 8 | "gateway module", 9 | "3d secure" 10 | ], 11 | "homepage": "http://www.whmcs.com/", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "WHMCS Development Team", 16 | "email": "development@whmcs.com", 17 | "homepage": "http://www.whmcs.com/", 18 | "role": "Developer" 19 | } 20 | ], 21 | "support": { 22 | "email": "support@whmcs.com", 23 | "forum": "http://forums.whmcs.com/", 24 | "wiki": "http://docs.whmcs.com/" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 WHMCS, Limited 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /whmcs.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": "1.0", 3 | "type": "whmcs-gateways", 4 | "name": "sample-merchant-gateway", 5 | "license": "MIT", 6 | "category": "gateway", 7 | "description": { 8 | "name": "Sample Merchant Gateway Module", 9 | "tagline": "Payment Gateway modules allow you to integrate payment solutions with the WHMCS platform.", 10 | "long": "The sample files here demonstrate how we suggest a Merchant Payment Gateway module for WHMCS be structured and implemented.", 11 | "features": [ 12 | "Provide structure for 3D Secure Authentication", 13 | "Provide structure for payment capture", 14 | "Provide structure for payment refund" 15 | ] 16 | }, 17 | "logo": { 18 | "filename": "logo.png" 19 | }, 20 | "support": { 21 | "homepage": "https:\/\/www.whmcs.com\/", 22 | "learn_more": "https:\/\/www.whmcs.com\/tour", 23 | "email": "support@whmcs.com", 24 | "support_url": "https:\/\/support.whmcs.com\/", 25 | "docs_url": "https:\/\/developers.whmcs.com\/payment-gateways\/" 26 | }, 27 | "authors": [ 28 | { 29 | "name": "WHMCS", 30 | "homepage": "https:\/\/www.whmcs.com\/" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WHMCS Sample Merchant Gateway Module # 2 | 3 | ## Summary ## 4 | 5 | Payment Gateway modules allow you to integrate payment solutions with the WHMCS 6 | platform. 7 | 8 | There are two types of gateway module: 9 | 10 | * Third Party Gateways - these are payment solutions where checkout occurs 11 | on a remote website, usually hosted by the payment gateway themselves. 12 | 13 | * Merchant Gateways - these are payment solutions where credit card details 14 | are collected - usually within the WHMCS application, though more and more 15 | often this will be done remotely, typically via an iframe, with a page hosted 16 | remotely by the payment gateway enabling tokenised storage. 17 | 18 | The sample files here demonstrate how we suggest a Merchant Payment Gateway 19 | module for WHMCS be structured and implemented. 20 | 21 | For more information, please refer to the documentation at: 22 | https://developers.whmcs.com/payment-gateways/ 23 | 24 | ## Recommended Module Content ## 25 | 26 | The recommended structure of a merchant gateway module is as follows. 27 | 28 | ``` 29 | modules/gateways/ 30 | |- callback/merchantgateway.php 31 | | merchantgateway.php 32 | ``` 33 | 34 | ## Minimum Requirements ## 35 | 36 | For the latest WHMCS minimum system requirements, please refer to 37 | https://docs.whmcs.com/System_Requirements 38 | 39 | We recommend your module follows the same minimum requirements wherever 40 | possible. 41 | 42 | ## Useful Resources 43 | * [Developer Resources](https://developers.whmcs.com/) 44 | * [Hook Documentation](https://developers.whmcs.com/hooks/) 45 | * [API Documentation](https://developers.whmcs.com/api/) 46 | 47 | [WHMCS Limited](https://www.whmcs.com) 48 | -------------------------------------------------------------------------------- /modules/gateways/callback/merchantgateway.php: -------------------------------------------------------------------------------- 1 | 'Sample Merchant Gateway Module', 42 | 'APIVersion' => '1.1', // Use API Version 1.1 43 | ); 44 | } 45 | 46 | /** 47 | * Define gateway configuration options. 48 | * 49 | * The fields you define here determine the configuration options that are 50 | * presented to administrator users when activating and configuring your 51 | * payment gateway module for use. 52 | * 53 | * Supported field types include: 54 | * * text 55 | * * password 56 | * * yesno 57 | * * dropdown 58 | * * radio 59 | * * textarea 60 | * 61 | * Examples of each field type and their possible configuration parameters are 62 | * provided in the sample function below. 63 | * 64 | * @see https://developers.whmcs.com/payment-gateways/configuration/ 65 | * 66 | * @return array 67 | */ 68 | function merchantgateway_config() 69 | { 70 | return array( 71 | // the friendly display name for a payment gateway should be 72 | // defined here for backwards compatibility 73 | 'FriendlyName' => array( 74 | 'Type' => 'System', 75 | 'Value' => 'Sample Merchant Gateway Module', 76 | ), 77 | // a text field type allows for single line text input 78 | 'accountID' => array( 79 | 'FriendlyName' => 'Account ID', 80 | 'Type' => 'text', 81 | 'Size' => '25', 82 | 'Default' => '', 83 | 'Description' => 'Enter your account ID here', 84 | ), 85 | // a password field type allows for masked text input 86 | 'secretKey' => array( 87 | 'FriendlyName' => 'Secret Key', 88 | 'Type' => 'password', 89 | 'Size' => '25', 90 | 'Default' => '', 91 | 'Description' => 'Enter secret key here', 92 | ), 93 | // the yesno field type displays a single checkbox option 94 | 'testMode' => array( 95 | 'FriendlyName' => 'Test Mode', 96 | 'Type' => 'yesno', 97 | 'Description' => 'Tick to enable test mode', 98 | ), 99 | // the dropdown field type renders a select menu of options 100 | 'dropdownField' => array( 101 | 'FriendlyName' => 'Dropdown Field', 102 | 'Type' => 'dropdown', 103 | 'Options' => array( 104 | 'option1' => 'Display Value 1', 105 | 'option2' => 'Second Option', 106 | 'option3' => 'Another Option', 107 | ), 108 | 'Description' => 'Choose one', 109 | ), 110 | // the radio field type displays a series of radio button options 111 | 'radioField' => array( 112 | 'FriendlyName' => 'Radio Field', 113 | 'Type' => 'radio', 114 | 'Options' => 'First Option,Second Option,Third Option', 115 | 'Description' => 'Choose your option!', 116 | ), 117 | // the textarea field type allows for multi-line text input 118 | 'textareaField' => array( 119 | 'FriendlyName' => 'Textarea Field', 120 | 'Type' => 'textarea', 121 | 'Rows' => '3', 122 | 'Cols' => '60', 123 | 'Description' => 'Freeform multi-line text input field', 124 | ), 125 | ); 126 | } 127 | 128 | /** 129 | * Perform 3D Authentication. 130 | * 131 | * Called upon checkout using a credit card. 132 | * 133 | * Optional: Exclude this function if your merchant gateway does not support 134 | * 3D Secure Authentication. 135 | * 136 | * @param array $params Payment Gateway Module Parameters 137 | * 138 | * @see https://developers.whmcs.com/payment-gateways/3d-secure/ 139 | * 140 | * @return string 3D Secure Form 141 | */ 142 | function merchantgateway_3dsecure($params) 143 | { 144 | // Gateway Configuration Parameters 145 | $accountId = $params['accountID']; 146 | $secretKey = $params['secretKey']; 147 | $testMode = $params['testMode']; 148 | $dropdownField = $params['dropdownField']; 149 | $radioField = $params['radioField']; 150 | $textareaField = $params['textareaField']; 151 | 152 | // Invoice Parameters 153 | $invoiceId = $params['invoiceid']; 154 | $description = $params["description"]; 155 | $amount = $params['amount']; 156 | $currencyCode = $params['currency']; 157 | 158 | // Credit Card Parameters 159 | $cardType = $params['cardtype']; 160 | $cardNumber = $params['cardnum']; 161 | $cardExpiry = $params['cardexp']; 162 | $cardStart = $params['cardstart']; 163 | $cardIssueNumber = $params['cardissuenum']; 164 | $cardCvv = $params['cccvv']; 165 | 166 | // Client Parameters 167 | $firstname = $params['clientdetails']['firstname']; 168 | $lastname = $params['clientdetails']['lastname']; 169 | $email = $params['clientdetails']['email']; 170 | $address1 = $params['clientdetails']['address1']; 171 | $address2 = $params['clientdetails']['address2']; 172 | $city = $params['clientdetails']['city']; 173 | $state = $params['clientdetails']['state']; 174 | $postcode = $params['clientdetails']['postcode']; 175 | $country = $params['clientdetails']['country']; 176 | $phone = $params['clientdetails']['phonenumber']; 177 | 178 | // System Parameters 179 | $companyName = $params['companyname']; 180 | $systemUrl = $params['systemurl']; 181 | $returnUrl = $params['returnurl']; 182 | $langPayNow = $params['langpaynow']; 183 | $moduleDisplayName = $params['name']; 184 | $moduleName = $params['paymentmethod']; 185 | $whmcsVersion = $params['whmcsVersion']; 186 | 187 | // Return HTML form for redirecting user to 3D Auth. 188 | 189 | $url = 'https://www.demopaymentgateway.com/do.3dauth'; 190 | 191 | $postfields = array( 192 | 'account_id' => $accountId, 193 | 'invoice_id' => $invoiceId, 194 | 'amount' => $amount, 195 | 'currency' => $currencyCode, 196 | 'card_type' => $cardType, 197 | 'card_number' => $cardNumber, 198 | 'card_expiry_month' => substr($cardExpiry, 0, 2), 199 | 'card_expiry_year' => substr($cardExpiry, 2, 2), 200 | 'card_cvv' => $cardCvv, 201 | 'card_holder_name' => $firstname . ' ' . $lastname, 202 | 'card_holder_address' => $address1, 203 | 'card_holder_city' => $city, 204 | 'card_holder_state' => $state, 205 | 'card_holder_zip' => $postcode, 206 | 'card_holder_country' => $country, 207 | 'return_url' => $systemUrl . '/modules/gateways/callback/' . $moduleName . '.php', 208 | ); 209 | 210 | $htmlOutput = '
'; 216 | 217 | return $htmlOutput; 218 | } 219 | 220 | /** 221 | * Capture payment. 222 | * 223 | * Called when a payment is to be processed and captured. 224 | * 225 | * The card cvv number will only be present for the initial card holder present 226 | * transactions. Automated recurring capture attempts will not provide it. 227 | * 228 | * @param array $params Payment Gateway Module Parameters 229 | * 230 | * @see https://developers.whmcs.com/payment-gateways/merchant-gateway/ 231 | * 232 | * @return array Transaction response status 233 | */ 234 | function merchantgateway_capture($params) 235 | { 236 | // Gateway Configuration Parameters 237 | $accountId = $params['accountID']; 238 | $secretKey = $params['secretKey']; 239 | $testMode = $params['testMode']; 240 | $dropdownField = $params['dropdownField']; 241 | $radioField = $params['radioField']; 242 | $textareaField = $params['textareaField']; 243 | 244 | // Invoice Parameters 245 | $invoiceId = $params['invoiceid']; 246 | $description = $params["description"]; 247 | $amount = $params['amount']; 248 | $currencyCode = $params['currency']; 249 | 250 | // Credit Card Parameters 251 | $cardType = $params['cardtype']; 252 | $cardNumber = $params['cardnum']; 253 | $cardExpiry = $params['cardexp']; 254 | $cardStart = $params['cardstart']; 255 | $cardIssueNumber = $params['cardissuenum']; 256 | $cardCvv = $params['cccvv']; 257 | 258 | // Client Parameters 259 | $firstname = $params['clientdetails']['firstname']; 260 | $lastname = $params['clientdetails']['lastname']; 261 | $email = $params['clientdetails']['email']; 262 | $address1 = $params['clientdetails']['address1']; 263 | $address2 = $params['clientdetails']['address2']; 264 | $city = $params['clientdetails']['city']; 265 | $state = $params['clientdetails']['state']; 266 | $postcode = $params['clientdetails']['postcode']; 267 | $country = $params['clientdetails']['country']; 268 | $phone = $params['clientdetails']['phonenumber']; 269 | 270 | // System Parameters 271 | $companyName = $params['companyname']; 272 | $systemUrl = $params['systemurl']; 273 | $returnUrl = $params['returnurl']; 274 | $langPayNow = $params['langpaynow']; 275 | $moduleDisplayName = $params['name']; 276 | $moduleName = $params['paymentmethod']; 277 | $whmcsVersion = $params['whmcsVersion']; 278 | 279 | // perform API call to capture payment and interpret result 280 | 281 | if ($responseData->status == 1) { 282 | $returnData = [ 283 | // 'success' if successful, otherwise 'declined', 'error' for failure 284 | 'status' => 'success', 285 | // Data to be recorded in the gateway log - can be a string or array 286 | 'rawdata' => $responseData, 287 | // Unique Transaction ID for the capture transaction 288 | 'transid' => $transactionId, 289 | // Optional fee amount for the fee value refunded 290 | 'fee' => $feeAmount, 291 | ]; 292 | } else { 293 | $returnData = [ 294 | // 'success' if successful, otherwise 'declined', 'error' for failure 295 | 'status' => 'declined', 296 | // When not successful, a specific decline reason can be logged in the Transaction History 297 | 'declinereason' => 'Credit card declined. Please contact issuer.', 298 | // Data to be recorded in the gateway log - can be a string or array 299 | 'rawdata' => $responseData, 300 | ]; 301 | } 302 | 303 | return $returnData; 304 | } 305 | 306 | 307 | /** 308 | * Refund transaction. 309 | * 310 | * Called when a refund is requested for a previously successful transaction. 311 | * 312 | * @param array $params Payment Gateway Module Parameters 313 | * 314 | * @see https://developers.whmcs.com/payment-gateways/refunds/ 315 | * 316 | * @return array Transaction response status 317 | */ 318 | function merchantgateway_refund($params) 319 | { 320 | // Gateway Configuration Parameters 321 | $accountId = $params['accountID']; 322 | $secretKey = $params['secretKey']; 323 | $testMode = $params['testMode']; 324 | $dropdownField = $params['dropdownField']; 325 | $radioField = $params['radioField']; 326 | $textareaField = $params['textareaField']; 327 | 328 | // Transaction Parameters 329 | $transactionIdToRefund = $params['transid']; 330 | $refundAmount = $params['amount']; 331 | $currencyCode = $params['currency']; 332 | 333 | // Client Parameters 334 | $firstname = $params['clientdetails']['firstname']; 335 | $lastname = $params['clientdetails']['lastname']; 336 | $email = $params['clientdetails']['email']; 337 | $address1 = $params['clientdetails']['address1']; 338 | $address2 = $params['clientdetails']['address2']; 339 | $city = $params['clientdetails']['city']; 340 | $state = $params['clientdetails']['state']; 341 | $postcode = $params['clientdetails']['postcode']; 342 | $country = $params['clientdetails']['country']; 343 | $phone = $params['clientdetails']['phonenumber']; 344 | 345 | // System Parameters 346 | $companyName = $params['companyname']; 347 | $systemUrl = $params['systemurl']; 348 | $langPayNow = $params['langpaynow']; 349 | $moduleDisplayName = $params['name']; 350 | $moduleName = $params['paymentmethod']; 351 | $whmcsVersion = $params['whmcsVersion']; 352 | 353 | // perform API call to initiate refund and interpret result 354 | 355 | return array( 356 | // 'success' if successful, otherwise 'declined', 'error' for failure 357 | 'status' => 'success', 358 | // Data to be recorded in the gateway log - can be a string or array 359 | 'rawdata' => $responseData, 360 | // Unique Transaction ID for the refund transaction 361 | 'transid' => $refundTransactionId, 362 | // Optional fee amount for the fee value refunded 363 | 'fee' => $feeAmount, 364 | ); 365 | } 366 | --------------------------------------------------------------------------------