Skip to content

Get statistics

The statistics methods return call counts, durations, ASR, ACD, revenue and cost for any period, from hours to years, grouped by account, customer, vendor, connection, tariff or destination, plus profit per customer and vendor and the breakdown of disconnect causes. They read hourly, daily and monthly totals that FlySIP keeps for every call, so a year takes as long as a day, and they feed the Statistics screen of the panel. Use them for dashboards, trends and charts; for figures you invoice, use the summary reports, which read the call records themselves.

The vendor, connection, tariff and profit methods are for the root customer only. The account, customer, destination and disconnect-cause methods are open to every customer and limited to its own traffic, without the cost side. All methods support trusted mode with i_customer, which names the customer the call is made for and never narrows the report; to narrow it, use the filters of each method. They read from the database replica.

  • Freshness. Calls are added to the hourly totals a minute or two after they end. data_complete_until in every response is the start of the newest hour that has data; that hour, and an hour in which long calls are still in progress, can still grow. Leave a margin when a period ends at the current time.
  • Buckets. An hourly bucket holds the calls connected within that hour, UTC. Daily and monthly totals are built from the hourly ones. The customer statistics use the setup time of the call instead of the connect time.
  • Retention. Hourly totals are kept for 180 days, daily totals for 3 years, monthly totals without limit. The disconnect causes are kept hourly for 90 days. Statistics stay available after the call records themselves have been deleted.
  • Re-rating. When calls are re-rated, the totals of the affected days are rebuilt, so the figures of a past period can change afterwards.
  • Currency. Amounts are kept in the currency of the account, customer or vendor and converted into cdr_currency at the time of the request with your current exchange rates, like in the panel. The profit totals are converted into the base currency of the system when the calls are aggregated.
  • Calculation. ASR, ACD and PDD are calculated from the sums of the whole period, never averaged over buckets. Figures can differ slightly from the summary reports, which select calls by setup time and read the call records themselves.

The period is start_date up to but not including end_date, both in UTC: for the whole of July send 2026-07-01 00:00:00 and 2026-08-01 00:00:00. This differs from the summary reports, where the end is included.

granularity is the size of the buckets of a time series. With auto it is hour for periods up to 3 days, day up to 120 days and month beyond; a level whose retention does not reach back to start_date is replaced by the next coarser one. The totals of the period do not depend on it: each method sums the period from the coarsest totals that cover it in whole buckets, down to hourly ones, so a period from 22:00 to 22:00 UTC is summed exactly, from hourly totals. Only when no level fits, for example when the period starts at 10:30 or lies beyond the hourly retention without starting on a whole day, is it widened to whole buckets. period_from and period_to then show the period actually covered and period_aligned is True; show that period to your users. The profit, the per-customer destination and the disconnect-cause methods always work in whole days or hours, see each method.

tz sets the time zone whose calendar days and months the day and month buckets of a time series follow. It does not change start_date and end_date, which stay UTC: for 1 July in Amsterdam send 2026-06-30 22:00:00 to 2026-07-01 22:00:00 with tz Europe/Amsterdam. bucket is the start of the bucket as a UTC timestamp, here 2026-06-30 22:00:00+00:00.

These parameters work the same way in every method, unless the method says otherwise.

Name Type Required Description
start_date string no Start of the period, UTC, YYYY-MM-DD HH:MM:SS. The other formats of the summary reports are accepted, but with them period_aligned is always True. Default: 24 hours ago
end_date string no End of the period, UTC, not included. Default: now
granularity string no auto (default), hour, day or month: the bucket size of a time series
tz string no IANA time zone name, for example Europe/Amsterdam, for the day and month buckets of a time series. Default: UTC
timeseries boolean no True returns one row per bucket and per entity, with bucket, for charts. Default: False
totals_only boolean no With timeseries: one row per bucket for all entities together, without IDs and names
cdr_currency string no ISO 4217 code of the currency of all amounts. Default: your base currency
order_by string no Sort key: number_of_calls, billable_calls, duration, billed_duration, revenue, cost, profit, margin, asr, acd or bucket. Rows are sorted from the highest value, bucket from the earliest. Default: bucket for a time series, otherwise the method’s main amount, revenue or cost
limit int no Return at most this many rows. Default: 0, all rows
offset int no Skip this many rows. Default: 0

The response does not say how many rows there are in all. To page through a long list, request pages until one comes back shorter than limit.

Name Type Description
result string OK
report_data array The rows, see Row figures and each method
currency string Currency of all amounts
start_date, end_date string The period as sent, or the defaults
period_from, period_to string The period actually covered, UTC, YYYY-MM-DD HH:MM:SS
period_aligned boolean True when the period was widened to whole buckets
granularity_used string hour, day or month: the bucket size
data_complete_until string Start of the newest hour with data, for example 2026-10-26 09:00:00+00:00; empty when nothing has been aggregated
total_number_of_calls, total_billable_calls int Totals of the whole period
total_duration, total_billed_duration double Totals of the whole period, seconds
total_revenue, total_cost double Totals of the amounts the method returns

