The dataset behind every page on this site
Every figure on this site comes out of one file, and that file is published. It holds 37 providers and 108 plans, each figure copied from the provider's own published pricing page with the URL it was read from and the date it was read. It is free to reuse under CC BY 4.0.
Two formats hold the same rows: data.json keeps the plans nested inside each provider, and data.csv is flat — one row per plan, 108 rows and 48 columns — so it opens in a spreadsheet.
What is in it
| Providers | 37 |
| Plans | 108 |
| Providers publishing a price | 28 |
| Providers asking you to contact sales | 6 |
| Providers whose price we could not read | 3 |
| Rows with at least one field the provider does not state | 37 |
| Recorded changes and corrections | 128 |
| Markets | United States (USD), United Kingdom (GBP) |
| Last full refresh | 2026-08-21 |
The files
| data.csv | One row per plan. Provider fields repeat on each of that provider's rows. UTF-8, comma separated. |
| data.json | One object per provider with plans[] nested inside, plus the change history for each row. Served with CORS open, so you can fetch it from your own page. |
| feed.xml | RSS. One item per provider per day a figure changed. |
| changes | The same history as a page, by month, with the old value and the new one. |
What one row means
In the CSV a row is a plan; the provider columns repeat down that provider's rows. In JSON the same provider fields sit on the object and the plan fields sit in plans[], where they carry the names below without the plan_ prefix.
| Column | Type | What it holds |
|---|---|---|
key | string | URL-safe identifier. The provider page is /d/<key>. |
brand | string | Provider name exactly as the provider writes it. |
brand_short | string | Short form used in page titles where the official name is too long for a title. Empty when the official name is already short. |
page_url | url | The page on this site that holds this row. |
vendor_url | url | The provider's own home page. |
pricing_url | url | The published pricing page every figure in the row was read from. |
markets | list | US, UK, or both. Set by the currency the provider publishes in. We never convert. |
category | string | ucaas (seat-priced phone system), virtual-number (number and line plans), or pbx-license (self-hosted licence). |
parent_company | string | Parent company, or Independent. Empty where we could not confirm it. |
parent_src | url | The page the parent company was confirmed on. |
price_published | boolean | Whether a per-seat price appears on the provider's own page. |
price_visibility | string | Why a price is missing when it is: published, quote_only, not_readable, other_currency. |
fees_disclosure | string | amount (the provider publishes the amount or rate of taxes and fees), stated (says they apply, no amount), none (silent). |
fees_url | url | The page the fee wording was read from. |
fee_treatment | string | How the provider treats taxes and fees at the account level: included, all_inclusive, separate_stated, locale_dependent, unstated. |
affiliate_brand | string | The brand name in our affiliate ledger, where a programme exists. It has no effect on any ordering. |
unconfirmed | list | Field names the provider does not state publicly. These are left empty rather than guessed. |
checked | date | The day the whole row was last read against the provider's page (_checked in data.json). |
| Column | Type | What it holds |
|---|---|---|
plan_name | string | The plan name as the provider writes it. |
plan_currency | string | USD or GBP. Never converted. |
plan_per_seat_annual | number | Per-seat monthly price on annual (or longer) billing. |
plan_per_seat_monthly | number | Per-seat monthly price on monthly billing. Empty where the provider does not publish it. |
plan_flat_monthly | number | Monthly price for plans that are not priced per seat. |
plan_users_included | number | Seats included in a flat plan. |
plan_additional_user_price | number | Price per seat above users_included, where the provider states one. |
plan_tiers | json | Volume bands where the per-seat price changes with seat count, as [{from,to,per_seat}]. |
plan_min_seats | number | Minimum seats billed. |
plan_max_seats | number | Highest seat count this price applies to. |
plan_contract_months | number | Months of commitment the price requires. |
plan_price_is_from | boolean | True where the provider prints the figure as a “from” price. |
plan_setup_fee | number | One-off set-up fee. 0 where the provider states there is none. |
plan_hardware_required | boolean | Whether the plan requires buying hardware. |
plan_minutes_included | string | Call allowance in the provider's own words. |
plan_usage_basis | string | How calls are charged when they are not in the seat price: call_packages, or empty for per-minute. |
plan_free_trial_days | number | Free trial length in days. |
plan_free_months | number | Months free from sign-up, where the provider states a number. |
plan_free_then_plan | string | The plan the free period rolls into. |
plan_fee_uplift_pct | number | Taxes and fees as a percentage, only where the provider publishes the rate. |
plan_vat_basis | string | For UK plans: whether the figure is stated ex-VAT or inc-VAT. |
plan_pricing_model | string | per_seat, flat_package, usage, add_on or quote. |
plan_pstn_included | boolean | Whether calling to the public telephone network is in the price. |
plan_prerequisites | list | Licences you must already hold to buy this plan. |
plan_prerequisite_cost | number | Published price of the cheapest qualifying prerequisite licence, per user per month. |
plan_fee_treatment | string | Plan-level version of fee_treatment, where the provider states it per plan. |
plan_status | string | current or legacy. Legacy plans stay on the provider page but are out of every ranking. |
plan_source_url | url | The page this plan's figures were read from, where it differs from pricing_url. |
plan_checked | date | The day this plan was last read. |
plan_notes | string | The provider's own wording for any condition attached to the price. |
What is deliberately not in it
No computed values. The cost per seat at ten seats, the three-year figure and the monthly-to-annual ratio are worked out at build time from these columns; they are not stored, so nobody has to trust a number whose derivation is invisible. The method page gives the formula.
No converted currencies. USD and GBP rows are never mixed or converted, because a converted figure is one no provider published.
No guesses. Where a provider does not state something, the field is empty and its name appears in unconfirmed. An empty price cell and a provider that will not publish a price are different things, and price_visibility tells them apart.
No ratings. There is no score, star or rank column. Ordering on this site comes from one computed number and nothing else.
4 plans are marked plan_status=legacy: still documented by the provider but out of every ranking.
How often it changes
Figures are re-read against the provider's page and re-dated when they move. Any figure older than 90 days is labelled on the page it appears on. Every change is kept — old value, new value, date and reason — and published in changes and the feed. The URLs above are stable; the file at each one is replaced, never moved.
Licence
The data is published under Creative Commons Attribution 4.0. You may reuse it, including commercially, if you credit Business Phone Costs and link back. The prices themselves are facts published by the providers; the collection, the column definitions and the wording on this site are ours.
Cite this data
If you quote a figure, please cite the dataset rather than an individual page, and give the date you took it — the figures move.
| Reference | Business Phone Costs (2026). Business phone system pricing dataset [Data set]. https://costofsoftware.com/business-phone-system/data |
| In a sentence | “According to Business Phone Costs (2026), …” with a link to https://costofsoftware.com/business-phone-system/data |
| Licence | CC BY 4.0 |
Journalists and researchers are welcome to the whole file. If you need a cut of it that is not here — a market, a category, a date range — ask and it will be produced.
If a figure is wrong
Tell us through the contact form with the provider page you saw it on. It will be re-read, corrected, re-dated and the correction published in changes with the old value beside the new one.
Related
Written by Kaz (pen name). Figures are copied from providers' published pricing pages on the dates shown. We have not used these products. Corrections: contact form.