User Usage
OrderUsage
OrderUsage is entity in Order domain that is used for measure usage of application defined by metrics. The application itself uploads metrics to the Order domain. Metrics can be uploaded at any time during the month, and they can also be sent multiple times, but only the last (newest) one is valid for future billing. Other (older) metrics are not used for billing, but can be used to summarize incremental metrics in invoiced period.
Preparation
Every application must count its own metrics for each tenant. For example if customer pay per usage of some kind of feature, application must measure these metricts.
Before metrics upload its also good to check if customer (tenant) has valid licence for example by calling licenses GET endpoint in IDM https://[hostname]/api/asol/idm/api/v1/Licenses to be sure, that you can upload metrics.
Implementation
To upload metrics, you need to call POST endpoint https://[hostname]/api/asol/ord/api/v1/OrderUsages with this object (example)
{
"amount": "450.00", // Total price
"dateOfTaxable": "2025-06-31T23:00:00.000Z", // Date, which is shown on invoice. Should be last day in billing period. See limitations below.
"orderNumber": "<string>", // Order number
"orderItemId": "<string>", // OrderItemId
"currency": "<string>", // ISO code of currency
"transactionCostDetail": [
{
"quantity": "30", // quantity of metric
"unitOfMeasure": "Accounts", // unit of measure
"unitPrice": "15.00", // price for 1 metric
"currency": "EUR", // ISO code of currency
"total": "450", // Total price
"name": "<string>", // name
"description": "<string>" // description of subscription
}
]
}
In text below is described, how these properties you get.
For these properties, you need to find SalesItem in orderlines. There are plenty types of orderlines that are connected together. It can be seen on picture below.

