Billing Usage API guide
The Billing Usage API gives you programmatic access to the same billing data behind your monthly invoices. Query costs on demand, integrate results into your own systems, and build automated reporting pipelines.
Use the Billing Usage API when you need to:
- Automate cost reporting pipelines
- Integrate billing data into your own dashboards or financial systems
- Query across your full account hierarchy on demand
- Aggregate costs at day or month level for period-over-period analysis
| Capability | Billing Usage API | Metrics API | Financial reports |
|---|---|---|---|
| Data type | Financial (costs) | Performance (delivery, engagement) | Financial (costs) |
| Access | Asynchronous API | Asynchronous API | Web interface |
| Time granulation | Day, month | Hour to year | Monthly totals, optional Day breakdown |
| Retention | Current month + 2 months prior | Up to 366 days per query | Current month + 2 months prior |
| Filter by campaign reference | Yes | Yes | No (available as dimension only) |
| Multitenant | Application, entity | Application, entity | Application, entity |
Access and availability
To use the Billing Usage API, you need:
- API key: Must have the
billing:usage:viewscope. See API authorization. - Callback URL: A publicly reachable endpoint on your server where Infobip POSTs results when your query completes. Localhost will not work.
- Date range: Data is available for the current month and the previous two calendar months only.
By default, your results include data for your account, related sub-accounts, and all accounts under your company. This cross-account view mirrors your invoicing structure. If you log in as a sub-account, you see only your own data. See Account hierarchy and visibility.
Coverage
The Billing Usage API supports the following channels and platform services:
For the full list of billing category codes, see Categories in the Billing data reference.
How it works
The Billing Usage API uses an asynchronous request-response pattern:
Submit a request
POST to the Billing Usage API endpoint with your filters, aggregation dimensions, and a callbackUrl pointing to your server.
Receive a request ID
The API immediately returns a requestId (HTTP 201). Processing runs asynchronously.
Receive results at your callback URL
When processing completes, Infobip POSTs the results as JSON to your callbackUrl. Processing time varies based on query complexity and date range.
Data finalization
Billing data for the current month is provisional until the month closes. Totals may change until finalized on the 5th of the following month, when the invoice is issued.
Current month data can change due to:
- Late-arriving traffic records
- Retroactive volume-based discounts
- Pricing adjustments
The API response includes a metadata.billingPeriods array that indicates the finalization status of each billing period in your query. Always verify against your invoice before using billing data for financial planning or billing purposes.
For a broader comparison with the Metrics API, use Metrics API. The two APIs measure different things and are not directly comparable.
Data scope [#data-scope]
These constraints apply to all billing data surfaces (financial reports, Billing Usage API):
- Retention: Current month and up to 2 months prior
- Time zone: UTC. Custom time zones are not supported.
- Multi-data center: Data is generated and accessed per data center. Cross-data center aggregation is not supported. To determine where your accounts are hosted, contact your account manager or Support.
- Invoicing alignment: Billing data follows the same monthly cycles, currency format, and billing structure as Infobip invoices.
Options [#options]
includeUnfinalizedData(boolean, defaulttrue): Set tofalseto return only finalized billing periods and exclude current-month provisional data.
Build your request
Every request requires three fields: callbackUrl, request.filterBy.dateInterval, and at least one entry in request.aggregateBy. All other filters are optional.
dateInterval or aggregateBy return a validation error. The date range must not exceed 3 months.Example [#example]
This returns costs for April 2026 broken down by day. Because sentUntil is exclusive, use the first day of the following month to cover a full calendar month. ACCOUNT_NAME and CATEGORY_CODE are added automatically as defaults since no account or category dimension is specified.
Filters [#filters]
Filters narrow which data is included before processing. dateInterval is required. All others are optional.
| Filter | Description | Notes |
|---|---|---|
dateInterval | Time period for billing data in UTC | Required. Uses sentSince and sentUntil in yyyy-MM-dd format. sentSince is inclusive and sentUntil is exclusive. Max range: current month and two months prior. |
categories | Channel or service to filter by | See Categories. |
trafficTypes | Traffic type within a channel | Values vary by channel. |
platforms | CPaaS X application and entity combination | Use to isolate costs per tenant or use case. |
campaignReferenceIds | Campaign reference ID | Available in the API only, not in financial reports. |
countryCodes | Destination countries | ISO 3166-1 alpha-2 format (for example, ["US", "DE"]). |
subCategories | Service variant within a category | Applicable to Viber only. Accepts VIBER_BM and VIBER_BOTS. |
accountKeys, senders, senderTypes, directions, campaignIds, templateIds | Additional optional filters | See the Billing data reference for valid values. |
SMS_OPERATOR_FEE or MMS_OPERATOR_FEE category for carrier surcharges. To capture the full cost, include both in your filter: categories: ["SMS", "SMS_OPERATOR_FEE"].Aggregation dimensions [#aggregation-dimensions]
Aggregation dimensions define how results are grouped in the response. Filters narrow which data is included; dimensions define how it is grouped. For example, filtering by categories: ["SMS"] limits results to SMS; adding "COUNTRY_NAME" to aggregateBy then breaks that down by country.
At least one dimension is required in aggregateBy. Two pairs have auto-added defaults if you do not specify either variant from the pair:
| If you send... | Result includes... |
|---|---|
["DAY"] | ACCOUNT_NAME, CATEGORY_CODE, DAY |
["ACCOUNT_KEY", "DAY"] | CATEGORY_CODE, ACCOUNT_KEY, DAY |
["ACCOUNT_NAME", "CATEGORY_NAME", "DAY"] | ACCOUNT_NAME, CATEGORY_NAME, DAY |
["ACCOUNT_KEY", "CATEGORY_NAME", "DAY"] | ACCOUNT_KEY, CATEGORY_NAME, DAY |
Default auto-added dimensions:
- ACCOUNT_NAME: Auto-added if neither
ACCOUNT_NAMEnorACCOUNT_KEYis specified. - CATEGORY_CODE: Auto-added if neither
CATEGORY_CODEnorCATEGORY_NAMEis specified.
Specifying one variant suppresses the other; both are never added simultaneously unless you explicitly include both.
Additional dimensions cover time (DAY, MONTH), geography (COUNTRY_NAME, NETWORK_NAME), sender, campaign, and multitenant context (APPLICATION_ID, ENTITY_ID). Campaign and template dimensions return IDs only. Names are not included in billing data.
For the full list of aggregateBy enum values and their definitions, see Dimensions in the Billing data reference.
Response data
Results are delivered to your callback URL as JSON. The response includes:
| Field | Description |
|---|---|
requestId | Matches the ID returned when you submitted the query |
status | SUCCESS or FAILED |
response.requestedPeriod | The time range used in the query. May differ from your requested range due to granularity alignment or finalization trimming. |
response.totalRows | Total number of data rows returned |
response.columns | Array describing each column: columnName (the dimension or cost field code) and columnDataType (STRING, INTEGER, NUMBER, BOOLEAN, DATE_TIME) |
response.rows | Array of data rows. Each row contains values in the same order as the columns array. N/A indicates the field is not applicable for that row combination. |
failureMessage | Present when status is FAILED |
metadata.clientRequestedPeriod | The sentSince and sentUntil values exactly as you submitted them. Compare against response.requestedPeriod to see whether the range was adjusted. |
metadata.billingPeriods | Finalization status of each billing period in your query, given as month (in yyyy-MM format) and volumeFinalized. When volumeFinalized is true, unit counts for that month are complete and no further volume changes are expected. Prices may still change until the invoice is issued, so always verify final amounts against your invoice. |
For cost field definitions and currency format, see Cost fields.
Account hierarchy and visibility
By default, the Billing Usage API returns data across your full account hierarchy: your own account, related sub-accounts, and all accounts under your company. This mirrors your invoicing structure.
If you log in as a sub-account, you see only your own account data. To narrow results to specific accounts, use the accountKeys filter parameter.
Troubleshooting
| Problem | Solution |
|---|---|
| Callback URL is not receiving results | Verify that the callback URL is publicly accessible (localhost will not work). Check for firewall rules that may block incoming requests. Confirm the request was accepted by checking the requestId returned in the initial response. |
| 401 Unauthorized error | Verify the API key has the billing:usage:view scope. See API authorization. |
| Validation error | Check that dateInterval and at least one aggregateBy dimension are included. Verify the date range does not exceed 3 months. |
| Cannot access the Billing Usage API | Verify the API key has the billing:usage:view scope. If the scope is correct, the account may use a legacy setup, which is a structural limitation that cannot be enabled on request. Contact your account manager to confirm. |
Billing data reference
Look up cost fields, billing categories, traffic types by channel, and all available aggregation dimensions.
Financial reports
View the same billing data through the web interface with scheduling and export options.
Metrics API
Query aggregated performance metrics for delivery and engagement analysis across all channels.