The totals cover all rows, regardless of limit and offset.

Every row has these figures next to the fields that identify it.

Name Type Description
number_of_calls int Number of calls; for vendors and connections, of vendor attempts
billable_calls int Answered calls
duration double Total duration, seconds
billed_duration double Total billed duration, seconds
asr double Answered calls divided by all calls, a fraction: 0.5512 is 55.12 %
acd double Billed duration per answered call, seconds
pdd_avg double Average post-dial delay, seconds, over the calls that got a provisional response. Account, customer, vendor and connection rows only; not in totals_only rows
revenue double What the calls were charged, in currency
cost double What the vendors charged for the calls, in currency
margin double revenue minus cost, an amount, in rows that have both
bucket string Start of the bucket, UTC timestamp. Time series only

In the account, customer and destination statistics, cost is the vendors’ charge, the root customer’s purchase price. Only the root customer gets it: other customers get these rows without cost and margin, and without total_cost.

Statistics per account. Any customer may call it: a reseller gets its own accounts, the root customer gets the accounts of every customer unless it sends i_customer_filter. revenue is what the account was charged.

The common parameters, plus:

Name Type Required Description
i_customer_filter int no Root customer only: the accounts of this customer. Send your own ID for your own accounts only
i_account int no Only this account

The common response. Rows have i_account and username, the row figures, revenue, pdd_avg and, for the root customer, cost and margin.

request
call("getStatsAccountSummary", {
"start_date": "2026-07-01 00:00:00",
"end_date": "2026-08-01 00:00:00",
"i_customer_filter": 1,
"limit": 10,
})
response
{
"result": "OK",
"report_data": [
{
"i_account": 3092,
"username": "1001",
"number_of_calls": 1840,
"billable_calls": 1012,
"duration": 98340.0,
"billed_duration": 99120.0,
"asr": 0.55,
"acd": 97.9,
"pdd_avg": 2.315,
"revenue": 245.8,
"cost": 131.2,
"margin": 114.6,
},
# … up to 10 rows, highest revenue first
],
"currency": "USD",
"start_date": "2026-07-01 00:00:00",
"end_date": "2026-08-01 00:00:00",
"period_from": "2026-07-01 00:00:00",
"period_to": "2026-08-01 00:00:00",
"period_aligned": False,
"granularity_used": "day",
"data_complete_until": "2026-10-26 09:00:00+00:00",
"total_number_of_calls": 25410,
"total_billable_calls": 13880,
"total_duration": 1351200.0,
"total_billed_duration": 1362400.0,
"total_revenue": 3390.5,
"total_cost": 1802.75,
}

Statistics per sub-customer. Any customer may call it and gets its direct sub-customers; revenue is what you charged them. Buckets follow the setup time of the calls. The calls of the root customer’s own accounts are not here; use getStatsAccountSummary for them.

The common parameters, plus:

Name Type Required Description
i_customer_filter int no Only this customer. For a reseller it must be a direct sub-customer, otherwise the report is empty
all_levels boolean no Root customer only: True returns the customers of every level of the tree, each with the price of its own level. Do not add up revenue across levels: the same call is counted once per level. Default: False

The common response. Rows have i_customer and name, the row figures, revenue, pdd_avg and, for the root customer, cost and margin.

A reseller asks for two days in its own time zone as a daily time series:

request
call("getStatsCustomerSummary", {
"start_date": "2026-06-30 22:00:00",
"end_date": "2026-07-02 22:00:00",
"timeseries": True,
"granularity": "day",
"tz": "Europe/Amsterdam",
})
response
{
"result": "OK",
"report_data": [
{
"bucket": "2026-06-30 22:00:00+00:00",
"i_customer": 7,
"name": "Sub-reseller LLC",
"number_of_calls": 412,
"billable_calls": 230,
"duration": 21450.0,
"billed_duration": 21800.0,
"asr": 0.5583,
"acd": 94.8,
"pdd_avg": 1.982,
"revenue": 41.7,
},
{
"bucket": "2026-07-01 22:00:00+00:00",
"i_customer": 7,
"name": "Sub-reseller LLC",
# … the same fields
},
],
"granularity_used": "day",
"period_aligned": False,
# … the rest of the common response, without total_cost
}

Statistics per vendor, with what the vendors charged. Only the root customer may call it. Every vendor attempt counts as a call, so asr is per attempt.

The common parameters, plus:

