Billing detail
Overview
Get the full billing picture: every account with its plan, charges, usage, and overage.
Use this for a billing page or reconciliation.
You'll need a partner token.
Returns the itemized data.
Prerequisites
- A Partner bearer token. See Authentication.
- Optional: a
yearandmonth. Leave them out for the current month.
Base URL
| Environment | URL |
|---|---|
| Production | https://production-api.shoutaboutus.com |
| Development | https://development-api.shoutaboutus.com |
Endpoint
GET /api/v1/partner/billing/dashboard
Authentication
Partner token
- Only partner and sub-partner users can call it. Any other token gets
403(Authenticated user is not associated with an partner.). - It always covers your own partner: the accounts directly under it. There is no id to send.
Rate limit
120 requests per minute, counted per user (the token’s user). See Rate limits.
Request parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
year | query | integer | No | Billing year, 2000 to 2100. Defaults to the current year. |
month | query | integer | No | Billing month, 1 to 12. Defaults to the current month. |
Request body
None.
Request payload
None.
Response body
The payload is nested one level deeper than usual: it sits in data.data. It has the same fields as Billing summary, with more detail on each account, plus summary, overage_breakdown, allocation_status and context.
| Field | Type | Description |
|---|---|---|
data.data | object | The billing dashboard. |
data.data.total_billed | number | Total charged to your accounts for the period, to 2 decimals. |
data.data.period | string | The billing period, as YYYY-MM. |
data.data.billing_model | string or null | Your partner's billing model: plan-based or usage-based. null when not set. |
data.data.contract_model | string or null | Your partner's contract model: model-a (overage is charged) or model-b (a flat rate per location, hard stop, no overage). null when not set. |
data.data.active_stores | integer | Active and pending locations across your accounts. |
data.data.accounts | array of objects | One row per account directly under your partner. |
data.data.accounts[].account_id | integer | The account's id. |
data.data.accounts[].account_name | string | The account's name. |
data.data.accounts[].plan_name | string or null | Name of the account's latest plan, or null when it has none. |
data.data.accounts[].store_count | integer | The account's active and pending locations. |
data.data.accounts[].cost | number | Charges for the period, excluding overage, to 2 decimals. |
data.data.accounts[].overage | number | Overage charges for the period, to 2 decimals. |
data.data.accounts[].status | string | halted when a location hit a hard limit in the period, overage when there are overage charges, otherwise within_limits. |
data.data.accounts[].plan_subtitle | string | A one-line label for the plan: plan name, location count and how limits apply, e.g. Growth · 2 loc · Per-location cap. |
data.data.accounts[].enforcement_mode | string | How limits apply: per-location (each location has its own limit) or aggregate-pool (the account shares one pool). |
data.data.accounts[].total_cost | number | cost plus overage, to 2 decimals. |
data.data.accounts[].allocation_note | string | A short note on usage against the allocation, e.g. within allocation, hard stop active or ↑ $0.44 overage (Response posting). For model-b, the same text as billing_formula. |
data.data.accounts[].allocation_state | string | Usage against the allocation: within_allocation, overage or halted. |
data.data.accounts[].billing_formula | string or null | Only for model-b: how the charge is worked out, e.g. 2 × $20.00 · no overage, with (+ proration) when there is a proration charge. null otherwise. |
data.data.summary | object | Headline numbers for the period. |
data.data.summary.total_billed | number | Total charged for the period, to 2 decimals. |
data.data.summary.total_billed_previous_month | number | Total charged for the month before, to 2 decimals. |
data.data.summary.total_billed_change_pct | number or null | Change from the month before, as a percentage to 1 decimal. null when the month before had no charges. |
data.data.summary.total_billed_caption_model_b | string or null | Only for model-b: how the total is worked out, e.g. 2 loc × $20.00 / loc. null otherwise. |
data.data.summary.active_accounts | integer | Accounts directly under your partner. |
data.data.summary.active_stores | integer | Active and pending locations across those accounts. |
data.data.summary.total_overage | number | Total overage charges, to 2 decimals. |
data.data.summary.accounts_with_overage | integer | Accounts with any overage charge. |
data.data.summary.at_limit_locations | integer | Locations that hit a hard limit in the period. |
data.data.summary.halted_locations | integer | Same as at_limit_locations. |
data.data.overage_breakdown | array of objects | Overage charges by account and feature. Empty when there are none. |
data.data.overage_breakdown[].account_id | integer | The account's id. |
data.data.overage_breakdown[].account_name | string | The account's name. |
data.data.overage_breakdown[].features | array of objects | One entry per feature with overage, by feature name. |
data.data.overage_breakdown[].features[].feature_name | string | The billed feature, e.g. response_posting. |
data.data.overage_breakdown[].features[].feature_label | string | Display name of the feature, e.g. Response posting. |
data.data.overage_breakdown[].features[].overage_amount | number | Overage charged for this feature, to 2 decimals. |
data.data.overage_breakdown[].features[].units_over | integer | Units used above the limit. |
data.data.overage_breakdown[].features[].usage_total | integer | Units used across the account's locations in the period. |
data.data.overage_breakdown[].features[].rate | number | Price per unit over the limit, to 4 decimals. |
data.data.overage_breakdown[].features[].unit_price_label | string | The rate as a label, e.g. $0.04/unit. |
data.data.allocation_status | array of objects | Only for model-b: usage against the allocation, one row per account and feature with a limit. Empty for model-a. |
data.data.allocation_status[].account_id | integer | The account's id. |
data.data.allocation_status[].account_name | string | The account's name. |
data.data.allocation_status[].feature_name | string | The feature. |
data.data.allocation_status[].feature_label | string | Display name of the feature, prefixed with Pool for an aggregate pool. |
data.data.allocation_status[].row_title | string | A label for the row: account name and feature, with the number of locations at their limit when there are any. |
data.data.allocation_status[].used | integer | Units used across the account's locations in the period. |
data.data.allocation_status[].allocation | integer | Units allowed: the per-location limit times the number of locations. |
data.data.allocation_status[].percentage | number or null | used as a percentage of allocation, to 1 decimal. null when the allocation is 0. |
data.data.allocation_status[].status | string | halted at or over the allocation, warning from 75%, otherwise on_track. |
data.data.allocation_status[].enforcement_mode | string | per-location or aggregate-pool. |
data.data.allocation_status[].locations_at_limit | integer | Locations that reached their own limit. Always 0 for an aggregate pool. |
data.data.context | object | Labels for the page header. |
data.data.context.headline | string | A heading for the billing setup, e.g. Usage-Based — Model A — Per-Unit Charges. Billing when the models aren't set. |
data.data.context.billing_model | string or null | Your partner's billing model: plan-based or usage-based. null when not set. |
data.data.context.contract_model | string or null | Your partner's contract model: model-a (overage is charged) or model-b (a flat rate per location, hard stop, no overage). null when not set. |
Response payload
{
"data": {
"data": {
"total_billed": 40.44,
"period": "2026-09",
"billing_model": "usage-based",
"contract_model": "model-a",
"active_stores": 2,
"accounts": [
{
"account_id": 5994,
"account_name": "Acme Coffee",
"plan_name": "Growth",
"store_count": 2,
"cost": 40.0,
"overage": 0.44,
"status": "overage",
"plan_subtitle": "Growth · 2 loc · Per-location cap",
"enforcement_mode": "per-location",
"total_cost": 40.44,
"allocation_note": "↑ $0.44 overage (Response posting)",
"allocation_state": "overage",
"billing_formula": null
}
],
"summary": {
"total_billed": 40.44,
"total_billed_previous_month": 40.0,
"total_billed_change_pct": 1.1,
"total_billed_caption_model_b": null,
"active_accounts": 1,
"active_stores": 2,
"total_overage": 0.44,
"accounts_with_overage": 1,
"at_limit_locations": 0,
"halted_locations": 0
},
"overage_breakdown": [
{
"account_id": 5994,
"account_name": "Acme Coffee",
"features": [
{
"feature_name": "response_posting",
"feature_label": "Response posting",
"overage_amount": 0.44,
"units_over": 11,
"usage_total": 61,
"rate": 0.04,
"unit_price_label": "$0.04/unit"
}
]
}
],
"allocation_status": [],
"context": {
"headline": "Usage-Based — Model A — Per-Unit Charges",
"billing_model": "usage-based",
"contract_model": "model-a"
}
}
}
}Examples
Success payload
See Response payload.
Error payload
403 Not a partner
{
"message": "Forbidden",
"status": "error",
"errors": "Authenticated user is not associated with an partner."
}422 Invalid period
{
"message": "The year field must be at least 2000. (and 1 more error)",
"errors": {
"year": [
"The year field must be at least 2000."
],
"month": [
"The month field must not be greater than 12."
]
}
}429 Too many requests
{
"message": "Too Many Attempts."
}| Status | Meaning |
|---|---|
200 | The billing dashboard. |
401 | The token is missing, expired or invalid. |
403 | The caller isn't a partner or sub-partner user. |
422 | year is outside 2000 to 2100, or month is outside 1 to 12. |
429 | More than 120 requests in a minute from this user. |
500 | Unexpected server error. |
Example request
curl --request GET \
--url "https://production-api.shoutaboutus.com/api/v1/partner/billing/dashboard?year=2026&month=9" \
--header 'Authorization: Bearer <bearer-token>' \
--header 'Accept: application/json'Updated 17 days ago
Did this page help you?
