Skip to main content

International calling rates and dialling codes, as JSON

Two datasets this site already publishes as pages, served as files a program can read. No key, no account, no rate limit worth the name, and a licence that lets you keep what you build.

No authenticationCORS openOpenAPI 3.1CC BY 4.0Updated 2026-09
Every public endpoint. All five are static files on this origin, so a fetch is a CDN hit.
Endpoint What it returns Size
/api/v1/rates.json Per-minute prices for 93 destinations, plus billing terms and credit-pack prices 93 destinations
/api/v1/countries.json Country calling code, exit codes, trunk prefix, number format, timezone, mobile and landline prefixes 136 countries
/api/v1/area-codes.json City and area codes with the timezone each city keeps 202 cities
/api/v1/status.json When each dataset was last rebuilt, and how many rows it holds 1 object
/api/v1/openapi.json OpenAPI 3.1 description of everything above schema

One request, no setup

There is nothing to configure. The following works from a terminal, from a browser console on any origin, and from a server with no credentials configured.

curl -s https://telvio.app/api/v1/rates.json \
  | jq '.destinations[] | select(.iso2 == "IN")'

{
  "country": "India",
  "iso2": "IN",
  "dial_code": "+91",
  "landline_usd_per_min": 0.24,
  "mobile_usd_per_min": 0.24,
  "available": true,
  "page": "https://telvio.app/call/india/"
}

What the fields mean, and where people get them wrong

The shapes are in the OpenAPI description. The meanings are here, because four of these fields are routinely misread, and each misreading produces an answer that looks correct and is not.

available — the difference between a price and a payable price

Every destination in rates.json carries an available boolean. False means the carrier will not connect a call there today. The figure beside it is a real historical price, kept because the reference page for that country stays up while the destination list is being expanded, and dropping the row would break every link pointing at it. Of the 93 destinations in the sheet, 41 are connectable right now. Anything that computes a headline — a cheapest-country claim, an average, a comparison table — has to filter on this field first. We learned that the expensive way: a figure computed over the whole sheet advertised a rate no call could match.

quoted_via — when the price belongs to another country's prefix

Carriers price by dialling prefix, not by country. Several countries share the +1 North American prefix, so a call to one of them is billed at the rate attached to that prefix rather than at a tariff written against the country's name. Where that happens the row carries quoted_via naming the destination whose prefix set the price. It is not a footnote to hide: presenting an inherited price as a country's own negotiated tariff is a small lie that a reader can catch.

exit_codes — belongs to the caller, not to the destination

This is the single most common mistake in dialling data, and it is easy to make because the field sits in the destination's record. exit_codes is what you dial to leave that country — 011 from the United States and Canada, 00 across most of Europe, 010 from Japan, 00 or 009 depending on the operator in a few places. To build a dial string you need the exit code of the country the caller is in and the dial_code of the country they are calling. Reading both off the same record produces a number that fails silently, because the switch simply does not connect and the caller blames the app.

trunk_prefix — the leading zero, and the country that keeps it

A national trunk prefix is the digit a domestic caller dials before an area code, almost always 0. The general rule is that an international caller drops it: a London number written 020 7123 4567 is dialled +44 20 7123 4567. Italy is the exception everyone gets wrong — Italian landline numbers keep the leading 0 from abroad, so +39 06 for Rome, not +39 6. Rather than encoding the exception in your own logic, trust the example field: it is a real, correctly formatted E.164 number for that country, and comparing it against the national form tells you what happens to the prefix.

mobile_prefixes and landline_prefixes — a hint, not a guarantee

These are the digit ranges that identify a line type in each national numbering plan, and they decide the price wherever a destination has a split rate. They stopped being decisive when number portability arrived: a number that was issued as a mobile can be carried to a fixed service and keep its digits. Treat them as the best available signal for pricing an unknown number, and expect a small share of misses. Where landline_usd_per_min and mobile_usd_per_min are equal, the carrier bills one rate for the destination and the distinction does not matter at all — which is the case for most of the sheet.

Where the numbers come from