Name Type Required Description
i_vendor int no Only this vendor

The common response, with total_cost and no total_revenue. Rows have i_vendor and name, the row figures, cost and pdd_avg.

request
call("getStatsVendorSummary", {
"start_date": "2026-10-01 00:00:00",
"end_date": "2026-10-26 00:00:00",
"order_by": "asr",
})
response
{
"result": "OK",
"report_data": [
{
"i_vendor": 11,
"name": "Carrier A",
"number_of_calls": 9310,
"billable_calls": 4870,
"duration": 402100.0,
"billed_duration": 405300.0,
"asr": 0.5231,
"acd": 83.2,
"pdd_avg": 3.104,
"cost": 512.36,
},
],
"total_cost": 512.36,
# … the rest of the common response
}

Statistics per vendor connection. Only the root customer may call it. Like the vendor statistics, every attempt counts as a call.

The common parameters, plus:

Name Type Required Description
i_connection int no Only this connection
i_vendor int no Only the connections of this vendor

The common response, with total_cost and no total_revenue. Rows have i_connection and name, the row figures, cost and pdd_avg.

request
call("getStatsConnectionSummary", {
"start_date": "2026-10-25 00:00:00",
"end_date": "2026-10-26 00:00:00",
"i_vendor": 11,
})
response
{
"result": "OK",
"report_data": [
{
"i_connection": 23,
"name": "carrier-a-main",
"number_of_calls": 380,
"billable_calls": 201,
"asr": 0.5289,
"acd": 81.4,
"pdd_avg": 2.87,
"cost": 21.4,
# … duration, billed_duration
},
],
"granularity_used": "hour",
# … the rest of the common response
}

Statistics per tariff: the calls of all accounts, grouped by the tariff of the customer that owns the account. Only the root customer may call it. Rows with i_tariff 0 and an empty name are the calls of customers without a tariff.

The common parameters, plus:

Name Type Required Description
i_tariff int no Only this tariff

The common response, with total_revenue and no total_cost. Rows have i_tariff and name, the row figures and revenue, without pdd_avg.

request
call("getStatsTariffSummary", {
"start_date": "2026-01-01 00:00:00",
"end_date": "2026-10-01 00:00:00",
"cdr_currency": "EUR",
})
response
{
"result": "OK",
"report_data": [
{
"i_tariff": 12,
"name": "Wholesale EU",
"number_of_calls": 120400,
"billable_calls": 66100,
"asr": 0.549,
"acd": 102.6,
"revenue": 18230.4,
# … duration, billed_duration
},
],
"currency": "EUR",
"granularity_used": "month",
# … the rest of the common response
}

Statistics per destination: the longest destination that matches the prefix the call was rated by. Any customer may call it:

  • The root customer gets all calls, at any granularity, or with i_customer_filter the calls of one customer’s accounts.
  • Another customer gets the calls of its own accounts, not of its sub-customers.

The statistics of one customer are kept per day and month only: for them hour granularity becomes day, a period that does not start and end on whole UTC days is widened to whole days, and tz has no effect.

The common parameters, plus:

Name Type Required Description
i_customer_filter int no Root customer only: the calls of this customer’s accounts
i_destination int no Only this destination
country_iso string no Only the destinations of this country, by the three-letter code of the destination, for example UKR
group_by_country boolean no True returns one row per country instead of one per destination. Default: False

The common response. Rows have i_destination, prefix, description, country_iso and country, or with group_by_country only country_iso and country; then the row figures, revenue and, for the root customer, cost and margin, without pdd_avg. Calls with no matching destination come under i_destination 0.

request
call("getStatsDestinationSummary", {
"start_date": "2026-09-01 00:00:00",
"end_date": "2026-10-01 00:00:00",
"group_by_country": True,
"limit": 20,
})
response
{
"result": "OK",
"report_data": [
{
"country_iso": "UKR",
"country": "Ukraine",
"number_of_calls": 48210,
"billable_calls": 27930,
"duration": 2540100.0,
"billed_duration": 2561000.0,
"asr": 0.5793,
"acd": 91.7,
"revenue": 2104.5,
"cost": 1210.3,
"margin": 894.2,
},
# … up to 20 countries, highest revenue first
],
# … the rest of the common response
}

Revenue, cost and profit per customer and vendor. Only the root customer may call it. i_customer is the customer that owns the account that made the call.

The revenue of a call is booked to the vendor that answered it; the cost includes every vendor attempt. Calls that never reached a vendor are booked under i_vendor 0 with revenue only. The totals are kept per day and month: granularity is day or month (hour and short auto periods become day), the period is always widened to whole UTC days or months, and tz and totals_only are not used.

The common parameters, plus:

Name Type Required Description
i_customer_filter int no Only the calls of this customer’s accounts
i_vendor int no Only this vendor
group_by string no both (default) for one row per customer and vendor, customer for one row per customer, vendor for one row per vendor

The common response, with total_number_of_calls, total_revenue, total_cost and total_profit as the only totals. Each row has:

Name Type Description
i_customer, customer_name int, string The customer; not with group_by vendor
i_vendor, vendor_name int, string The vendor; not with group_by customer. 0 and an empty name for calls that never reached a vendor
number_of_calls int Answered calls, and under i_vendor 0 the calls that never reached a vendor
revenue, cost, profit double Amounts in currency; profit is revenue minus cost
margin double profit divided by revenue, a fraction: 0.4167 is 41.67 %. Unlike the other methods, not an amount
bucket string The day or the first day of the month, YYYY-MM-DD. Time series only

The default order is by profit, highest first.

request
call("getStatsProfitSummary", {
"start_date": "2026-01-01 00:00:00",
"end_date": "2026-10-01 00:00:00",
"granularity": "month",
"group_by": "vendor",
})
response
{
"result": "OK",
"report_data": [
{
"i_vendor": 11,
"vendor_name": "Carrier A",
"number_of_calls": 48100,
"revenue": 6120.0,
"cost": 3570.0,
"profit": 2550.0,
"margin": 0.4167,
},
],
"currency": "USD",
"period_from": "2026-01-01 00:00:00",
"period_to": "2026-10-01 00:00:00",
"period_aligned": False,
"granularity_used": "month",
"total_number_of_calls": 48100,
"total_revenue": 6120.0,
"total_cost": 3570.0,
"total_profit": 2550.0,
# … start_date, end_date, data_complete_until
}

The breakdown of calls by disconnect cause, or by who ended the call; the Hangup Causes view of the Statistics screen. Any customer may call it: the root customer selects what to count with scope, another customer always gets the calls of its own accounts.

The disconnect causes are kept per hour for 90 days: the period is widened to whole hours, and an older period returns partial data. granularity, tz, timeseries, cdr_currency and order_by are not used; rows come with the most frequent first.

start_date, end_date, limit and offset from the common parameters, plus:

Name Type Required Description
scope string no Root customer only: vendor (default) counts vendor attempts, connection counts them per connection, customer counts the calls of customers’ accounts
scope_id int no Root customer only: the ID of the vendor, connection or customer to count. Default: all of them
group_by string no release_source returns who ended the calls instead of the disconnect causes
Name Type Description
result string OK
report_data array The rows, see below
scope string The scope used; customer for a customer other than root
start_date, end_date, period_from, period_to, data_complete_until string As in the common response
granularity_used string Always hour
total_number_of_calls int All calls counted

Each row has result, the disconnect cause, description, calls and share_pct, the share of all calls in percent. result 0 is an answered call, 400 to 699 are SIP responses passed through, other codes are the softswitch’s own disconnect causes; it is not the SIP status of the call. description is Answered, the description of the cause, or SIP 486 and the like. With group_by release_source the rows have release_source, one of caller, callee, system and unknown, with calls and share_pct.

request
call("getStatsResultSummary", {
"start_date": "2026-10-25 00:00:00",
"end_date": "2026-10-26 00:00:00",
"scope": "vendor",
"scope_id": 11,
})
response
{
"result": "OK",
"report_data": [
{"result": 0, "description": "Answered", "calls": 5120, "share_pct": 55.02},
{"result": 486, "description": "SIP 486", "calls": 1730, "share_pct": 18.59},
# … the other causes
],
"scope": "vendor",
"start_date": "2026-10-25 00:00:00",
"end_date": "2026-10-26 00:00:00",
"period_from": "2026-10-25 00:00:00",
"period_to": "2026-10-26 00:00:00",
"granularity_used": "hour",
"data_complete_until": "2026-10-26 09:00:00+00:00",
"total_number_of_calls": 9306,
}
faultCode faultString Cause
401 You do not have permissions to use this API call. A customer other than root called the vendor, connection, tariff or profit method
402 Unrecognized date format in start_date. start_date or end_date is in none of the accepted formats
402 start_date must precede end_date. The period is empty or reversed
402 granularity must be auto, hour, day or month. Another granularity value
402 Unknown time zone. tz is not a known IANA time zone name
402 Unsupported order_by value. order_by is not one of the listed keys
402 limit/offset must be integers. limit or offset is not a number
402 group_by must be customer, vendor or both. getStatsProfitSummary: another group_by value
402 scope must be vendor, connection or customer. getStatsResultSummary: another scope value
404 Statistics aggregation is not enabled for this environment. The statistics are not set up on this switch. Use the summary reports instead
404 Customer not found The customer named by i_customer in trusted mode does not exist