├── .gitignore ├── LICENSE.md ├── composer.json ├── phpstan.neon.dist └── src ├── Api ├── AbstractApi.php ├── Addons.php ├── Affiliates.php ├── Authentication.php ├── Billing.php ├── Client.php ├── Custom.php ├── Domains.php ├── Orders.php ├── Products.php ├── Servers.php ├── Service.php ├── System.php └── Users.php ├── ApiEndpointTrait.php ├── Client.php ├── Exception ├── AuthenticationException.php ├── ErrorException.php └── IpBlockedException.php └── HttpClient ├── Builder.php ├── Formatter └── ResponseFormatter.php └── Plugin ├── AccessKey.php ├── Authentication.php ├── ContentType.php ├── ExceptionHandler.php └── WhmcsContentType.php /.gitignore: -------------------------------------------------------------------------------- 1 | .build/ 2 | /vendor 3 | composer.phar 4 | composer.lock 5 | .DS_Store 6 | .idea 7 | .env 8 | phpunit.xml 9 | .phpunit.result.cache 10 | example.php 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "darthsoup/php-whmcs-api", 3 | "description": "WHMCS API client for PHP", 4 | "keywords": ["whmcs", "api"], 5 | "type": "library", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Kevin Krummnacker", 10 | "email": "kevin.krummnacker@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "php": "^7.4|^8.0.2", 15 | "ext-json": "*", 16 | "psr/http-client-implementation": "^1.0", 17 | "psr/http-factory-implementation": "^1.0", 18 | "psr/http-message": "^1.1 || ^2.0", 19 | "php-http/client-common": "^2.6", 20 | "php-http/discovery": "^1.17", 21 | "php-http/httplug": "^2.4", 22 | "symfony/options-resolver": "^5.0 || ^6.0 || ^7.0" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^8.5.14 || ^9.5.1", 26 | "guzzlehttp/guzzle": "^7.8", 27 | "http-interop/http-factory-guzzle": "^1.0", 28 | "phpstan/phpstan": "^1.10" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "DarthSoup\\WhmcsApi\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "DarthSoup\\Tests\\WhmcsApi\\": "tests/" 38 | } 39 | }, 40 | "config": { 41 | "allow-plugins": { 42 | "php-http/discovery": true 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 5 3 | paths: 4 | - src 5 | - examples 6 | -------------------------------------------------------------------------------- /src/Api/AbstractApi.php: -------------------------------------------------------------------------------- 1 | client = $client; 43 | } 44 | 45 | /** 46 | * @param string $action 47 | * @param array $parameter 48 | * @return mixed|string 49 | */ 50 | protected function send(string $action, array $parameter = []) 51 | { 52 | $header = []; 53 | $body = array_merge(['action' => $action], $parameter); 54 | 55 | $stream = new AppendStream([Utils::streamFor(http_build_query($body))]); 56 | 57 | $response = $this->client->getHttpClient()->post( 58 | '', // WHMCS doesnt use a specific url 59 | $header, 60 | $stream 61 | ); 62 | 63 | return ResponseFormatter::format($response); 64 | } 65 | 66 | protected function createOptionsResolver(): OptionsResolver 67 | { 68 | $resolver = new OptionsResolver(); 69 | $resolver->setDefined('firstname') 70 | ->setAllowedTypes('firstname', 'string'); 71 | $resolver->setDefined('lastname') 72 | ->setAllowedTypes('lastname', 'string'); 73 | $resolver->setDefined('address1') 74 | ->setAllowedTypes('address1', 'string'); 75 | $resolver->setDefined('address2') 76 | ->setAllowedTypes('address2', 'string'); 77 | $resolver->setDefined('companyname') 78 | ->setAllowedTypes('companyname', 'string'); 79 | $resolver->setDefined('city') 80 | ->setAllowedTypes('city', 'string'); 81 | $resolver->setDefined('state') 82 | ->setAllowedTypes('state', 'string'); 83 | $resolver->setDefined('postcode') 84 | ->setAllowedTypes('postcode', 'string'); 85 | $resolver->setDefined('country') 86 | ->setAllowedTypes('country', 'string'); 87 | $resolver->setDefined('number') 88 | ->setAllowedTypes('number', 'string'); 89 | $resolver->setDefined('phonenumber') 90 | ->setAllowedTypes('phonenumber', 'string'); 91 | 92 | $resolver->setDefined('email') 93 | ->setAllowedTypes('email', 'string') 94 | ->setAllowedValues('email', fn($value) => filter_var($value, FILTER_VALIDATE_EMAIL)); 95 | $resolver->setDefined('password2') 96 | ->setAllowedTypes('password2', 'string'); 97 | 98 | $resolver->setDefined('customfields') 99 | ->setAllowedTypes('customfields', 'string'); 100 | 101 | $resolver->setDefined('ip') 102 | ->setAllowedTypes('ip', 'string') 103 | ->setInfo('ip', 'Must be a valid IPv4 or IPv6.') 104 | ->setAllowedValues('ip', fn($value) => filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)); 105 | $resolver->setDefined('clientip') 106 | ->setAllowedTypes('clientip', 'string') 107 | ->setInfo('clientip', 'Must be a valid IPv4 or IPv6.') 108 | ->setAllowedValues('clientip', fn($value) => filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)); 109 | 110 | 111 | // Global 112 | $resolver->setDefined('search') 113 | ->setAllowedTypes('search', 'string'); 114 | $resolver->setDefined('limitstart') 115 | ->setAllowedTypes('limitstart', 'int') 116 | ->setAllowedValues('limitstart', fn($value) => $value > 0); 117 | $resolver->setDefined('limitnum') 118 | ->setAllowedTypes('limitnum', 'int') 119 | ->setAllowedValues('limitnum', fn($value) => $value > 0 && $value <= 250); 120 | 121 | $resolver->setDefined('sorting') 122 | ->setAllowedValues('sorting', self::SORTING); 123 | $resolver->setDefined('sortOrder') 124 | ->setAllowedValues('sortOrder', self::SORTING); 125 | $resolver->setDefined('orderby') 126 | ->setAllowedTypes('orderby', 'string'); 127 | 128 | $resolver->setDefined('status') 129 | ->setAllowedValues('status', [ 130 | ...self::STATUS_ORDER, 131 | ...self::STATUS_CLIENT, 132 | ...self::STATUS_INVOICE, 133 | ...self::STATUS_PRODUCT, 134 | ]); 135 | 136 | return $resolver; 137 | } 138 | 139 | protected function getClient(): Client 140 | { 141 | return $this->client; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Api/Addons.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setDefined([ 16 | 'id', 'status', 'addonid', 'name', 'setupfee', 'recurring', 'billingcycle', 17 | 'nextduedate', 'terminationdate', 'notes', 'autorecalc', 18 | ]); 19 | $resolver->setAllowedTypes('id', 'int'); 20 | $resolver->setAllowedTypes('setupfee', 'float‚'); 21 | $resolver->setAllowedTypes('recurring', 'float‚'); 22 | $resolver->setAllowedValues('status', self::STATUS_PRODUCT); 23 | 24 | $resolver->setRequired('id'); 25 | 26 | return $this->send('UpdateClientAddon', $resolver->resolve($parameters)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Api/Affiliates.php: -------------------------------------------------------------------------------- 1 | send('AffiliateActivate', ['userid' => $userId]); 15 | } 16 | 17 | /** 18 | * @see https://developers.whmcs.com/api-reference/getaffiliates/ 19 | */ 20 | public function getAffiliates(array $parameters = []) 21 | { 22 | $resolver = $this->createOptionsResolver(); 23 | $resolver->setDefined(['userid', 'visitors', 'paytype', 'payamount', 'onetime', 'balance', 'withdrawn']); 24 | 25 | return $this->send('GetAffiliates', $resolver->resolve($parameters)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Api/Authentication.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setDefined(['grantType', 'scope', 'name', 'serviceId', 'description', 'logoUri', 'redirectUri']); 16 | $resolver->setAllowedTypes('grantType', 'string'); 17 | $resolver->setAllowedTypes('scope', 'string'); 18 | $resolver->setRequired(['grantType', 'scope']); 19 | 20 | return $this->send('CreateOAuthCredential', $resolver->resolve($parameters)); 21 | } 22 | 23 | /** 24 | * @see https://developers.whmcs.com/api-reference/createssotoken/ 25 | */ 26 | public function createSsoToken(array $parameters = []) 27 | { 28 | $resolver = $this->createOptionsResolver(); 29 | $resolver->setDefined(['client_id', 'user_id', 'destination', 'service_id', 'domain_id', 'sso_redirect_path']); 30 | $resolver->setAllowedTypes('client_id', 'int'); 31 | $resolver->setAllowedTypes('user_id', 'int'); 32 | $resolver->setAllowedTypes('destination', 'string'); 33 | $resolver->setAllowedTypes('service_id', 'int'); 34 | $resolver->setAllowedTypes('domain_id', 'int'); 35 | $resolver->setAllowedTypes('sso_redirect_path', 'string'); 36 | 37 | return $this->send('CreateSsoToken', $resolver->resolve($parameters)); 38 | } 39 | 40 | /** 41 | * @see https://developers.whmcs.com/api-reference/deleteoauthcredential/ 42 | */ 43 | public function deleteOAuthCredential(int $credentialId) 44 | { 45 | return $this->send('DeleteOAuthCredential', ['credentialId' => $credentialId]); 46 | } 47 | 48 | /** 49 | * @see https://developers.whmcs.com/api-reference/listoauthcredentials/ 50 | */ 51 | public function listOAuthCredentials(array $parameters = []) 52 | { 53 | $resolver = $this->createOptionsResolver(); 54 | $resolver->setDefined(['grantType', 'sortField', 'limit']); 55 | $resolver->setDefined('limit') 56 | ->setAllowedTypes('limit', 'int') 57 | ->setAllowedValues('limit', fn($value): bool => $value > 0 && $value <= 250); 58 | 59 | return $this->send('ListOAuthCredentials', $resolver->resolve($parameters)); 60 | } 61 | 62 | /** 63 | * @see https://developers.whmcs.com/api-reference/validatelogin/ 64 | */ 65 | public function validateLogin(string $email, string $password) 66 | { 67 | return $this->send('ValidateLogin', ['email' => $email, 'password2' => $password]); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Api/Billing.php: -------------------------------------------------------------------------------- 1 | send('AcceptQuote', ['quoteid' => $quoteId]); 15 | } 16 | 17 | /** 18 | * @see https://developers.whmcs.com/api-reference/addbillableitem/ 19 | */ 20 | public function addBillableItem(array $parameters = []) 21 | { 22 | $resolver = $this->createOptionsResolver(); 23 | $resolver->setDefined([ 24 | 'clientid', 'description', 'amount', 'unit', 'quantity', 'invoiceaction', 'recur', 25 | 'recurcycle', 'recurfor', 'duedate' 26 | ]); 27 | $resolver->setAllowedTypes('clientid', 'int'); 28 | $resolver->setAllowedTypes('description', 'string'); 29 | $resolver->setAllowedTypes('amount', 'float'); 30 | $resolver->setAllowedValues('unit', ['hours', 'quantity']); 31 | $resolver->setAllowedValues('invoiceaction', ['noinvoice', 'nextcron', 'nextinvoice', 'duedate', 'recur']); 32 | $resolver->setAllowedValues('recurcycle', ['Days', 'Weeks', 'Months', 'Years']); 33 | $resolver->setRequired(['clientid', 'description', 'amount', 'unit']); 34 | 35 | return $this->send('AddBillableItem', $resolver->resolve($parameters)); 36 | } 37 | 38 | /** 39 | * @see https://developers.whmcs.com/api-reference/addcredit/ 40 | */ 41 | public function addCredit(array $parameters = []) 42 | { 43 | $resolver = $this->createOptionsResolver(); 44 | $resolver->setDefined(['clientid', 'description', 'amount', 'date', 'adminid', 'type']); 45 | $resolver->setAllowedTypes('clientid', 'int'); 46 | $resolver->setAllowedTypes('description', 'string'); 47 | $resolver->setAllowedTypes('amount', 'float'); 48 | $resolver->setRequired(['clientid', 'description', 'amount']); 49 | 50 | return $this->send('AddCredit', $resolver->resolve($parameters)); 51 | } 52 | 53 | /** 54 | * @see https://developers.whmcs.com/api-reference/addinvoicepayment/ 55 | */ 56 | public function addInvoicePayment(array $parameters = []) 57 | { 58 | $resolver = $this->createOptionsResolver(); 59 | $resolver->setDefined(['invoiceid', 'transid', 'gateway', 'date', 'amount', 'fees', 'noemail']); 60 | $resolver->setAllowedTypes('invoiceid', 'int'); 61 | $resolver->setAllowedTypes('transid', 'string'); 62 | $resolver->setAllowedTypes('gateway', 'string'); 63 | $resolver->setRequired(['invoiceid', 'transid', 'gateway', 'date']); 64 | 65 | return $this->send('AddInvoicePayment', $resolver->resolve($parameters)); 66 | } 67 | 68 | /** 69 | * @see https://developers.whmcs.com/api-reference/addpaymethod/ 70 | */ 71 | public function addPayMethod(array $parameters = []) 72 | { 73 | $resolver = $this->createOptionsResolver(); 74 | $resolver->setDefined([ 75 | 'clientid', 'type', 'description', 'gateway_module_name', 'card_number', 'card_expiry', 'card_start', 76 | 'card_issue_number', 'bank_name', 'bank_account_type', 'bank_code', 'bank_account', 'set_as_default' 77 | ]); 78 | $resolver->setAllowedTypes('clientid', 'int'); 79 | $resolver->setRequired(['clientid']); 80 | 81 | return $this->send('AddPayMethod', $resolver->resolve($parameters)); 82 | } 83 | 84 | /** 85 | * @see https://developers.whmcs.com/api-reference/addtransaction/ 86 | */ 87 | public function addTransaction(array $parameters = []) 88 | { 89 | $resolver = $this->createOptionsResolver(); 90 | $resolver->setDefined([ 91 | 'paymentmethod', 'userid', 'invoiceid', 'transid', 'date', 'currencyid', 'description', 'amountin', 'fees', 92 | 'amountout', 'rate', 'credit', 'allowduplicatetransid' 93 | ]); 94 | $resolver->setAllowedTypes('paymentmethod', 'string'); 95 | $resolver->setAllowedTypes('userid', 'int'); 96 | $resolver->setAllowedTypes('invoiceid', 'int'); 97 | $resolver->setAllowedTypes('transid', 'string'); 98 | $resolver->setRequired(['paymentmethod']); 99 | 100 | return $this->send('AddTransaction', $resolver->resolve($parameters)); 101 | } 102 | 103 | /** 104 | * @see https://developers.whmcs.com/api-reference/applycredit/ 105 | */ 106 | public function applyCredit(array $parameters = []) 107 | { 108 | $resolver = $this->createOptionsResolver(); 109 | $resolver->setDefined(['invoiceid', 'amount', 'noemail']); 110 | $resolver->setAllowedTypes('invoiceid', 'int'); 111 | $resolver->setAllowedTypes('amount', 'float'); 112 | $resolver->setAllowedTypes('noemail', 'bool'); 113 | $resolver->setRequired(['invoiceid']); 114 | 115 | return $this->send('ApplyCredit', $resolver->resolve($parameters)); 116 | } 117 | 118 | /** 119 | * @see https://developers.whmcs.com/api-reference/capturepayment/ 120 | */ 121 | public function capturePayment(array $parameters = []) 122 | { 123 | $resolver = $this->createOptionsResolver(); 124 | $resolver->setDefined(['invoiceid', 'cvv']); 125 | $resolver->setAllowedTypes('invoiceid', 'int'); 126 | $resolver->setAllowedTypes('cvv', 'string'); 127 | $resolver->setRequired(['invoiceid']); 128 | 129 | return $this->send('CapturePayment', $resolver->resolve($parameters)); 130 | } 131 | 132 | /** 133 | * @see https://developers.whmcs.com/api-reference/createinvoice/ 134 | */ 135 | public function createInvoice(array $parameters = []) 136 | { 137 | $resolver = $this->createOptionsResolver(); 138 | $resolver->setDefined([ 139 | 'userid', 'status', 'draft', 'sendinvoice', 'paymentmethod', 'taxrate', 'taxrate2', 'date', 140 | 'duedate', 'notes', 'itemdescriptionx', 'itemamountx', 'itemtaxedx', 'autoapplycredit' 141 | ]); 142 | $resolver->setAllowedTypes('userid', 'int'); 143 | $resolver->setAllowedTypes('status', 'string'); 144 | $resolver->setAllowedTypes('draft', 'bool'); 145 | $resolver->setAllowedTypes('sendinvoice', 'bool'); 146 | $resolver->setAllowedTypes('paymentmethod', 'string'); 147 | $resolver->setAllowedTypes('taxrate', 'float'); 148 | $resolver->setAllowedTypes('taxrate2', 'float'); 149 | $resolver->setAllowedTypes('date', 'string'); 150 | $resolver->setAllowedTypes('duedate', 'string'); 151 | $resolver->setAllowedTypes('notes', 'string'); 152 | $resolver->setAllowedTypes('itemdescriptionx', 'string'); 153 | $resolver->setAllowedTypes('itemamountx', 'float'); 154 | $resolver->setAllowedTypes('itemtaxedx', 'bool'); 155 | $resolver->setAllowedTypes('autoapplycredit', 'bool'); 156 | $resolver->setRequired(['userid']); 157 | 158 | return $this->send('CreateInvoice', $this->createOptionsResolver()->resolve($parameters)); 159 | } 160 | 161 | /** 162 | * @see https://developers.whmcs.com/api-reference/createquote/ 163 | */ 164 | public function createQuote(array $parameters = []) 165 | { 166 | $resolver = $this->createOptionsResolver(); 167 | $resolver->setDefined([ 168 | 'subject', 'stage', 'validuntil', 'datecreated', 'lineitems', 'userid', 'firstname', 'lastname', 169 | 'companyname', 'email', 'address1', 'address2', 'city', 'state', 'postcode', 'country', 'phonenumber', 170 | 'tax_id', 'currency', 'proposal', 'customernotes', 'adminnotes', 171 | ]); 172 | $resolver->setAllowedValues('stage', self::STATUS_BILLINGSTAGE); 173 | $resolver->setRequired(['subject', 'stage', 'validuntil']); 174 | 175 | return $this->send('CreateQuote', $resolver->resolve($parameters)); 176 | } 177 | 178 | /** 179 | * @see https://developers.whmcs.com/api-reference/deletepaymethod/ 180 | */ 181 | public function deletePayMethod(array $parameters = []) 182 | { 183 | $resolver = $this->createOptionsResolver(); 184 | $resolver->setDefined(['clientid', 'paymethodid', 'failonremotefailure']); 185 | $resolver->setAllowedTypes('clientid', 'int'); 186 | $resolver->setAllowedTypes('paymethodid', 'int'); 187 | $resolver->setRequired(['clientid', 'paymethodid']); 188 | 189 | return $this->send('DeletePayMethod', $resolver->resolve($parameters)); 190 | } 191 | 192 | /** 193 | * @see https://developers.whmcs.com/api-reference/deletequote/ 194 | */ 195 | public function deleteQuote(int $quoteId) 196 | { 197 | return $this->send('DeleteQuote', ['quoteid' => $quoteId]); 198 | } 199 | 200 | /** 201 | * @see https://developers.whmcs.com/api-reference/geninvoices/ 202 | */ 203 | public function genInvoices(array $parameters = []) 204 | { 205 | $resolver = $this->createOptionsResolver(); 206 | $resolver->setDefined(['noemails', 'clientid', 'serviceids', 'domainids', 'addonids']); 207 | $resolver->setAllowedTypes('noemails', 'bool'); 208 | $resolver->setAllowedTypes('clientid', 'int'); 209 | $resolver->setAllowedTypes('serviceids', 'int[]'); 210 | $resolver->setAllowedTypes('domainids', 'int[]'); 211 | $resolver->setAllowedTypes('addonids', 'int[]'); 212 | 213 | return $this->send('GenInvoices', $resolver->resolve($parameters)); 214 | } 215 | 216 | /** 217 | * @see https://developers.whmcs.com/api-reference/getcredits/ 218 | */ 219 | public function getCredits(int $clientId) 220 | { 221 | return $this->send('GetCredits', ['clientid' => $clientId]); 222 | } 223 | 224 | /** 225 | * @see https://developers.whmcs.com/api-reference/getinvoice/ 226 | */ 227 | public function getInvoice(int $invoiceId) 228 | { 229 | return $this->send('GetInvoice', ['invoiceid' => $invoiceId]); 230 | } 231 | 232 | /** 233 | * @see https://developers.whmcs.com/api-reference/getinvoices/ 234 | */ 235 | public function getInvoices(array $parameters = []) 236 | { 237 | $resolver = $this->createOptionsResolver(); 238 | $resolver->setDefined(['userid', 'status']); 239 | $resolver->setAllowedTypes('userid', 'int'); 240 | $resolver->setAllowedValues('status', self::STATUS_INVOICE); 241 | 242 | return $this->send('GetInvoices', $resolver->resolve($parameters)); 243 | } 244 | 245 | /** 246 | * @see https://developers.whmcs.com/api-reference/getpaymethods/ 247 | */ 248 | public function getPayMethods(array $parameters = []) 249 | { 250 | $resolver = $this->createOptionsResolver(); 251 | $resolver->setDefined(['clientid', 'paymethodid', 'type']); 252 | $resolver->setAllowedTypes('clientid', 'int'); 253 | $resolver->setAllowedTypes('paymethodid', 'int'); 254 | $resolver->setRequired(['clientid']); 255 | 256 | return $this->send('GetPayMethods', $resolver->resolve($parameters)); 257 | } 258 | 259 | /** 260 | * @see https://developers.whmcs.com/api-reference/getquotes/ 261 | */ 262 | public function getQuotes(array $parameters = []) 263 | { 264 | $resolver = $this->createOptionsResolver(); 265 | $resolver->setDefined(['quoteid', 'userid', 'subject', 'stage', 'datecreated', 'lastmodified', 'validuntil']); 266 | $resolver->setAllowedTypes('quoteid', 'int'); 267 | $resolver->setAllowedTypes('userid', 'int'); 268 | $resolver->setAllowedTypes('subject', 'string'); 269 | $resolver->setAllowedValues('stage', self::STATUS_BILLINGSTAGE); 270 | $resolver->setAllowedTypes('datecreated', 'string'); 271 | $resolver->setAllowedTypes('lastmodified', 'string'); 272 | $resolver->setAllowedTypes('validuntil', 'string'); 273 | 274 | return $this->send('GetQuotes', $resolver->resolve($parameters)); 275 | } 276 | 277 | /** 278 | * @see https://developers.whmcs.com/api-reference/gettransactions/ 279 | */ 280 | public function getTransactions(array $parameters = []) 281 | { 282 | $resolver = $this->createOptionsResolver(); 283 | $resolver->setDefined(['invoiceid', 'clientid', 'transid']); 284 | $resolver->setAllowedTypes('invoiceid', 'int'); 285 | $resolver->setAllowedTypes('clientid', 'int'); 286 | $resolver->setAllowedTypes('transid', 'string'); 287 | 288 | return $this->send('GetTransactions', $resolver->resolve($parameters)); 289 | } 290 | 291 | /** 292 | * @see https://developers.whmcs.com/api-reference/sendquote/ 293 | */ 294 | public function sendQuote(int $quoteId) 295 | { 296 | return $this->send('SendQuote', ['quoteid' => $quoteId]); 297 | } 298 | 299 | /** 300 | * @see https://developers.whmcs.com/api-reference/updateinvoice/ 301 | */ 302 | public function updateInvoice(array $parameters = []) 303 | { 304 | $resolver = $this->createOptionsResolver(); 305 | $resolver->setDefined([ 306 | 'invoiceid', 'status', 'paymentmethod', 'taxrate', 'taxrate2', 'credit', 'date', 'duedate', 'datepaid', 307 | 'notes', 'itemdescription', 'itemamount', 'itemtaxed', 'newitemdescription', 'newitemamount', 308 | 'newitemtaxed', 'deletelineids', 'publish', 'publishandsendemail', 309 | ]); 310 | $resolver->setAllowedTypes('invoiceid', 'int'); 311 | $resolver->setAllowedTypes('itemdescription', 'string[]'); 312 | $resolver->setAllowedTypes('itemamount', 'float[]'); 313 | $resolver->setAllowedTypes('itemtaxed', 'bool[]'); 314 | $resolver->setAllowedTypes('newitemdescription', 'string[]'); 315 | $resolver->setAllowedTypes('newitemamount', 'float[]'); 316 | $resolver->setAllowedTypes('newitemtaxed', 'bool[]'); 317 | $resolver->setAllowedTypes('deletelineids', 'int[]'); 318 | $resolver->setAllowedValues('status', self::STATUS_ORDER); 319 | $resolver->setRequired(['invoiceid']); 320 | 321 | return $this->send('UpdateInvoice', $this->createOptionsResolver()->resolve($parameters)); 322 | } 323 | 324 | /** 325 | * @see https://developers.whmcs.com/api-reference/updatepaymethod/ 326 | */ 327 | public function updatePayMethod(array $parameters = []) 328 | { 329 | $resolver = $this->createOptionsResolver(); 330 | $resolver->setDefined([ 331 | 'clientid', 'paymethodid', 'card_number', 'card_expiry', 'card_start', 'card_issue_number', 'bank_name', 332 | 'bank_account_type', 'bank_code', 'bank_account', 'set_as_default', 333 | ]); 334 | $resolver->setAllowedTypes('clientid', 'int'); 335 | $resolver->setAllowedTypes('paymethodid', 'int'); 336 | $resolver->setRequired(['clientid', 'paymethodid']); 337 | 338 | return $this->send('UpdatePayMethod', $resolver->resolve($parameters)); 339 | } 340 | 341 | /** 342 | * @see https://developers.whmcs.com/api-reference/updatequote/ 343 | */ 344 | public function updateQuote(array $parameters = []) 345 | { 346 | $resolver = $this->createOptionsResolver(); 347 | $resolver->setDefined([ 348 | 'quoteid', 'subject', 'stage', 'validuntil', 'datecreated', 'lineitems', 'userid', 'firstname', 'lastname', 349 | 'companyname', 'email', 'address1', 'address2', 'city', 'state', 'country', 'phonenumber', 'tax_id', 350 | 'currency', 'proposal', 'customernotes', 'adminnotes' 351 | ]); 352 | $resolver->setAllowedTypes('quoteid', 'int'); 353 | $resolver->setAllowedValues('stage', self::STATUS_BILLINGSTAGE); 354 | $resolver->setRequired(['quoteid']); 355 | 356 | return $this->send('UpdateQuote', $resolver->resolve($parameters)); 357 | } 358 | 359 | /** 360 | * @see https://developers.whmcs.com/api-reference/updatetransaction/ 361 | */ 362 | public function updateTransaction(array $parameters = []) 363 | { 364 | $resolver = $this->createOptionsResolver(); 365 | $resolver->setDefined([ 366 | 'transactionid', 'refundid', 'userid', 'invoiceid', 'transid', 'date', 'gateway', 367 | 'currency', 'description', 'amountin', 'fees', 'amountout', 'rate', 'credit' 368 | ]); 369 | $resolver->setAllowedTypes('transactionid', 'int'); 370 | $resolver->setAllowedTypes('refundid', 'int'); 371 | $resolver->setAllowedTypes('userid', 'int'); 372 | $resolver->setAllowedTypes('invoiceid', 'int'); 373 | $resolver->setRequired(['transactionid']); 374 | 375 | return $this->send('UpdateTransaction', $resolver->resolve($parameters)); 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /src/Api/Client.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setDefined([ 16 | 'owner_user_id', 'firstname', 'lastname', 'companyname', 'email', 'address1', 'address2', 'city', 17 | 'state', 'postcode', 'country', 'phonenumber', 'tax_id', 'password2', 'securityqid', 'securityqans', 18 | 'currency', 'groupid', 'customfields', 'language', 'clientip', 'notes', 'marketingoptin', 19 | 'noemail', 'skipvalidation', 20 | ]); 21 | $resolver->setRequired(['firstname', 'lastname', 'email', 'address1', 'city', 'state', 'postcode', 'country', 'phonenumber',]); 22 | 23 | return $this->send('AddClient', $resolver->resolve($parameters)); 24 | } 25 | 26 | /** 27 | * @see https://developers.whmcs.com/api-reference/addcontact/ 28 | */ 29 | public function addContact(array $parameters = []) 30 | { 31 | $resolver = $this->createOptionsResolver(); 32 | $resolver->setDefined([ 33 | 'firstname', 'lastname', 'companyname', 'email', 'address1', 'address2', 'city', 'state', 'postcode', 34 | 'country', 'phonenumber', 'tax_id', 35 | ]); 36 | $resolver->setRequired(['clientid']); 37 | 38 | return $this->send('AddContact', $resolver->resolve($parameters)); 39 | } 40 | 41 | /** 42 | * @see https://developers.whmcs.com/api-reference/closeclient/ 43 | */ 44 | public function closeClient(int $clientId) 45 | { 46 | return $this->send('CloseClient', ['clientid' => $clientId]); 47 | } 48 | 49 | /** 50 | * @see https://developers.whmcs.com/api-reference/deleteclient/ 51 | */ 52 | public function deleteClient(int $clientId, bool $deleteUsers = false, bool $deleteTransactions = false) 53 | { 54 | return $this->send('DeleteClient', [ 55 | 'clientid' => $clientId, 56 | 'deleteusers' => $deleteUsers, 57 | 'deletetransactions' => $deleteTransactions 58 | ]); 59 | } 60 | 61 | /** 62 | * @see https://developers.whmcs.com/api-reference/deletecontact/ 63 | */ 64 | public function deleteContact(int $contactId) 65 | { 66 | return $this->send('DeleteContact', ['contactid' => $contactId]); 67 | } 68 | 69 | /** 70 | * @see https://developers.whmcs.com/api-reference/getcancelledpackages/ 71 | */ 72 | public function getCancelledPackages(array $parameters = []) 73 | { 74 | return $this->send('GetCancelledPackages', $this->createOptionsResolver()->resolve($parameters)); 75 | } 76 | 77 | /** 78 | * @see https://developers.whmcs.com/api-reference/getclientgroups/ 79 | */ 80 | public function getClientGroups() 81 | { 82 | return $this->send('GetClientGroups'); 83 | } 84 | 85 | /** 86 | * @see https://developers.whmcs.com/api-reference/getclientpassword/ 87 | */ 88 | public function getClientPassword(array $parameters = []) 89 | { 90 | return $this->send('GetClientPassword', $this->createOptionsResolver()->resolve($parameters)); 91 | } 92 | 93 | /** 94 | * @see https://developers.whmcs.com/api-reference/getclients/ 95 | */ 96 | public function getClients(array $parameters = []) 97 | { 98 | $resolver = $this->createOptionsResolver(); 99 | $resolver->setAllowedValues('orderby', ['id', 'invoicenumber', 'date', 'duedate', 'total', 'status']); 100 | 101 | return $this->send('GetClients', $resolver->resolve($parameters)); 102 | } 103 | 104 | /** 105 | * @see https://developers.whmcs.com/api-reference/getclientsaddons/ 106 | */ 107 | public function getClientsAddons(array $parameters = []) 108 | { 109 | $resolver = $this->createOptionsResolver(); 110 | $resolver->setDefined(['serviceid', 'clientid', 'addonid']); 111 | $resolver->setAllowedTypes('serviceid', 'int'); 112 | $resolver->setAllowedTypes('clientid', 'int'); 113 | $resolver->setAllowedTypes('addonid', 'int'); 114 | 115 | return $this->send('GetClientsAddons', $resolver->resolve($parameters)); 116 | } 117 | 118 | /** 119 | * @see https://developers.whmcs.com/api-reference/getclientsdetails/ 120 | */ 121 | public function getClientsDetails(array $parameters = []) 122 | { 123 | $resolver = $this->createOptionsResolver(); 124 | $resolver->setDefined(['clientid', 'email', 'stats']); 125 | $resolver->setAllowedTypes('clientid', 'int'); 126 | $resolver->setAllowedTypes('email', 'string'); 127 | $resolver->setAllowedTypes('stats', 'bool'); 128 | 129 | return $this->send('GetClientsDetails', $resolver->resolve($parameters)); 130 | } 131 | 132 | /** 133 | * @see https://developers.whmcs.com/api-reference/getclientsdomains/ 134 | */ 135 | public function getClientsDomains(array $parameters = []) 136 | { 137 | $resolver = $this->createOptionsResolver(); 138 | $resolver->setDefined(['clientid', 'domainid', 'domain']); 139 | $resolver->setAllowedTypes('clientid', 'int'); 140 | $resolver->setAllowedTypes('domainid', 'int'); 141 | $resolver->setAllowedTypes('domain', 'string'); 142 | 143 | return $this->send('GetClientsDomains', $resolver->resolve($parameters)); 144 | } 145 | 146 | /** 147 | * @see https://developers.whmcs.com/api-reference/getclientsproducts/ 148 | */ 149 | public function getClientsProducts(array $parameters = []) 150 | { 151 | $resolver = $this->createOptionsResolver(); 152 | $resolver->setDefined(['clientid', 'serviceid', 'pid', 'domain', 'username2']); 153 | $resolver->setAllowedTypes('clientid', 'int'); 154 | $resolver->setAllowedTypes('serviceid', 'int'); 155 | $resolver->setAllowedTypes('pid', 'int'); 156 | $resolver->setAllowedTypes('domain', 'string'); 157 | $resolver->setAllowedTypes('username2', 'string'); 158 | 159 | return $this->send('GetClientsProducts', $resolver->resolve($parameters)); 160 | } 161 | 162 | /** 163 | * @see https://developers.whmcs.com/api-reference/getcontacts/ 164 | */ 165 | public function getContacts(array $parameters = []) 166 | { 167 | $resolver = $this->createOptionsResolver(); 168 | $resolver->setDefined(['userid']); 169 | $resolver->setAllowedTypes('userid', 'int'); 170 | 171 | return $this->send('GetContacts', $resolver->resolve($parameters)); 172 | } 173 | 174 | /** 175 | * @see https://developers.whmcs.com/api-reference/getemails/ 176 | */ 177 | public function getEmails(array $parameters = []) 178 | { 179 | $resolver = $this->createOptionsResolver(); 180 | $resolver->setDefined(['clientid', 'date', 'email']); 181 | $resolver->setAllowedTypes('clientid', 'int'); 182 | $resolver->setAllowedTypes('date', 'string'); 183 | $resolver->setRequired(['clientid']); 184 | 185 | return $this->send('GetEmails', $resolver->resolve($parameters)); 186 | } 187 | 188 | /** 189 | * @see https://developers.whmcs.com/api-reference/updateclient/ 190 | */ 191 | public function updateClient(array $parameters = []) 192 | { 193 | $resolver = $this->createOptionsResolver(); 194 | $resolver->setDefined([ 195 | 'clientid', 'tax_id', 'currency', 'groupid', 'customfields', 'language', 'clientip', 'notes', 196 | 'status', 'paymentmethod', 'marketingoptin', 'clearcreditcard', 'skipvalidation', 'latefeeoveride', 197 | 'overideduenotices', 'taxexempt', 'separateinvoices', 'disableautocc', 'overrideautoclose', 198 | ]); 199 | $resolver->setAllowedTypes('clientid', 'int'); 200 | $resolver->setAllowedValues('status', self::STATUS_CLIENT); 201 | 202 | /* only support clientid for now */ 203 | $resolver->setRequired('clientid'); 204 | 205 | return $this->send('UpdateClient', $resolver->resolve($parameters)); 206 | } 207 | 208 | /** 209 | * @see https://developers.whmcs.com/api-reference/updatecontact/ 210 | */ 211 | public function updateContact(array $parameters = []) 212 | { 213 | $resolver = $this->createOptionsResolver(); 214 | $resolver->setDefined(['contactid']); 215 | $resolver->setAllowedTypes('contactid', 'int'); 216 | $resolver->setRequired('contactid'); 217 | 218 | return $this->send('UpdateContact', $resolver->resolve($parameters)); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/Api/Custom.php: -------------------------------------------------------------------------------- 1 | send($name, $parameters); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Api/Domains.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setDefined([ 16 | 'extension', 'id_protection', 'dns_management', 'email_forwarding', 'epp_required', 'auto_registrar', 17 | 'group', 'currency_code', 'grace_period_days', 'grace_period_fee', 'redemption_period_days', 18 | 'redemption_period_fee', 'register', 'renew', 'transfer', 'display_after', 19 | ]); 20 | $resolver->setAllowedTypes('extension', 'string'); 21 | $resolver->setRequired(['extension']); 22 | 23 | return $this->send('CreateOrUpdateTLD', $resolver->resolve($parameters)); 24 | } 25 | 26 | /** 27 | * @see https://developers.whmcs.com/api-reference/domaingetlockingstatus/ 28 | */ 29 | public function domainGetLockingStatus(int $domainId) 30 | { 31 | return $this->send('DomainGetLockingStatus', ['domainid' => $domainId]); 32 | } 33 | 34 | /** 35 | * @see https://developers.whmcs.com/api-reference/domaingetnameservers/ 36 | */ 37 | public function domainGetNameservers(int $domainId) 38 | { 39 | return $this->send('DomainGetNameservers', ['domainid' => $domainId]); 40 | } 41 | 42 | /** 43 | * @see https://developers.whmcs.com/api-reference/domaingetwhoisinfo/ 44 | */ 45 | public function domainGetWhoisInfo(int $domainId) 46 | { 47 | return $this->send('DomainGetWhoisInfo', ['domainid' => $domainId]); 48 | } 49 | 50 | /** 51 | * @see https://developers.whmcs.com/api-reference/domainregister/ 52 | */ 53 | public function domainRegister(array $parameters = []) 54 | { 55 | $resolver = $this->createOptionsResolver(); 56 | $resolver->setDefined(['domainid', 'idnlanguage']); 57 | $resolver->setAllowedTypes('domainid', 'int'); 58 | $resolver->setRequired(['domainid']); 59 | 60 | return $this->send('DomainRegister', $resolver->resolve($parameters)); 61 | } 62 | 63 | /** 64 | * @see https://developers.whmcs.com/api-reference/domainrelease/ 65 | */ 66 | public function domainRelease(array $parameters = []) 67 | { 68 | $resolver = $this->createOptionsResolver(); 69 | $resolver->setDefined(['domainid', 'newtag']); 70 | $resolver->setAllowedTypes('domainid', 'int'); 71 | $resolver->setRequired(['domainid', 'newtag']); 72 | 73 | return $this->send('DomainRelease', $resolver->resolve($parameters)); 74 | } 75 | 76 | /** 77 | * @see https://developers.whmcs.com/api-reference/domainrenew/ 78 | */ 79 | public function domainRenew(array $parameters = []) 80 | { 81 | $resolver = $this->createOptionsResolver(); 82 | $resolver->setDefined(['domainid', 'regperiod']); 83 | $resolver->setAllowedTypes('domainid', 'int'); 84 | $resolver->setRequired(['domainid']); 85 | 86 | return $this->send('DomainRenew', $resolver->resolve($parameters)); 87 | } 88 | 89 | /** 90 | * @see https://developers.whmcs.com/api-reference/domainrequestepp/ 91 | */ 92 | public function domainRequestEpp(int $domainId) 93 | { 94 | return $this->send('DomainRequestEPP', ['domainid' => $domainId]); 95 | } 96 | 97 | /** 98 | * @see https://developers.whmcs.com/api-reference/domaintransfer/ 99 | */ 100 | public function domainTransfer(array $parameters = []) 101 | { 102 | $resolver = $this->createOptionsResolver(); 103 | $resolver->setDefined(['domainid', 'eppcode']); 104 | $resolver->setAllowedTypes('eppcode', 'string'); 105 | $resolver->setRequired(['domainid']); 106 | 107 | return $this->send('DomainTransfer', $resolver->resolve($parameters)); 108 | } 109 | 110 | /** 111 | * @see https://developers.whmcs.com/api-reference/domaintoggleidprotect/ 112 | */ 113 | public function domainToggleIdProtect(array $parameters = []) 114 | { 115 | $resolver = $this->createOptionsResolver(); 116 | $resolver->setDefined(['domainid', 'idprotect']); 117 | $resolver->setAllowedTypes('domainid', 'int'); 118 | $resolver->setAllowedTypes('idprotect', 'bool'); 119 | $resolver->setRequired(['domainid']); 120 | 121 | return $this->send('DomainToggleIdProtect', $resolver->resolve($parameters)); 122 | } 123 | 124 | /** 125 | * @see https://developers.whmcs.com/api-reference/domainupdatelockingstatus/ 126 | */ 127 | public function domainUpdateLockingStatus(array $parameters = []) 128 | { 129 | $resolver = $this->createOptionsResolver(); 130 | $resolver->setDefined(['domainid', 'lockstatus']); 131 | $resolver->setAllowedTypes('domainid', 'int'); 132 | $resolver->setAllowedTypes('lockstatus', 'bool'); 133 | $resolver->setRequired(['domainid']); 134 | 135 | return $this->send('DomainUpdateLockingStatus', $resolver->resolve($parameters)); 136 | } 137 | 138 | /** 139 | * @see https://developers.whmcs.com/api-reference/domainupdatenameservers/ 140 | */ 141 | public function domainUpdateNameservers(array $parameters = []) 142 | { 143 | $resolver = $this->createOptionsResolver(); 144 | $resolver->setDefined(['domainid', 'ns1', 'ns2', 'n3', 'n4', 'ns5']); 145 | $resolver->setAllowedTypes('domainid', 'int'); 146 | $resolver->setAllowedTypes('ns1', 'string'); 147 | $resolver->setAllowedTypes('ns2', 'string'); 148 | $resolver->setRequired(['domainid', 'ns1', 'ns2']); 149 | 150 | return $this->send('DomainUpdateNameservers', $resolver->resolve($parameters)); 151 | } 152 | 153 | /** 154 | * @see https://developers.whmcs.com/api-reference/domainupdatewhoisinfo/ 155 | */ 156 | public function domainUpdateWhoisInfo(array $parameters = []) 157 | { 158 | $resolver = $this->createOptionsResolver(); 159 | $resolver->setDefined(['domainid', 'xml']); 160 | $resolver->setAllowedTypes('domainid', 'int'); 161 | $resolver->setAllowedTypes('xml', 'string'); 162 | $resolver->setRequired(['domainid', 'xml']); 163 | 164 | return $this->send('DomainUpdateWhoisInfo', $resolver->resolve($parameters)); 165 | } 166 | 167 | /** 168 | * @see https://developers.whmcs.com/api-reference/domainwhois/ 169 | */ 170 | public function domainWhois(string $domain) 171 | { 172 | return $this->send('DomainWhois', ['domain' => $domain]); 173 | } 174 | 175 | /** 176 | * @see https://developers.whmcs.com/api-reference/getregistrars/ 177 | */ 178 | public function getRegistrars() 179 | { 180 | return $this->send('GetRegistrars'); 181 | } 182 | 183 | /** 184 | * @see https://developers.whmcs.com/api-reference/gettldpricing/ 185 | */ 186 | public function getTldPricing(array $parameters = []) 187 | { 188 | $resolver = $this->createOptionsResolver(); 189 | $resolver->setDefined(['currencyid', 'clientid']); 190 | $resolver->setAllowedTypes('currencyid', 'int'); 191 | $resolver->setAllowedTypes('clientid', 'int'); 192 | 193 | return $this->send('GetTLDPricing', $resolver->resolve($parameters)); 194 | } 195 | 196 | /** 197 | * @see https://developers.whmcs.com/api-reference/updateclientdomain/ 198 | */ 199 | public function updateClientDomain(array $parameters = []) 200 | { 201 | $resolver = $this->createOptionsResolver(); 202 | $resolver->setDefined([ 203 | 'domainid', 'dnsmanagement', 'emailforwarding', 'idprotection', 'donotrenew', 'type', 'regdate', 204 | 'nextduedate', 'expirydate', 'domain', 'firstpaymentamount', 'recurringamount', 'registrar', 'regperiod', 205 | 'paymentmethod', 'subscriptionid', 'status', 'notes', 'promoid', 'autorecalc', 'updatens', 206 | 'ns1', 'ns2', 'ns3', 'ns4', 'ns5', 207 | ]); 208 | $resolver->setAllowedTypes('domainid', 'int'); 209 | $resolver->setAllowedValues('status', self::STATUS_PRODUCT); 210 | $resolver->setRequired(['domainid']); 211 | 212 | return $this->send('UpdateClientDomain', $resolver->resolve($parameters)); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/Api/Orders.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setDefined([ 16 | 'orderid', 'serverid', 'serviceusername', 'servicepassword', 'registrar', 17 | 'sendregistrar', 'autosetup', 'sendemail', 18 | ]); 19 | $resolver->setAllowedTypes('orderid', 'int'); 20 | $resolver->setAllowedTypes('serverid', 'int'); 21 | $resolver->setAllowedTypes('serviceusername', 'string'); 22 | $resolver->setAllowedTypes('servicepassword', 'string'); 23 | $resolver->setAllowedTypes('registrar', 'string'); 24 | $resolver->setAllowedTypes('sendregistrar', 'bool'); 25 | $resolver->setAllowedTypes('autosetup', 'bool'); 26 | $resolver->setAllowedTypes('sendemail', 'bool'); 27 | 28 | $resolver->setRequired('orderid'); 29 | 30 | return $this->send('AcceptOrder', $resolver->resolve($parameters)); 31 | } 32 | 33 | /** 34 | * @see https://developers.whmcs.com/api-reference/addorder/ 35 | */ 36 | public function addOrder(array $parameters = []) 37 | { 38 | $resolver = $this->createOptionsResolver(); 39 | $resolver->setDefined([ 40 | 'clientid', 'paymentmethod', 'pid', 'domain', 'billingcycle', 'domaintype', 'regperiod', 'idnlanguage', 'eppcode', 41 | 'nameserver1', 'nameserver2', 'nameserver3', 'nameserver4', 'nameserver5', 'customfields', 'configoptions', 42 | 'priceoverride', 'promocode', 'promooverride', 'affid', 'noinvoice', 'noinvoiceemail', 'noemail', 'addons', 43 | 'hostname', 'ns1prefix', 'ns2prefix', 'rootpw', 'contactid', 'dnsmanagement', 'domainfields', 44 | 'emailforwarding', 'idprotection', 'domainpriceoverride', 'domainrenewoverride', 'domainrenewals', 45 | 'addonid', 'serviceid', 'addonids', 'serviceids', 46 | ]); 47 | $resolver->setAllowedTypes('clientid', 'int'); 48 | $resolver->setAllowedTypes('paymentmethod', 'string'); 49 | $resolver->setAllowedTypes('pid', 'int[]'); 50 | $resolver->setAllowedTypes('domain', 'string[]'); 51 | $resolver->setAllowedTypes('billingcycle', 'string[]'); 52 | $resolver->setAllowedTypes('domaintype', 'string[]'); 53 | $resolver->setAllowedTypes('regperiod', 'int[]'); 54 | $resolver->setAllowedTypes('idnlanguage', 'string[]'); 55 | $resolver->setAllowedTypes('eppcode', 'string[]'); 56 | $resolver->setAllowedTypes('nameserver1', 'string'); 57 | $resolver->setAllowedTypes('nameserver2', 'string'); 58 | $resolver->setAllowedTypes('nameserver3', 'string'); 59 | $resolver->setAllowedTypes('nameserver4', 'string'); 60 | $resolver->setAllowedTypes('nameserver5', 'string'); 61 | $resolver->setAllowedTypes('customfields', 'string[]'); 62 | $resolver->setAllowedTypes('configoptions', 'string[]'); 63 | $resolver->setAllowedTypes('priceoverride', 'float[]'); 64 | $resolver->setAllowedTypes('promocode', 'string'); 65 | $resolver->setAllowedTypes('promooverride', 'bool'); 66 | $resolver->setAllowedTypes('affid', 'int'); 67 | $resolver->setAllowedTypes('noinvoice', 'bool'); 68 | $resolver->setAllowedTypes('noinvoiceemail', 'bool'); 69 | $resolver->setAllowedTypes('noemail', 'bool'); 70 | $resolver->setAllowedTypes('addons', 'string[]'); 71 | $resolver->setAllowedTypes('hostname', 'string[]'); 72 | $resolver->setAllowedTypes('ns1prefix', 'string[]'); 73 | $resolver->setAllowedTypes('ns2prefix', 'string[]'); 74 | $resolver->setAllowedTypes('rootpw', 'string[]'); 75 | $resolver->setAllowedTypes('contactid', 'int'); 76 | $resolver->setAllowedTypes('dnsmanagement', 'bool[]'); 77 | $resolver->setAllowedTypes('domainfields', 'string[]'); 78 | $resolver->setAllowedTypes('emailforwarding', 'bool[]'); 79 | $resolver->setAllowedTypes('idprotection', 'bool[]'); 80 | $resolver->setAllowedTypes('domainpriceoverride', 'float[]'); 81 | $resolver->setAllowedTypes('domainrenewoverride', 'float[]'); 82 | $resolver->setAllowedTypes('domainrenewals', 'array'); 83 | $resolver->setAllowedTypes('addonid', 'int'); 84 | $resolver->setAllowedTypes('serviceid', 'int'); 85 | $resolver->setAllowedTypes('addonids', 'int[]'); 86 | $resolver->setAllowedTypes('serviceids', 'int[]'); 87 | $resolver->setRequired(['clientid', 'paymentmethod']); 88 | 89 | return $this->send('AddOrder', $resolver->resolve($parameters)); 90 | } 91 | 92 | /** 93 | * @see https://developers.whmcs.com/api-reference/cancelorder/ 94 | */ 95 | public function cancelOrder(array $parameters = []) 96 | { 97 | $resolver = $this->createOptionsResolver(); 98 | $resolver->setDefined(['orderid', 'cancelsub', 'noemail']); 99 | $resolver->setAllowedTypes('orderid', 'int'); 100 | $resolver->setAllowedTypes('cancelsub', 'bool'); 101 | $resolver->setAllowedTypes('noemail', 'bool'); 102 | $resolver->setRequired(['orderid']); 103 | 104 | return $this->send('CancelOrder', $resolver->resolve($parameters)); 105 | } 106 | 107 | /** 108 | * @see https://developers.whmcs.com/api-reference/deleteorder/ 109 | */ 110 | public function deleteOrder(int $orderId) 111 | { 112 | return $this->send('DeleteOrder', ['orderid' => $orderId]); 113 | } 114 | 115 | /** 116 | * @see https://developers.whmcs.com/api-reference/fraudorder/ 117 | */ 118 | public function fraudOrder(int $orderId, bool $cancelSub = false) 119 | { 120 | return $this->send('FraudOrder', ['orderid' => $orderId, 'cancelsub' => $cancelSub]); 121 | } 122 | 123 | /** 124 | * @see https://developers.whmcs.com/api-reference/getorders/ 125 | */ 126 | public function getOrders(array $parameters = []) 127 | { 128 | $resolver = $this->createOptionsResolver(); 129 | $resolver->setDefined(['userid', 'requestor_id']); 130 | $resolver->setAllowedTypes('userid', 'int'); 131 | $resolver->setAllowedTypes('requestor_id', 'int'); 132 | 133 | return $this->send('GetOrders', $resolver->resolve($parameters)); 134 | } 135 | 136 | /** 137 | * @see https://developers.whmcs.com/api-reference/getorderstatuses/ 138 | */ 139 | public function getOrderStatuses() 140 | { 141 | return $this->send('GetOrderStatuses'); 142 | } 143 | 144 | /** 145 | * @see https://developers.whmcs.com/api-reference/getproducts/ 146 | */ 147 | public function getProducts(array $parameters = []) 148 | { 149 | $resolver = $this->createOptionsResolver(); 150 | $resolver->setDefined(['pid', 'gid', 'module']); 151 | $resolver->setAllowedTypes('pid', 'int'); 152 | $resolver->setAllowedTypes('gid', 'int'); 153 | $resolver->setAllowedTypes('module', 'string'); 154 | 155 | return $this->send('GetProducts', $resolver->resolve($parameters)); 156 | } 157 | 158 | /** 159 | * @see https://developers.whmcs.com/api-reference/getpromotions/ 160 | */ 161 | public function getPromotions(array $parameters = []) 162 | { 163 | $resolver = $this->createOptionsResolver(); 164 | $resolver->setDefined(['code']); 165 | $resolver->setAllowedTypes('code', 'string'); 166 | 167 | return $this->send('getPromotions', $resolver->resolve($parameters)); 168 | } 169 | 170 | /** 171 | * @see https://developers.whmcs.com/api-reference/orderfraudcheck/ 172 | */ 173 | public function orderFraudCheck(array $parameters = []) 174 | { 175 | $resolver = $this->createOptionsResolver(); 176 | 177 | $resolver->setDefined(['orderid']); 178 | $resolver->setAllowedTypes('orderid', 'int'); 179 | $resolver->setRequired('orderid'); 180 | 181 | return $this->send('OrderFraudCheck', $resolver->resolve($parameters)); 182 | } 183 | 184 | /** 185 | * @see https://developers.whmcs.com/api-reference/pendingorder/ 186 | */ 187 | public function pendingOrder(int $orderId) 188 | { 189 | return $this->send('PendingOrder', ['orderid' => $orderId]); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/Api/Products.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setDefined([ 16 | 'name', 'gid', 'slug', 'type', 'stockcontrol', 'qty', 'paytype', 'hidden', 'showdomainoptions', 17 | 'tax', 'isFeatured', 'proratabilling', 'description', 'shortdescription', 'tagline', 'color', 18 | 'welcomeemail', 'proratadate', 'proratachargenextmonth', 'subdomain', 'autosetup', 'module', 'servergroupid', 19 | 'configoption1', 'configoption2', 'configoption3', 'configoption4', 'configoption5', 'configoption6', 20 | 'order', 'pricing', 'recommendations', 21 | ]); 22 | $resolver->setAllowedTypes('name', 'string'); 23 | $resolver->setAllowedTypes('gid', 'int'); 24 | $resolver->setRequired(['name', 'gid']); 25 | 26 | return $this->send('AddProduct', $resolver->resolve($parameters)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Api/Servers.php: -------------------------------------------------------------------------------- 1 | send('GetHealthStatus', ['fetchStatus' => $fetchStatus]); 15 | } 16 | 17 | /** 18 | * @see https://developers.whmcs.com/api-reference/getservers/ 19 | */ 20 | public function getServers(array $parameters = []) 21 | { 22 | $resolver = $this->createOptionsResolver(); 23 | $resolver->setDefined(['serviceId', 'addonId', 'fetchStatus']); 24 | $resolver->setAllowedTypes('serviceId', 'int'); 25 | $resolver->setAllowedTypes('addonId', 'int'); 26 | $resolver->setAllowedTypes('fetchStatus', 'bool'); 27 | 28 | return $this->send('GetServers', $resolver->resolve($parameters)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Api/Service.php: -------------------------------------------------------------------------------- 1 | send('ModuleChangePackage', ['serviceid' => $serviceId]); 15 | } 16 | 17 | /** 18 | * @see https://developers.whmcs.com/api-reference/modulechangepw/ 19 | */ 20 | public function moduleChangePw(int $serviceId, string $servicePassword) 21 | { 22 | return $this->send('ModuleChangePw', [ 23 | 'serviceid' => $serviceId, 24 | 'servicepassword' => $servicePassword 25 | ]); 26 | } 27 | 28 | /** 29 | * @see https://developers.whmcs.com/api-reference/modulecreate/ 30 | */ 31 | public function moduleCreate(int $serviceId) 32 | { 33 | return $this->send('ModuleCreate', ['serviceid' => $serviceId]); 34 | } 35 | 36 | /** 37 | * @see https://developers.whmcs.com/api-reference/modulecustom/ 38 | */ 39 | public function moduleCustom(int $serviceId, string $funcName) 40 | { 41 | return $this->send('ModuleCustom', [ 42 | 'serviceid' => $serviceId, 43 | 'func_name' => $funcName 44 | ]); 45 | } 46 | 47 | /** 48 | * @see https://developers.whmcs.com/api-reference/modulesuspend/ 49 | */ 50 | public function moduleSuspend(int $serviceId, string $suspendReason) 51 | { 52 | return $this->send('ModuleSuspend', [ 53 | 'serviceid' => $serviceId, 54 | 'suspendreason' => $suspendReason 55 | ]); 56 | } 57 | 58 | /** 59 | * @see https://developers.whmcs.com/api-reference/moduleterminate/ 60 | */ 61 | public function moduleTerminate(int $serviceId) 62 | { 63 | return $this->send('ModuleTerminate', ['serviceid' => $serviceId]); 64 | } 65 | 66 | /** 67 | * @see https://developers.whmcs.com/api-reference/moduleunsuspend/ 68 | */ 69 | public function moduleUnsuspend(int $serviceId) 70 | { 71 | return $this->send('ModuleUnsuspend', ['serviceid' => $serviceId]); 72 | } 73 | 74 | /** 75 | * @see https://developers.whmcs.com/api-reference/updateclientproduct/ 76 | */ 77 | public function updateClientProduct(array $parameters = []) 78 | { 79 | $resolver = $this->createOptionsResolver(); 80 | $resolver->setDefined([ 81 | 'serviceid', 'pid', 'serverid', 'regdate', 'nextduedate', 'terminationdate', 'domain', 'firstpaymentamount', 82 | 'recurringamount', 'paymentmethod', 'billingcycle', 'subscriptionid', 'status', 'notes', 'serviceusername', 83 | 'servicepassword', 'overideautosuspend', 'overidesuspenduntil', 'ns1', 'ns2', 'dedicatedip', 'assignedips', 84 | 'diskusage', 'disklimit', 'bwusage', 'bwlimit', 'suspendreason', 'promoid', 'unset', 'autorecalc', 85 | 'customfields', 'configoptions' 86 | ]); 87 | $resolver->setAllowedTypes('serviceid', 'int'); 88 | $resolver->setRequired(['serviceid']); 89 | 90 | return $this->send('UpdateClientProduct', $resolver->resolve($parameters)); 91 | } 92 | 93 | /** 94 | * @see https://developers.whmcs.com/api-reference/upgradeproduct/ 95 | */ 96 | public function upgradeProduct(array $parameters = []) 97 | { 98 | $resolver = $this->createOptionsResolver(); 99 | $resolver->setDefined([ 100 | 'serviceid', 'calconly', 'paymentmethod', 'type', 'newproductid', 'newproductbillingcycle', 101 | 'promocode', 'configoptions' 102 | ]); 103 | $resolver->setAllowedTypes('serviceid', 'int'); 104 | $resolver->setAllowedTypes('paymentmethod', 'string'); 105 | $resolver->setAllowedTypes('type', 'string'); 106 | $resolver->setRequired(['serviceid', 'paymentmethod', 'type']); 107 | 108 | return $this->send('UpgradeProduct', $resolver->resolve($parameters)); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Api/System.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setAllowedTypes('reason', 'string'); 16 | $resolver->setAllowedTypes('days', 'int'); 17 | $resolver->setRequired(['ip', 'reason', 'days']); 18 | 19 | return $this->send('AddBannedIp', $resolver->resolve($parameters)); 20 | } 21 | 22 | /** 23 | * @see https://developers.whmcs.com/api-reference/decryptpassword/ 24 | */ 25 | public function decryptPassword(string $password) 26 | { 27 | return $this->send('DecryptPassword', ['password2' => $password]); 28 | } 29 | 30 | /** 31 | * @see https://developers.whmcs.com/api-reference/encryptpassword/ 32 | */ 33 | public function encryptPassword(string $password) 34 | { 35 | return $this->send('EncryptPassword', ['password2' => $password]); 36 | } 37 | 38 | /** 39 | * @see https://developers.whmcs.com/api-reference/getstats/ 40 | */ 41 | public function getStats(int $timelineDays) 42 | { 43 | return $this->send('GetStats', ['timeline_days' => $timelineDays]); 44 | } 45 | 46 | /** 47 | * @see https://developers.whmcs.com/api-reference/logactivity/ 48 | */ 49 | public function logActivity(array $parameters = []) 50 | { 51 | $resolver = $this->createOptionsResolver(); 52 | $resolver->setDefined(['clientid', 'description']); 53 | $resolver->setAllowedTypes('clientid', 'int'); 54 | $resolver->setAllowedTypes('description', 'string'); 55 | $resolver->setRequired(['description']); 56 | 57 | return $this->send('LogActivity', $resolver->resolve($parameters)); 58 | } 59 | 60 | /** 61 | * @see https://developers.whmcs.com/api-reference/sendadminemail/ 62 | */ 63 | public function sendAdminEmail(array $parameters = []) 64 | { 65 | $resolver = $this->createOptionsResolver(); 66 | $resolver->setDefined(['id', 'messagename', 'customsubject', 'custommessage', 'type', 'deptid', 'mergefields']); 67 | $resolver->setAllowedTypes('id', 'int'); 68 | $resolver->setAllowedTypes('messagename', 'string'); 69 | $resolver->setAllowedTypes('customsubject', 'string'); 70 | $resolver->setAllowedTypes('custommessage', 'string'); 71 | $resolver->setAllowedTypes('type', 'string'); 72 | $resolver->setAllowedTypes('deptid', 'int'); 73 | $resolver->setAllowedTypes('mergefields', 'array'); 74 | 75 | return $this->send('SendAdminEmail', $resolver->resolve($parameters)); 76 | } 77 | 78 | /** 79 | * @see https://developers.whmcs.com/api-reference/sendemail/ 80 | */ 81 | public function sendMail(array $parameters = []) 82 | { 83 | $resolver = $this->createOptionsResolver(); 84 | $resolver->setDefined(['id', 'messagename', 'customvars', 'customsubject', 'custommessage', 'customtype']); 85 | $resolver->setAllowedTypes('id', 'int'); 86 | $resolver->setAllowedTypes('messagename', 'string'); 87 | $resolver->setAllowedTypes('customvars', 'string'); 88 | $resolver->setAllowedTypes('customsubject', 'string'); 89 | $resolver->setAllowedTypes('custommessage', 'string'); 90 | $resolver->setAllowedTypes('customtype', 'string'); 91 | 92 | return $this->send('SendEmail', $resolver->resolve($parameters)); 93 | } 94 | 95 | /** 96 | * @see https://developers.whmcs.com/api-reference/whmcsdetails/ 97 | */ 98 | public function whmcsDetails() 99 | { 100 | return $this->send('WhmcsDetails'); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Api/Users.php: -------------------------------------------------------------------------------- 1 | createOptionsResolver(); 15 | $resolver->setDefined(['language']); 16 | $resolver->setAllowedTypes('language', 'string'); 17 | $resolver->setRequired(['firstname', 'lastname', 'email', 'password2']); 18 | 19 | return $this->send('AddUser', $resolver->resolve($parameters)); 20 | } 21 | 22 | /** 23 | * @see https://developers.whmcs.com/api-reference/createclientinvite/ 24 | */ 25 | public function createClientInvite(array $parameters = []) 26 | { 27 | $resolver = $this->createOptionsResolver(); 28 | $resolver->setDefined(['client_id', 'email', 'permissions']); 29 | $resolver->setAllowedTypes('client_id', 'string'); 30 | $resolver->setAllowedTypes('permissions', 'string'); 31 | $resolver->setRequired(['client_id', 'email', 'permissions']); 32 | 33 | return $this->send('CreateClientInvite', $resolver->resolve($parameters)); 34 | } 35 | 36 | /** 37 | * @see https://developers.whmcs.com/api-reference/deleteuserclient/ 38 | */ 39 | public function deleteUserClient(int $userId, int $clientId) 40 | { 41 | return $this->send('DeleteUserClient', [ 42 | 'user_id' => $userId, 43 | 'client_id' => $clientId 44 | ]); 45 | } 46 | 47 | /** 48 | * @see https://developers.whmcs.com/api-reference/getpermissionslist/ 49 | */ 50 | public function getPermissionsList(int $userId, int $clientId) 51 | { 52 | return $this->send('GetPermissionsList'); 53 | } 54 | 55 | /** 56 | * @see https://developers.whmcs.com/api-reference/getuserpermissions/ 57 | */ 58 | public function getUserPermissions(int $userId, int $clientId) 59 | { 60 | return $this->send('GetUserPermissions', [ 61 | 'user_id' => $userId, 62 | 'client_id' => $clientId 63 | ]); 64 | } 65 | 66 | /** 67 | * @see https://developers.whmcs.com/api-reference/getusers/ 68 | */ 69 | public function getUsers(array $parameters = []) 70 | { 71 | return $this->send('GetUsers', $this->createOptionsResolver()->resolve($parameters)); 72 | } 73 | 74 | /** 75 | * @see https://developers.whmcs.com/api-reference/updateuser/ 76 | */ 77 | public function updateUser(array $parameters = []) 78 | { 79 | $resolver = $this->createOptionsResolver(); 80 | $resolver->setDefined(['user_id', 'language']); 81 | $resolver->setAllowedTypes('user_id', 'string'); 82 | $resolver->setRequired(['user_id']); 83 | 84 | return $this->send('UpdateUser', $resolver->resolve($parameters)); 85 | } 86 | 87 | /** 88 | * @see https://developers.whmcs.com/api-reference/updateuserpermissions/ 89 | */ 90 | public function updateUserPermissions(array $parameters = []) 91 | { 92 | $resolver = $this->createOptionsResolver(); 93 | $resolver->setDefined(['user_id', 'client_id', 'permissions']); 94 | $resolver->setAllowedTypes('user_id', 'string'); 95 | $resolver->setAllowedTypes('client_id', 'string'); 96 | $resolver->setAllowedTypes('permissions', 'string'); 97 | $resolver->setRequired(['user_id', 'client_id', 'permissions']); 98 | 99 | return $this->send('UpdateUserPermissions', $resolver->resolve($parameters)); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/ApiEndpointTrait.php: -------------------------------------------------------------------------------- 1 | httpClientBuilder = $builder = $httpClientBuilder ?? new Builder(); 38 | 39 | $builder->addPlugin(new HeaderDefaultsPlugin([ 40 | 'User-Agent' => self::USER_AGENT, 41 | ])); 42 | $builder->addPlugin(new ExceptionHandler()); 43 | $builder->addPlugin(new ContentType()); 44 | $builder->addPlugin(new WhmcsContentType()); 45 | } 46 | 47 | /** 48 | * @param string $identifier 49 | * @param string $secret 50 | * @param string $authMethod 51 | * @return void 52 | */ 53 | public function authenticate(string $identifier, string $secret, string $authMethod = self::AUTH_API_CREDENTIALS): void 54 | { 55 | $this->getHttpClientBuilder()->removePlugin(Authentication::class); 56 | $this->getHttpClientBuilder()->addPlugin( 57 | new Authentication($authMethod, $identifier, $secret) 58 | ); 59 | } 60 | 61 | /** 62 | * @param string $accessKey 63 | * @return void 64 | */ 65 | public function accessKey(string $accessKey): void 66 | { 67 | $this->getHttpClientBuilder()->removePlugin(AccessKey::class); 68 | $this->getHttpClientBuilder()->addPlugin(new AccessKey($accessKey)); 69 | } 70 | 71 | /** 72 | * @param string $url 73 | * @return void 74 | */ 75 | public function url(string $url): void 76 | { 77 | $uri = $this->getHttpClientBuilder()->getUriFactory()->createUri($url); 78 | $uri = $uri->withPath(rtrim($uri->getPath(), '/') . self::API_PATH); 79 | 80 | $this->getHttpClientBuilder()->removePlugin(BaseUriPlugin::class); 81 | $this->getHttpClientBuilder()->addPlugin( 82 | new BaseUriPlugin($uri, ['replace' => true]) 83 | ); 84 | } 85 | 86 | /** 87 | * @return HttpMethodsClientInterface 88 | */ 89 | public function getHttpClient(): HttpMethodsClientInterface 90 | { 91 | return $this->getHttpClientBuilder()->getHttpClient(); 92 | } 93 | 94 | /** 95 | * @return Builder 96 | */ 97 | protected function getHttpClientBuilder(): Builder 98 | { 99 | return $this->httpClientBuilder; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Exception/AuthenticationException.php: -------------------------------------------------------------------------------- 1 | 32 | */ 33 | private array $plugins = []; 34 | 35 | public function __construct( 36 | ClientInterface $httpClient = null, 37 | RequestFactoryInterface $requestFactory = null, 38 | StreamFactoryInterface $streamFactory = null, 39 | UriFactoryInterface $uriFactory = null 40 | ) { 41 | $this->httpClient = $httpClient ?? Psr18ClientDiscovery::find(); 42 | $this->requestFactory = $requestFactory ?? Psr17FactoryDiscovery::findRequestFactory(); 43 | $this->streamFactory = $streamFactory ?? Psr17FactoryDiscovery::findStreamFactory(); 44 | $this->uriFactory = $uriFactory ?? Psr17FactoryDiscovery::findUriFactory(); 45 | } 46 | 47 | public function getHttpClient(): HttpMethodsClientInterface 48 | { 49 | if (null === $this->pluginClient) { 50 | $plugins = $this->plugins; 51 | 52 | $this->pluginClient = new HttpMethodsClient( 53 | (new PluginClientFactory())->createClient($this->httpClient, $plugins), 54 | $this->requestFactory, 55 | $this->streamFactory 56 | ); 57 | } 58 | 59 | return $this->pluginClient; 60 | } 61 | 62 | public function getRequestFactory(): RequestFactoryInterface 63 | { 64 | return $this->requestFactory; 65 | } 66 | 67 | public function getStreamFactory(): StreamFactoryInterface 68 | { 69 | return $this->streamFactory; 70 | } 71 | 72 | public function getUriFactory(): UriFactoryInterface 73 | { 74 | return $this->uriFactory; 75 | } 76 | 77 | public function addPlugin(Plugin $plugin): void 78 | { 79 | $this->plugins[] = $plugin; 80 | $this->pluginClient = null; 81 | } 82 | 83 | public function removePlugin(string $fqcn): void 84 | { 85 | foreach ($this->plugins as $idx => $plugin) { 86 | if ($plugin instanceof $fqcn) { 87 | unset($this->plugins[$idx]); 88 | $this->pluginClient = null; 89 | } 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/HttpClient/Formatter/ResponseFormatter.php: -------------------------------------------------------------------------------- 1 | getBody(); 20 | 21 | if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === 0) { 22 | return json_decode($body, true, 512, JSON_THROW_ON_ERROR); 23 | } 24 | 25 | return $body; 26 | } 27 | 28 | /** 29 | * @param ResponseInterface $response 30 | * @return string|null 31 | */ 32 | public static function errorResult(ResponseInterface $response): ?string 33 | { 34 | try { 35 | $content = self::format($response); 36 | } catch (JsonException $e) { 37 | return null; 38 | } 39 | 40 | return $content['result'] ?? null; 41 | } 42 | 43 | /** 44 | * @param ResponseInterface $response 45 | * @return string|null 46 | */ 47 | public static function errorMessage(ResponseInterface $response): ?string 48 | { 49 | try { 50 | $content = self::format($response); 51 | } catch (JsonException $e) { 52 | return null; 53 | } 54 | 55 | return $content['message'] ?? null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/AccessKey.php: -------------------------------------------------------------------------------- 1 | accessKey = $accessKey; 20 | } 21 | 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise 26 | { 27 | /** @var AppendStream $stream */ 28 | $stream = $request->getBody(); 29 | 30 | $httpQuery = http_build_query(['accesskey' => $this->accessKey]); 31 | 32 | $query = null !== $stream->getSize() 33 | ? '&' . $httpQuery 34 | : $httpQuery; 35 | 36 | $stream->addStream(Utils::streamFor($query)); 37 | 38 | $request = $request->withBody($stream); 39 | 40 | return $next($request); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/Authentication.php: -------------------------------------------------------------------------------- 1 | method = $method; 27 | $this->identifier = $identifier; 28 | $this->secret = $secret; 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise 35 | { 36 | /** @var AppendStream $stream */ 37 | $stream = $request->getBody(); 38 | 39 | $query = null !== $stream->getSize() 40 | ? '&' . $this->buildAuth() 41 | : $this->buildAuth(); 42 | 43 | $stream->addStream(Utils::streamFor($query)); 44 | 45 | $request = $request->withBody($stream); 46 | 47 | return $next($request); 48 | } 49 | 50 | /** 51 | * @return string 52 | */ 53 | private function buildAuth(): string 54 | { 55 | $authBag = []; 56 | switch ($this->method) { 57 | case Client::AUTH_API_CREDENTIALS: 58 | $authBag['identifier'] = $this->identifier; 59 | $authBag['secret'] = $this->secret; 60 | break; 61 | case Client::AUTH_LOGIN_CREDENTIALS: 62 | $authBag['username'] = $this->identifier; 63 | $authBag['password'] = md5($this->secret); 64 | break; 65 | default: 66 | throw new RuntimeException(sprintf('Authentication method "%s" does not exist.', $this->method)); 67 | } 68 | 69 | return http_build_query($authBag); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/ContentType.php: -------------------------------------------------------------------------------- 1 | hasHeader('Content-Type')) { 19 | $request = $request->withHeader('Content-Type', 'application/x-www-form-urlencoded'); 20 | } 21 | 22 | return $next($request); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/ExceptionHandler.php: -------------------------------------------------------------------------------- 1 | then(function (ResponseInterface $response): ResponseInterface { 33 | $status = $response->getStatusCode(); 34 | 35 | /* HTTP Exceptions */ 36 | if ($status >= 400 && $status < 500) { 37 | throw self::transformMessageToException( 38 | $status, 39 | ResponseFormatter::errorMessage($response) ?? $response->getReasonPhrase() 40 | ); 41 | } 42 | 43 | /* 44 | * WHMCS Errors to exception 45 | * any success response is status code 200 46 | */ 47 | $resultResponse = ResponseFormatter::errorResult($response); 48 | if ($status === 200 && $resultResponse === 'error') { 49 | throw self::transformWhmcsMessageToException( 50 | $status, 51 | ResponseFormatter::errorMessage($response) ?? $response->getReasonPhrase() 52 | ); 53 | } 54 | 55 | return $response; 56 | }); 57 | } 58 | 59 | /** 60 | * @param int $status 61 | * @param string|null $message 62 | * @return AuthenticationException|RuntimeException 63 | */ 64 | private static function transformMessageToException(int $status, ?string $message) 65 | { 66 | if (400 === $status && $message === self::ERROR_ACTION_EMPTY) { 67 | return new RuntimeException($message, $status); 68 | } 69 | 70 | if (400 === $status && strpos($message, self::ERROR_AUTH_INVALID_IP)) { 71 | return new IpBlockedException($message, $status); 72 | } 73 | 74 | if (403 === $status && ($message === self::ERROR_AUTH_FAILED || $message === self::ERROR_AUTH_CREDENTIALS)) { 75 | return new AuthenticationException($message, $status); 76 | } 77 | 78 | return new RuntimeException($message, $status); 79 | } 80 | 81 | /** 82 | * @param int $status 83 | * @param string|null $message 84 | * @return ErrorException 85 | */ 86 | private static function transformWhmcsMessageToException(int $status, ?string $message): ErrorException 87 | { 88 | return new ErrorException($message, $status); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/WhmcsContentType.php: -------------------------------------------------------------------------------- 1 | getBody(); 22 | 23 | $query = null !== $stream->getSize() 24 | ? '&' . http_build_query(['responsetype' => 'json']) 25 | : http_build_query(['responsetype' => 'json']); 26 | 27 | $stream->addStream(Utils::streamFor($query)); 28 | 29 | $request = $request->withBody($stream); 30 | 31 | return $next($request); 32 | } 33 | } 34 | --------------------------------------------------------------------------------