The rate sheet is not researched, scraped or estimated. It is derived at build time from the pricing endpoint the Telvio app itself calls, using the same longest-prefix lookup the app uses to price a call before you dial it. That is a deliberate architecture rather than a convenience: a price maintained by hand goes stale silently, and the first person to notice is a reader who was quoted one figure and charged another. The site and the app cannot disagree here, because they resolve the same source.

Today the cheapest connectable destination is United Kingdom at $0.03/min. Billing is per second with no connection fee, credit does not expire, and the credit packs are $1.99, $4.99, $9.99 — those are US-dollar credit balances spent at per-country rates, not bundles of minutes. A larger pack is more credit at the same per-minute price; it is not a discount, and the API does not pretend otherwise.

The dialling reference is compiled from published national numbering plans and ITU-T E.164 country-code assignments, and it changes far less often than the tariff. Both datasets report their own freshness in status.json, which is the field to poll rather than re-fetching a 64 KB file on a timer.

The rest of the machine surface

The JSON is the part a program consumes. Four other entry points exist for agents that prefer to read rather than to query, and all of them are generated from the same data on every build, so none of them can drift from the pages.

  • MCP server card — a Model Context Protocol server at /mcp, Streamable HTTP, no authentication. Three read-only tools: a rate for a destination, dialling instructions between two countries, and the caller-ID register. It cannot place a call or spend credit; neither of those has a server-side interface at all.
  • Agent skills — four SKILL.md documents an assistant can load before answering: how to look up a rate correctly, how to build an international dial string, how to identify a call from our caller ID, and how to compare calling services without pretending our own matrix is independent.
  • llms.txt and llms-full.txt — an index of the site and the full text of its primary pages, both generated from the rendered output rather than written by hand.
  • A markdown twin of every page. Append index.md to any URL on this site, or send Accept: text/markdown, and you get the same content without the markup — typically under a tenth of the bytes, which on a page like /call/india/ is the difference between 116 KB and about 11 KB.

Questions

Do I need an API key to use the Telvio rates API?

No. There is no key, no account, no signup and no OAuth flow. Every endpoint is a static JSON file served from the same origin as this page, with CORS open to any origin, so browser JavaScript can fetch it directly. That is also why there is no /.well-known/oauth-authorization-server document here: publishing one would advertise an authentication flow that does not exist.

What is the rate limit?

There is no application-level rate limit, because there is no application — the files sit behind a CDN. The request that costs us nothing is the one you do not make, so cache the response and re-fetch when status.json reports a newer rates_updated. A tariff changes at most a few times a month.

Where do the prices come from?

They are Telvio's own retail tariff, derived at build time from the pricing endpoint the app itself calls. They are the prices the app charges a user, not a market average, not a survey of carriers and not a wholesale rate. Anyone comparing providers should treat them as one vendor's published prices, which is exactly what they are.

Can I use this data commercially?

Yes. Everything under /api/v1/ is licensed CC BY 4.0: use it commercially, modify it, redistribute it, on the single condition that you credit Telvio with a link to telvio.app or to the specific page a figure came from. If you build something with it, a link is the whole licence fee.

Why do some destinations have available set to false?

Because the price is real history but the route is not currently connectable. When the carrier behind the app changed in August 2026 the list of destinations it will terminate to shrank, and those countries kept their previous published figure so their reference pages stayed useful. Never quote an unavailable rate as a price a caller can pay today — filter on available first.

Is there an MCP server for this data?

Yes. An MCP server card is published at /.well-known/mcp/server-card.json and the server speaks Streamable HTTP at /mcp. It exposes the same read-only lookups as the JSON endpoints — a rate for a country, dialling instructions between two countries, and the caller ID register. It cannot place a call, spend credit or read anything about a user, because no such interface exists on this side.

Bottom line

Two files answer almost every question anyone asks this API. rates.json tells you what a minute costs to 93 destinations that have a published price, and whether the route is connectable today. countries.json tells you how to dial 136 of them correctly, including the exit code of the country the caller is standing in, which is the field most implementations get backwards. Both are static, keyless and CORS-open; both are CC BY 4.0, so the only thing we ask is a link back. If something here is wrong or missing, write to [email protected] — the data behind these files is the data behind the app, so a correction lands in both.

1 free minuteNo account, no cardCall free