Whole uploading and searching is being done in Vendor tenant, so dont forget to switch content to your vendor tenant.
Get all order by calling https://[hostname]/api/asol/ord/api/v1/Order with ProductId and OrderAccessType parameters.
ProductId is Id of yours application. OrderAccessType is Vendor. This call gives you all necessary data to calculate metrics.
Now its need to iterate over all tenants, that your want to upload orderUsage because calling order you get all of order for all of your customers.
Filter order, that got CurrentStatusInfo.SystemStatus == "Done" and Customer.TenantId == "CustomerTenantId". In these orders you have to find order that contain OrderLineType == "Application" and ProductPartCode == "YourProductPartCode".
If you find this order for specific tenant, now is the time for find SalesItem.
Now find applicationOrderLine by filtering on order lines where OrderLineType == "Application" AND ProductPartCode == "YourProductPartCode".
Then editionOrderLine by filtering on order lines where OrderLineType == "Edition" AND ParentOrderLineId == applicationOrderLine.ParentOrderLineId
Then subscriptionOrderLine by filtering on order lines where OrderLineType == "Subscription" AND y.ParentOrderLineId == editionOrderLine.Id
Finaly salesItemOrderLine by filtering on order lines where OrderLineType == "SalesItem" AND ParentOrderLineId == subscriptionOrderLine.Id
For order with billingPeriodCode == "MonthlyForward" you dont need to upload metrics because they are billed automatically without metrics.
Now object should be filled as follows (all of these properties can be found on SalesItem(salesItemOrderLine) object unless otherwise stated):
amount = salesItemOrderLine.Price + salesItemOrderLine.BasePrice * MAX( 0; quantity - salesItemOrderLine.LicenceCount) //basePrice is cost per measure unit; price is fixed price that customer always pays; licenceCount is quantity of metric, that customer pay for this fixed price; quantity is your calculated measure
dateOfTaxable = "2025-06-31T23:00:00.000Z", // Date, which is shown on invoice. Should be last day in billing period. See limitations below.
orderNumber = order.OrderNumber // Is on whole order object
orderItemId = salesItemOrderLine.Id
currency = "EUR", // ISO code of the currency, currently not shown in the order
transactionCostDetail [
{
quantity = quantity // quantity of your metric
unitOfMeasure = salesItemOrderLine.UnitOfSaleCode,
unitPrice = salesItemOrderLine.BasePrice,
currency = "EUR", // ISO code of the currency, currently not shown in the order
total = salesItemOrderLine.Price + salesItemOrderLine.BasePrice * MAX( 0; quantity - salesItemOrderLine.LicenceCount) //basePrice is cost per measure unit; price is fixed price that customer pay always; licenceCount is quantity of metric, that customer pay for this fixed price; quantity is your calculated measure
name = salesItemOrderLine.ProductName, // name
description": "description" // description of subscription
}
]
Limitations
DateOfTaxable:
1st-15th day in month is valid only last day of previous month OR last day of current month.
After 15th is valid only last day of current month
Known issues
DateOfTaxable doesn't reflect time.
GET endpoint https://[hostname]/api/asol/ord/api/v1/OrderUsages which show all of your uploaded metrics badly show dateOfTaxable
Snippet code
private async Task ImportIntoOrderUsage(List<InvoicingSummaryReportModel> invoicingSummaryReportModels, DateTime dateOfTaxable, CancellationToken ct)
{
var impersonationProvider = ServiceProvider.GetRequiredService<IImpersonationProvider>();
using (var impersonatedScope = impersonationProvider.GetImpersonatedRuntimeContextScope(OrderOptions.VendorTenantId))
{
var orderClient = impersonatedScope.ScopeProvider.GetRequiredService<ICustomPlatformStoreOrderClient>();
var orders = await orderClient.GetOrdersAsync(new OrderFilter { OrderAccessType = OrderAccessType.Vendor, ProductId = OrderOptions.ProductId }, new PagingFilter { Limit = int.MaxValue }, ct);
string applicationLabel = "Application";
foreach (var invoicingSummaryReportModel in invoicingSummaryReportModels)
{
try
{
var bankAppOrders = orders.Where(x => x.OrderLines.Any(y => y.OrderLineType == applicationLabel && y.ProductPartCode == OrderOptions.ProductPartCode) && x.CurrentStatusInfo?.SystemStatus == "Done" && x.Customer.TenantId == invoicingSummaryReportModel.TenantId).OrderByDescending(x => x.CurrentStatusInfo?.ModifiedOn).ToList();
var activeOrder = bankAppOrders.FirstOrDefault();
if (activeOrder is null)
{
Logger.LogError("No active order to import to order usage for tenant {tenantId}", invoicingSummaryReportModel.TenantId);
continue;
}
var applicationOrderLine = activeOrder.OrderLines.Where(y => y.OrderLineType == applicationLabel && y.ProductPartCode == OrderOptions.ProductPartCode).Single();
var editionOrderLine = activeOrder.OrderLines.Where(y => y.OrderLineType == "Edition" && y.ParentOrderLineId == applicationOrderLine.ParentOrderLineId).Single();
var subscriptionOrderLine = activeOrder.OrderLines.Where(y => y.OrderLineType == "Subscription" && y.ParentOrderLineId == editionOrderLine.Id).Single();
var salesItemOrderLine = activeOrder.OrderLines.Where(y => y.OrderLineType == "SalesItem" && y.ParentOrderLineId == subscriptionOrderLine.Id).Single();
if (salesItemOrderLine.BillingPeriodCode != "MonthlyForward")
{
var price = salesItemOrderLine.Price + salesItemOrderLine.BasePrice * Math.Max(0, (int)invoicingSummaryReportModel.NumberOfAccounts! - (salesItemOrderLine.LicenceCount ?? 0));
var orderUsage = new CreateOrderUsageModel
{
TransactionCostDetail = new List<TransactionCostDetailItemModel>
{
new TransactionCostDetailItemModel
{
Quantity = invoicingSummaryReportModel.NumberOfAccounts.ToString(),
UnitOfMeasure = salesItemOrderLine.UnitOfSaleCode,
UnitPrice = salesItemOrderLine.BasePrice.ToString(),
Currency = "EUR",
Name = subscriptionOrderLine.ProductName,
Description = "Subscription", //hardcoded subscription
Total = price.ToString(),
}
},
Currency = "EUR",
OrderItemId = salesItemOrderLine.Id,
Amount = price,
DateOfTaxable = dateOfTaxable,
OrderNumber = activeOrder.OrderNumber
};
_ = await orderClient.CreateOrderUsageAsync(orderUsage, ct);
Logger.LogInformation("Successfully imported into order usage for tenant {tenantId}", invoicingSummaryReportModel.TenantId);
}
else
{
Logger.LogWarning("Nothing to import to order usage for tenant {tenantId}", invoicingSummaryReportModel.TenantId);
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Import into order usage failed for tenant {tenantId}", invoicingSummaryReportModel.TenantId);
continue;
}
}
}
}
"OrderOptions": {
"VendorTenantId": "Your-Vendor-TenantId",
"ProductId": "yourCode", // For example: 719197ec-3094-4c99-a670-e4c402717775
"ProductPartCode": "YourProductPartCode" // For example: ASOLEU-BankApp-AP-
}