Skip to content

Exoscale Marketplace Billing

This page describes how billing works for services provisioned through the Exoscale Marketplace integration. Provisioning and the Open Service Broker API are covered separately on that page. Here we focus on how usage is metered and reported to Exoscale, and how the money flows.

The money flow

VSHN reports Servala usage to Exoscale, Exoscale invoices the end-user, and VSHN invoices Exoscale for the same usage.

flowchart TB
    exo["Exoscale"]
    exocust["Exoscale Customer"]
    vshn["VSHN (Servala)"]

    vshn-- Reports usage --> exo
    exo-- Invoices --> exocust
    exocust-- Pays -->exo
    vshn-- Invoices --> exo
    exo-- Pays -->vshn

The end-user never receives an invoice from VSHN directly. They see the Servala usage on their Exoscale invoice, billed by Exoscale.

What is metered

Billing is event-based. Every Servala service instance generates usage events (based on the billing model: compute, storage, managed service, sizing, and so on). These events are recorded in VSHN Central (Odoo) as analytic usage and aggregated per organization and per service.

There is no fixed monthly subscription fee on the Exoscale side: a customer is billed for the usage their instances accumulate, and an instance that is deleted simply stops accumulating usage.

From Servala line items to one Exoscale item

Servala and Exoscale describe a service at different levels of detail, and the billing integration has to bridge the two.

On the Servala side, the billing model decomposes every service instance into several independent line items: one or more compute lines, one or more storage lines, additional CSP resources, the flat managed service fee, the sizing brackets, and an optional license. Each is priced on its own and appears as a separate line on the organization's Odoo sale order.

On the Exoscale side, a service is a single product with a single billing dimension (service, see How quantity works). Exoscale has no concept of the per-component breakdown: it expects one quantity per product.

To bridge this, we aggregate all the line items that belong to one service instance into a single Exoscale item. We rely on the grouping that Odoo already maintains: every line item of an instance is grouped together on the sale order under a shared sale order line group. The metering job sums the already-priced CHF amounts of all line items in that group and reports the sum as the single quantity for the mapped product.

The detailed component breakdown therefore stays visible inside Servala and Odoo (and on the audit records), while Exoscale and the end-user see one aggregated amount per service.

Reporting usage to Exoscale

Usage is reported to the Exoscale partner metering API.

POST https://partner-api.exoscale.com/v1.alpha/metering:apply

{
    "organization": "exoscale-org-uuid",
    "usage": [
        {
            "product": "servala-postgresql",
            "variable": "service",
            "quantity": 42.50
        },
        {
            "product": "servala-forgejo",
            "variable": "service",
            "quantity": 12.00
        }
    ]
}
  • organization: The Exoscale organization UUID. See Organization mapping.
  • product: The Exoscale product slug that the Servala service maps to. See Product mapping.
  • variable: The Exoscale billing dimension. Servala uses a single dimension named service for every product.
  • quantity: The amount to bill for the reporting period. See How quantity works.

The request uses HTTP Basic Auth. The endpoint, credentials, and timezone are configured in Odoo.

How quantity works

Exoscale's metering model lets a vendor report a raw usage quantity for a billing dimension, and Exoscale multiplies that quantity by a per-unit price held on their side. Servala does not use it that way.

Servala already calculates the price of all usage in Odoo, in CHF, following the billing model. We therefore report the already-priced CHF amount as the quantity, using a single arbitrary-quantity dimension (variable: service).

How Exoscale must handle Servala products

Because the reported quantity is already the CHF amount to charge, Exoscale must configure each Servala product with a single billing dimension service priced at exactly 1 CHF per unit (unit u, arbitrary quantity). With a per-unit price of 1, the amount Exoscale charges equals the amount Servala reports. Any other per-unit price would multiply the charge and produce a wrong invoice.

Quantities are rounded to two decimal places before they are sent.

Organization mapping

Each Servala organization that originates from the Exoscale Marketplace carries the Exoscale organization UUID. When the portal creates the organization through the OSB API, it stores this UUID and writes it onto the organization's Odoo sale order in the external_billing_org_id field, together with external_billing_provider = exoscale.

The metering job reads these two fields to decide which sale orders are in scope for Exoscale reporting and which organization UUID to report each usage record against.

Product mapping

Exoscale expects usage reported against an Exoscale product slug (for example servala-postgresql). Servala maps each billable service to an Exoscale product through a product mapping in Odoo. A mapping entry has:

  • a match string, matched against the service description on the sale order line
  • the target Exoscale product slug
  • the billing dimension (service by default)

Every billable service needs a mapping

If a service has no matching product mapping, its usage is not reported to Exoscale, and the customer is not billed for it. When adding a new service to the Exoscale Marketplace, the product mapping is a required step. See Add a Service to the Exoscale Marketplace.

The Exoscale product slug must match exactly what Exoscale has configured on their side for the product, so the slug has to be agreed with Exoscale during product setup.

Reporting schedule

Usage is reported monthly, per organization.

  • End-of-month report: At the end of each billing month (in the configured timezone, by default Europe/Zurich), the accumulated usage of the month is reported. The report combines the usage that has already been recorded with a deterministic projection of the remaining usage until the end of the month.
  • Reconciliation: After the month has fully closed, the actual recorded usage is recomputed. If it differs from what was reported, a delta adjustment is sent so the total billed amount matches the actual usage. Reconciliation runs once the previous month is over plus a short settling buffer.

The reporting jobs are idempotent: running them more than once in the same window does not double-report. Every report is stored in Odoo as an audit record, including the exact payload that was sent and the HTTP response.

Invoicing

Once a month, VSHN sends a single invoice to Exoscale for the total Servala usage of all Exoscale Marketplace organizations in the previous month. The per-customer breakdown is handled by Exoscale, which invoices each end-user based on the usage Servala reported per organization.

Resources