banshee is under active development: collectors will keep changing, and a version you publish will likely need adjustments. For stable use, wait for version 1.0.0.

Cloud

banshee/cloud-collection/cloud/ovh/https/

billing

The amount an OVHcloud account owes, by its debt account in the OVHcloud API.

  • cloud
  • ovhcloud
  • ovh
  • billing
  • debt
  • https
  • api

by banshee0 installations1 version

v1Latest

Published on October 27, 2026. First version.

Keen 1.0.0 · 52 lines
// What an OVHcloud account owes, by the OVHcloud API with an application's keys: the amount of its debts, in the
// currency of the account.
// Reads GET <api>/me/debtAccount, signed by ovh.sign.
need('protocol:http');
need('protocol:ovh');
$endpoint = need('protocol:ovh:endpoint');

output('due', 'number', array('label' => 'Amount due'));
output('currency', 'text', array('label' => 'Currency'));

watch.above('debt', 'Amount due to OVHcloud', 'due', array('warning' => 0));

// The address of the API set on the probe, checked: https:// only, its host and its version, without a final
// slash, https://eu.api.ovh.com/1.0. The signed headers go there and nowhere else.
function ovh_api($endpoint) {
    if (list.count(text.match($endpoint, '^https://[A-Za-z0-9.-]+/[0-9.]+$')) == 0) {
        fail('misconfigured', 'The address of the OVHcloud API is not written https://<host>/<version>',
            'For instance https://eu.api.ovh.com/1.0, https://ca.api.ovh.com/1.0 or https://api.us.ovhcloud.com/1.0.');
    }
    return $endpoint;
}

// One signed GET on the OVHcloud API: ovh.sign gives the headers that carry the application key, the consumer
// key and the signature; the application secret never leaves.
function ovh_get($api, $path, $what) {
    $url = $api . $path;
    $answer = http.get($url, headers=ovh.sign('GET', $url, ''));
    if ($answer['status'] == 401) {
        fail('misconfigured', 'OVHcloud refuses the keys, code 401',
            'The application key, its secret or the consumer key is wrong, expired or revoked, or the clock of the poller is off.');
    }
    if ($answer['status'] == 403) {
        fail('misconfigured', 'The consumer key may not read ' . $what . ', code 403',
            'Its access rules must allow GET on the routes the documentation of the collector names.');
    }
    if ($answer['status'] == 400 || $answer['status'] == 404) {
        fail('misconfigured', 'OVHcloud refuses to read ' . $what . ', code ' . $answer['status']);
    }
    if ($answer['status'] != 200) {
        fail('unreachable', 'OVHcloud answers the reading of ' . $what . ' with code ' . $answer['status']);
    }
    return json.read($answer['body']);
}

$api = ovh_api($endpoint);

// {"active": true, "dueAmount": {"currencyCode": "EUR", "text": "12.00 €", "value": 12, …}, "pendingAmount": {…},
// "todoAmount": {…}, "unmaturedAmount": {…}}: dueAmount is the amount of the debts the account has; a payment
// being processed is in pendingAmount, and is still due until it clears.
$balance = ovh_get($api, '/me/debtAccount', 'the debt account');
value('due', $balance['dueAmount']['value']);
value('currency', $balance['dueAmount']['currencyCode']);