Customise WHMCS: Building a customer API Call (the proper way)

Customise WHMCS: Building a customer API Call (the proper way)



So, if your like me – you have a strong love / hate relationship with WHMCS. I hate the limitations and arguably annoying design implementations that WHMCS enforces on the developer. I love that you can get around these because the way WHMCS designs these modules inherently makes it loosely coupled.

But WHMCS does make it very annoying to discover this stuff, because mainly its entirely encoded – maybe they don’t want us to! (It’s a conspiracy!)

Today, I show you once again how to get around just one of these limitation – the very limited list of API calls available in WHMCS.

I’ve currently seen two articles on the interwebs that roughly put you on the right track, but to be honest their implementation whilst correct a while ago is now deprecated, so it was time for an update!

So – what changed between WHMCS 4 and 5?

When you jump from 4 to latest, you’ll find a lot of stuff has changed, It’s important to remember that WHMCS loves to silently throw in things, respectively they also love to silently remove things!

Things I noticed they removed?

  • WHMCS Graphing (Ah, twas replaced with their new graphing system, which is actually pretty damn awesome to use)

Things I noticed they added?

  • localAPI function (this is a really cool function, I’m loving the ability to use this)

Anyway’s they did actually change so much stuff, it was scary!

So the previous two articles I found on the internet stated that you right a document in the ~/includes/api/ folder and that’s your call. – whilst this is true, echoing out your response is no longer the way they do business.
– so with that, I emailed support and they told me that I wouldn’t be able to access API’s for custom calls, I decided that wasn’t on, I want to prove them wrong.

Given that WHMCS’s code base is encrypted with Zend, I decided the only way I’m g0ing to work this out was with a little reverse engineering.
I initially took multiple pages and loaded up their declared variables  and worked out their styles and naming conventions – once I had that it was a matter of basically trial and error till I got what they used as the return variable.
So don’t you spend the four hours it took me to work that out, just jump straight too it!

So here it is, step by step:

  1. Create a file in the API folder (the name is what your API call is): ~/includes/api/yourCall.php
  2. In your file, there’s a set of things you need to be aware of:
    1. _POST[s] and _GET[s] aren’t filtered, you NEED to sanitize these data inlets yourself.
    2. When the local API is triggered, the CMD variable will be defined, you can validated that with get_defined_vars();
    3. The CMD variable won’t be defined when you do the API request through a POST.
    4. The api information should be contained within APIvalues variables, you can see this through get_defined_vars();
    5. The most IMPORTANT thing to remember is that results are returned in $apiresults variable!

So all of this, it’s a little difficult to sort through and grab stuff from WHMCS – I wrote a quick function to do it for you:

function get_env($vars) {
  $array = array('action' => array(), 'params' => array());
  if(isset($vars['cmd'])) {
    //Local API mode
    $array['action'] = $vars['cmd'];
    $array['params'] = (object)$vars['apivalues1'];
    $array['adminuser'] = $vars['adminuser'];

  } else {
    //Post CURL mode
    $array['action'] = $vars['_POST']['action'];
    unset($vars['_POST']['username']);
    unset($vars['_POST']['password']);
    unset($vars['_POST']['action']);
    $array['params'] = (object)$vars['_POST'];
  }
  return (object)$array;
}

Now this is how it’ll all look when you get ready to write a custom API call:

<?php

function get_env($vars) {
  $array = array('action' => array(), 'params' => array());
  if(isset($vars['cmd'])) {
    //Local API mode
    $array['action'] = $vars['cmd'];
    $array['params'] = (object)$vars['apivalues1'];
    $array['adminuser'] = $vars['adminuser'];

  } else {
    //Post CURL mode
    $array['action'] = $vars['_POST']['action'];
    unset($vars['_POST']['username']);
    unset($vars['_POST']['password']);
    unset($vars['_POST']['action']);
    $array['params'] = (object)$vars['_POST'];
  }
  return (object)$array;
}

try {
  $vars = get_defined_vars();
  //Get the parameters
  $request = get_env($vars);

  $apiresults =  array(
      "result" => "success",
      "myResultSet" => array(1.222,923.333,"11.11.11.11")
      );
} catch (Exception $e) {
  $apiresults = array("result" => "error", "message" => $e->getMessage());
}
?>

Go have a try!

325.



  • Richard

    It is recommended to use if (!function_exists("get_env")) { ... } if you want to call API multiple times. 😉

  • Milen Videnov

    great! if you need some reliable and professional cloud
    automated services I’d like to strongly recommend you http://www.cloudautomationsolutions.com/services.html
    These guys are truly passionate on what they are doing! s