How to Extract Per-User Billing Information using SoftLayer's API

In the SoftLayer Customer Portal, billing information is presented for a whole user account. But, sometimes an account owner would like to see the billing information on a per-user basis. While it’s not possible in the Portal, the SoftLayer APIs can be used to extract per-user billing amounts.

To accomplish this, we need to use the Account API service. The method to invoke is called getNextInvoiceTopLevelBillingItems. It returns an array of SoftLayerBillingItem objects. It is quite a big object, and we can use object masks to define which fields of it are of our interest. In our case, we’ll need the orderItem object (of SoftLayer_Billing_Order_Item type), from which, by following the Order->UserRecord->username chain of references, we can identify the portal user login ID. We’ll also need the invoiceItem object (of SoftLayer_Billing_Invoice_Item type), which contains totalRecurringAmount property. Below is a snippet of Ruby code creating the object mask (a value-less hash in Ruby) and calling getNextInvoiceTopLevelBillingItems:

require 'softlayer_api'
require 'pp'

user_id = "your user id"
api_key = "your API key"

object_mask = {"orderItem" => {"order" => {"userRecord" => {"username" => ""}}},
"invoiceItem" => {"totalRecurringAmount" => ""}}

billing = SoftLayer::Service.new("SoftLayer_Account",:username => user_id,
:api_key => api_key)
user_bill= billing.object_mask(object_mask).getNextInvoiceTopLevelBillingItems

pp user_bill

Of course, we can use a different object mask if we’re interested in any other properties of the billing items.

The above code returns an array of SoftLayer_Billing_Item of all users of the account. We can now process this array any way we want; for example, display all items for a particular user and their amounts:

for item in user_bill do
if item.key?("orderItem") &&
item["orderItem"]["order"]["userRecord"]["username"] == ""
pp("User " + "" + " has an invoice item of " +
item["invoiceItem"]["totalRecurringAmount"].to_s())
end
end


The test for existence of orderItem key (on the left-hand side of && in the if statement) assures that the order item exists. Some billing items with no recurring amounts may have no associated order item.

SoftLayer_Billing_Item objects, as well as order and invoice items, can have associated child objects; you can descend to if you are interested in the object details.

For those of you who prefer other programming languages, below is the billing info retrieving code in Python:

client = SoftLayer.Client(username=user_name, api_key=user_key)
object_mask = """mask[id,orderItem[id,order[userRecordId,userRecord[username]]],
invoiceItem[id,totalRecurringAmount]]""";
user_bill = client['Account'].getNextInvoiceTopLevelBillingItems(mask=object_mask)

and in PHP:

require_once 'SoftLayer/SoapClient.class.php';
#...
$client = SoftLayer_SoapClient::getClient('SoftLayer_Account', null, $apiUsername, $apiKey);
$mask = "mask[id,orderItem[id,order[userRecordId,userRecord[username]]],invoiceItem[id,totalRecurringAmount]]";
$client->setObjectMask($mask);
$user_bill = $client->getNextInvoiceTopLevelBillingItems();
#...
?>

In Python and PHP, IDs of relational properties to object masks have to be added in order for these masks to work properly.