All API resources
Voice and SMS market
Market View is the exchange's live order book: every seller's routes with their current price, quality (ASR, ACD) and capacity. Search it for a destination, download a seller's full rate deck, read the busiest destinations, and list your active calls and call or message records.
- POSTSearch Market View
- POSTDownload a route's rate deck
- GETTop destinations by traffic
- POSTList buyer accounts
- GETGet test numbers
- POSTStart a route test call
- POSTList active calls
- POSTList call records (CDRs)
- POSTList SMS records
- GETTop destinations by traffic (buyers)
- GETStart a route test call (signed URL)
Search Market View
POST/marketview/search
Searches the live order book of seller routes (voice by default, SMS with smpp=1) by prefix, country, destination description or seller. Each rate comes with the seller and route, the price you pay including the TCXC commission, billing intervals, capacity, daily and weekly ASR, ACD and minutes, the seller's rating, and any scheduled price changes in frates. Routes from anonymous sellers show vendor_name Anonymous and i_vendor 0. Results are sorted by weekly ASR unless you set order. Searching is free.
{"status": "error", "message": "..."}. The response has no total count: keep requesting with a higher off until fewer than pager rates come back. Prefer country_name to country_code, which can be inaccurate for a few countries.Parameters
searchformintegerform fieldRequiredAlways send 1. Without it the response contains no rates.
prefixstringform fieldOptionalDialling prefix to match: country code, optionally followed by an area or network code. Digits only. A prefix that starts with 1 needs at least four digits. Send at least one of prefix, country, description or seller.
countrystringform fieldOptionalCountry name exactly as TCXC lists it, for example UNITED KINGDOM.
descriptionstringform fieldOptionalText to match in the destination description, such as Mobile or a network name.
sellerstringform fieldOptionalSeller login. Must be an existing seller; routes are matched on any login containing this text. Anonymous routes are excluded when you set it.
sellerlikestringform fieldOptionalSend NOT LIKE to exclude the seller given in
sellerinstead of matching it.routestringform fieldOptionalRoute name to match exactly.
anymeans no filter.typestringform fieldOptionalRoute type, for example CLI, NCLI, TDM or NA.
anymeans no filter.smppintegerform fieldOptional1 searches SMS routes, 0 voice routes.
orderstringform fieldOptionalSort by weekly ASR, weekly ACD or weekly minutes (highest first), or by price (lowest first).
min_pricenumberform fieldOptionalOnly routes priced at or above this amount per minute or per message, including a 3% commission.
max_pricenumberform fieldOptionalOnly routes priced at or below this amount per minute or per message, including a 3% commission.
pagerintegerform fieldOptionalNumber of rates to return.
offintegerform fieldOptionalNumber of rates to skip, for paging.
downloadintegerform fieldOptional1 returns every matching rate as a CSV file (route_lookup.csv) instead of JSON, ignoring pager and off.
Errors
| Message | When |
|---|---|
"At least one of Search Criterias Prefix/Country/Description/Seller is mandatory." | prefix, country, description and seller are all empty |
"The prefix must be only numbers." | prefix contains anything other than digits |
"Prefix 1 should be followed by at least 3 digit area code." | prefix starts with 1 and is shorter than four digits |
"Seller Not Found" | seller is not an existing seller login |
"Country Not Found" | country is not a country name TCXC lists |
"The country must be only characters." | country contains no letters |
"The description must be only characters." | description contains no letters |
"The term 'SELECT' cannot be used in your search." | country or description contains the word SELECT (DELETE and UPDATE return the same message with that word) |
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X POST \
"https://apiv2.telecomsxchange.com/marketview/search" \
-d searchform=1 \
-d prefix=4477 \
-d country='UNITED KINGDOM' \
-d description=Mobile \
-d seller=Northwind \
-d type=CLI \
-d smpp=0 \
-d pager=50 \
-d off=0import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.post(
"https://apiv2.telecomsxchange.com/marketview/search",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
data={"searchform": 1, "prefix": "4477", "country": "UNITED KINGDOM", "description": "Mobile", "seller": "Northwind", "type": "CLI", "smpp": 0, "pager": 50, "off": 0},
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/marketview/search");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => http_build_query(['searchform' => 1, 'prefix' => "4477", 'country' => "UNITED KINGDOM", 'description' => "Mobile", 'seller' => "Northwind", 'type' => "CLI", 'smpp' => 0, 'pager' => 50, 'off' => 0]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"rates": [
{
"prefix": "4477",
"vendor_name": "Northwind",
"connection_name": "UK Mobile Premium",
"i_tariff": "655",
"daily_asr": 41.2,
"weekly_asr": 38.75,
"daily_acd": 3.1,
"weekly_acd": 2.9,
"daily_minutes": 15230,
"weekly_minutes": 98410,
"stats_time": "2026-10-21 03:05:27",
"i_connection": "653",
"effective_from": "10/01/26 9:00AM",
"price_1": "0.011330",
"price_n": "0.011330",
"interval_1": "1",
"interval_n": "1",
"i_vendor": "299",
"capacity_limit": "500",
"i_rate": "143754804",
"forbidden": "0",
"discontinued": "0",
"route_type": "CLI",
"seller_registration_date": "2019-09-13 20:16:26",
"vendor_short_memo": "Tier 1 carrier routes",
"connection_short_memo": "Direct to network, CLI delivered",
"anonymous": "0",
"pos_on_page": 0,
"country_code": "gb",
"country_name": "United Kingdom",
"description": "Mobile - Vodafone",
"mccmnc": "23415",
"seller_avg_rating": 4.5,
"seller_reviews": 12,
"orig_effective_from": "2026-10-01 09:00:00",
"rateid": 143754804,
"frates": [
{
"effective_from": "2026-11-01 00:00:00",
"price_1": "0.0115",
"price_n": "0.0115",
"interval_1": "1",
"interval_n": "1"
}
]
}
]
}Download a route's rate deck
POST/sellers/rates/{i_tariff}
Downloads the full rate deck of a seller route as a CSV file: one row per prefix with country, description, effective date, rate ID, forbidden and discontinued flags, first and next-interval prices, billing intervals, and last-day and last-week ASR, ACD and minutes. Prices include the TCXC commission, so they are what you pay. Find a route's i_tariff with Market View, List seller routes or List interconnects. Authenticate with your buyer credentials. Free.
i_tariff returns only the header row. Send xls in the form body.Parameters
i_tariffintegerpathRequiredThe route's tariff ID (
i_tariff).xlsintegerform fieldOptional1 returns an Excel (.xls) file instead of CSV.
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X POST \
"https://apiv2.telecomsxchange.com/sellers/rates/866"import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.post(
"https://apiv2.telecomsxchange.com/sellers/rates/866",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/sellers/rates/866");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);Top destinations by traffic
GET/sellers/toproutes
Returns the busiest destinations across the whole exchange over a period: the last 24 hours, the 24 hours before that, the last 7 days or the last month. Results are grouped by country, busiest first. Each country lists its billing prefixes with the price billed, the route type and the route ID (id), busiest first. Voice is ranked by minutes, SMS (smpp=1) by message count. Free.
{"status": "error", "message": "..."}. SMS results have no type field.Parameters
periodstringqueryRequiredtoday is the last 24 hours, yesterday the 24 hours before that, week the last 7 days, month the last month up to now.
numberintegerqueryOptionalHow many countries to return, from 1 to 20.
typestringqueryOptionalOnly count traffic on routes of this type. Voice only: leave empty when smpp is 1.
smppintegerqueryOptional1 ranks SMS traffic, 0 voice traffic.
Errors
| Message | When |
|---|---|
"period parameter error. Supported values are today, yesterday, week, month" | period is missing or not one of the four values |
"type parameter error. Supported values are <empty value>/<unset>, TDM, CLI, NCLI, NA" | type is set to anything other than TDM, CLI, NCLI or NA |
"smpp parameter error. Supported values are <empty value>/<unset>, 0, 1 " | smpp is not 0 or 1 |
"type parameter error. Only support for non-smpp reports" | type is set together with smpp=1 |
"number parameter error. Allowed values are from 1 to 20" | number is below 1, above 20, or not a number |
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X GET \
"https://apiv2.telecomsxchange.com/sellers/toproutes?period=week&number=5&type=CLI&smpp=0"import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.get(
"https://apiv2.telecomsxchange.com/sellers/toproutes?period=week&number=5&type=CLI&smpp=0",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/sellers/toproutes?period=week&number=5&type=CLI&smpp=0");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"top_routes": {
"NIGERIA": {
"routes": [
{
"billing_prefix": "234803",
"price": "0.0761",
"type": "CLI",
"id": "882",
"description": "Mobile - MTN"
},
{
"billing_prefix": "234805",
"price": "0.0702",
"type": "CLI",
"id": "882",
"description": "Mobile - Glo"
}
]
},
"UNITED KINGDOM": {
"routes": [
{
"billing_prefix": "447",
"price": "0.0113",
"type": "CLI",
"id": "653",
"description": "Mobile"
}
]
}
}
}List buyer accounts
POST/buyers/account/list
Returns your buyer accounts (voice, SMPP and IoT) with their settings: authorised IP, SIP or SMPP login, balance, credit and capacity limits, the account whose balance each one spends, and, for SMPP accounts, whether the bind is online. Blocked accounts are left out unless show_blocked=1. Free.
smpp_bind_status is ONLINE or OFFLINE for SMPP accounts and empty for others.Parameters
show_blockedintegerform fieldOptional1 includes blocked accounts. 0 or -1 leaves them out.
disable_recurringintegerform fieldOptionalAn
i_accountwhose automatic card top-up should be switched off before the list is returned. This clears the account's top-up amount, threshold and saved card.
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X POST \
"https://apiv2.telecomsxchange.com/buyers/account/list" \
-d show_blocked=0import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.post(
"https://apiv2.telecomsxchange.com/buyers/account/list",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
data={"show_blocked": 0},
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/buyers/account/list");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => http_build_query(['show_blocked' => 0]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"accounts": [
{
"i_account": "1855",
"name": "A2P-TRAFFIC",
"ip_address": "",
"currency": "USD",
"balance": "0.00",
"use_balance": "1022",
"credit_limit": "0",
"i_customer": "1014",
"blocked": "0",
"notification_balance": null,
"last_notification_status": "1",
"capacity_limit": "0",
"voip_login": "smpp307104",
"smpp": "1",
"smpp_rate_limit": "0",
"default_routing_group": "0",
"subspace": "0",
"mqtt": "0",
"window_size": "1000",
"recurring": "0",
"recurring_amount": "0",
"lower_limit": "0",
"parent_balance": "4,035.45",
"parent_name": "NORTHWIND",
"smpp_bind_status": "ONLINE"
},
{
"i_account": "1022",
"name": "NORTHWIND",
"ip_address": "203.0.113.10",
"currency": "USD",
"balance": "4,035.45",
"use_balance": "0",
"credit_limit": "60000",
"i_customer": "1014",
"blocked": "0",
"notification_balance": "1000",
"last_notification_status": "0",
"capacity_limit": "1000",
"voip_login": "",
"smpp": "0",
"smpp_rate_limit": "0",
"default_routing_group": "0",
"subspace": "0",
"mqtt": "0",
"window_size": "1000",
"recurring": "0",
"recurring_amount": "0",
"lower_limit": "0",
"parent_balance": "0.00",
"parent_name": "",
"smpp_bind_status": ""
}
]
}Get test numbers
GET/buyers/tools/getnumbers
Returns phone numbers that recently carried traffic on the exchange for a prefix, country or network, to use as targets in route tests. Numbers are picked at random from recent matching calls, so repeated requests return different numbers. Each comes with its billing prefix and the destination's country and description. Free.
country, description and limit in a POST body; they are ignored in the query string on that form. Errors return {"status": "error", "message": "..."}. When a number's destination is unknown, country_code, country_name and description are N/A. Prefer country_name to country_code, which can be inaccurate for a few countries.Parameters
prefixstringqueryOptionalNumber prefix to match: country code plus an optional area or network code. You can also put it in the path: /buyers/tools/getnumbers/{prefix}. Send at least one of prefix, country or description.
countrystringqueryOptionalText to match in the country name, for example India.
descriptionstringqueryOptionalText to match in the destination description, usually a network name such as Airtel.
limitintegerqueryOptionalHow many numbers to return, up to 1000.
Errors
| Message | When |
|---|---|
"prefix or country description parameters expected" | prefix, country and description are all empty |
"Prefix format error. Expected "12345" " | prefix contains no digits; the rejected value follows the message |
"Country may only contain letters " | country contains no letters |
"Description may only contain letters " | description contains no letters |
"Limit less than 1000 expected" | limit is above 1000 |
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X GET \
"https://apiv2.telecomsxchange.com/buyers/tools/getnumbers?prefix=91&country=India&description=Airtel&limit=10"import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.get(
"https://apiv2.telecomsxchange.com/buyers/tools/getnumbers?prefix=91&country=India&description=Airtel&limit=10",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/buyers/tools/getnumbers?prefix=91&country=India&description=Airtel&limit=10");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"cdrs": [
{
"CLD": "919812345670",
"billing_prefix": "9198",
"country_code": "in",
"country_name": "India",
"description": "Mobile - Airtel"
},
{
"CLD": "919845551203",
"billing_prefix": "9198",
"country_code": "in",
"country_name": "India",
"description": "Mobile - Airtel"
}
]
}Start a route test call
POST/buyers/routetest
Queues a two-leg test call through one of your accounts: TCXC calls cld1 over route i_connection1 showing caller ID cli1, then calls cld2 over route i_connection2 showing cli2. Both routes must be purchased on i_account; to test one route, send the same route ID twice. Both legs are ordinary calls charged to i_account at the purchased routes' rates. The response confirms the test was queued, not how the calls went.
status_text, not status: errors also return status: ok. Always send i_account; without it the response body is empty. Send cld1 and cld2 as plain digits.Parameters
i_accountintegerform fieldRequiredID of your account that places and pays for the test calls.
cld1stringform fieldRequiredFirst number to call, in E.164 format without the plus sign.
cli1stringform fieldRequiredCaller ID to show on the first call. Digits only; a leading + or 0 is removed.
i_connection1integerform fieldRequiredRoute ID (
i_connectionin Market View) for the first call. Must be purchased oni_account.cld2stringform fieldRequiredSecond number to call, in E.164 format without the plus sign.
cli2stringform fieldRequiredCaller ID to show on the second call. Digits only.
i_connection2integerform fieldRequiredRoute ID for the second call. Must be purchased on
i_account. Repeati_connection1to test one route.
Errors
| Message | When |
|---|---|
"Selected account does not have a purchased for selected route(s), please choose other combination or purchase selected route(s) on this account" | i_account is not one of your accounts, or i_connection1 or i_connection2 is not purchased on it |
"CLD format error" | cld1 or cld2 is not a number |
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X POST \
"https://apiv2.telecomsxchange.com/buyers/routetest" \
-d i_account=1501 \
-d cld1=447700900123 \
-d cli1=12025550143 \
-d i_connection1=653 \
-d cld2=4915112345678 \
-d cli2=12025550178 \
-d i_connection2=864import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.post(
"https://apiv2.telecomsxchange.com/buyers/routetest",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
data={"i_account": 1501, "cld1": "447700900123", "cli1": "12025550143", "i_connection1": 653, "cld2": "4915112345678", "cli2": "12025550178", "i_connection2": 864},
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/buyers/routetest");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => http_build_query(['i_account' => 1501, 'cld1' => "447700900123", 'cli1' => "12025550143", 'i_connection1' => 653, 'cld2' => "4915112345678", 'cli2' => "12025550178", 'i_connection2' => 864]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "ok",
"status_text": "Test call has been initiated"
}List active calls
POST/buyers/livecalls
Lists the calls in progress or being routed on all of your accounts, oldest first: called and calling numbers, seller and route, billing prices, authorised duration and amount, and seconds elapsed. Inbound calls to your numbers show connection_name Inbound and route_type DID. Can also hang up one of your calls. Free.
type is Connected or Routing. total_rows counts every matching call, not just this page. A disconnect request returns the call list; check that the call has gone from a later list to confirm the hang-up.Parameters
prefixstringform fieldOptionalOnly calls whose called number starts with this prefix. Leave empty for all calls.
showstringform fieldOptionalcall returns only connected calls, auth only calls still being routed, all both.
pagerintegerform fieldOptionalMaximum number of calls to return.
offintegerform fieldOptionalNumber of calls to skip, for paging.
disconnectintegerform fieldOptionali_live_callof one of your calls to hang up before the list is returned.downloadintegerform fieldOptional1 returns the list as a CSV file (live_calls.csv) instead of JSON.
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X POST \
"https://apiv2.telecomsxchange.com/buyers/livecalls" \
-d prefix=44import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.post(
"https://apiv2.telecomsxchange.com/buyers/livecalls",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
data={"prefix": "44"},
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/buyers/livecalls");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => http_build_query(['prefix' => "44"]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"live_calls": [
{
"i_live_call": "608114221",
"call_id": "46a570fafe8c11e9a4880cc47ab0b860@198.51.100.10-b2b_1",
"type": "Connected",
"CLD": "447700900123",
"CLI": "12025550143",
"authorized_duration": "3600",
"authorized_amount": 0.6798,
"connect_time": "2026-10-22 10:53:58",
"setup_time": "2026-10-22 10:53:57",
"interim_update_time": null,
"i_account": "1501",
"i_purchased_route": "90124",
"i_vendor": "259",
"i_connection": "653",
"i_rate": "111788009",
"billing_prefix": "4477",
"billing_price_1": 0.0113,
"billing_price_n": 0.0113,
"billing_interval_1": "1",
"billing_interval_n": "1",
"cancel_flag": "0",
"parent_call_id": "46a570fafe8c11e9a4880cc47ab0b860@198.51.100.10",
"route_order": "1",
"visible": "1",
"duration": "94",
"vendor_name": "Northwind",
"account_name": "Main SIP trunk",
"connection_name": "UK Mobile Premium",
"route_type": "CLI",
"anonymous": "0",
"link": "i_connection=653",
"country_name": "UNITED KINGDOM",
"description": "Mobile - Vodafone",
"country_code": "gb"
}
],
"total_rows": "1"
}List call records (CDRs)
POST/buyers/callhistory
Lists the call detail records of all your accounts between two times, newest first: called and calling numbers, duration and billed duration, amount charged, billing prices, seller and route, and the disconnect code and reason. Use show to choose answered calls, failed calls or both. Sellers of anonymous routes appear as Anonymous. Free.
show=all, every record also has sip_code (0 for answered calls). For anonymous routes i_vendor is omitted. The response has no total count: page with pager and off.Parameters
showstringform fieldOptionalgood returns answered calls (duration above zero), bad failed calls (zero duration), all both.
date_fromstringform fieldOptionalStart of the period, matched on call setup time, as YYYY-MM-DD HH:MM:SS. Defaults to 24 hours ago.
date_tostringform fieldOptionalEnd of the period, as YYYY-MM-DD HH:MM:SS. Defaults to now.
prefixstringform fieldOptionalOnly calls whose called number starts with this prefix. A full number works too, and % matches any characters.
pagerintegerform fieldOptionalMaximum number of records to return.
offintegerform fieldOptionalNumber of records to skip, for paging.
downloadintegerform fieldOptional1 returns all matching records as a CSV file (cdrs.csv) instead of JSON, ignoring pager and off.
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X POST \
"https://apiv2.telecomsxchange.com/buyers/callhistory" \
-d show=good \
-d date_from='2026-10-21 00:00:00' \
-d date_to='2026-10-22 00:00:00' \
-d prefix=4477 \
-d pager=50 \
-d off=0import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.post(
"https://apiv2.telecomsxchange.com/buyers/callhistory",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
data={"show": "good", "date_from": "2026-10-21 00:00:00", "date_to": "2026-10-22 00:00:00", "prefix": "4477", "pager": 50, "off": 0},
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/buyers/callhistory");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => http_build_query(['show' => "good", 'date_from' => "2026-10-21 00:00:00", 'date_to' => "2026-10-22 00:00:00", 'prefix' => "4477", 'pager' => 50, 'off' => 0]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"cdrs": [
{
"i_cdr": "524807884",
"CLD": "447700900123",
"CLI": "12025550143",
"call_id": "0edc2626fe9311e99c4f002590d192ea@203.0.113.11-b2b_1",
"duration": "94",
"billed_duration": "94",
"connect_time": "2026-10-21 23:38:37",
"disconnect_time": "2026-10-21 23:40:11",
"setup_time": "2026-10-21 23:38:31",
"billing_prefix": "4477",
"billing_price_1": 0.0113,
"billing_price_n": 0.0113,
"billing_interval_1": "1",
"billing_interval_n": "1",
"customer_amount": "0.017703",
"i_customer": "1014",
"i_account": "1501",
"i_vendor": "423",
"i_connection": "653",
"i_purchased_route": "97967",
"disconnect_code": "16",
"customer_ip": "203.0.113.10",
"i_rate": "114110752",
"vendor_name": "Northwind",
"account_name": "Main SIP trunk",
"connection_name": "UK Mobile Premium",
"disconnect_reason": "Normal call clearing",
"anonymous": "0",
"link": "i_connection=653",
"country_name": "UNITED KINGDOM",
"description": "Mobile - Vodafone"
}
]
}List SMS records
POST/buyers/smshistory
Lists the SMS records of all your accounts between two times, newest first: sender and recipient, message text, delivery status, billed message parts, amount charged, seller and route, and destination. Sellers of anonymous routes appear as Anonymous. Free.
sent to choose accepted or failed messages. customer_amount is the amount charged, commission included. For anonymous routes i_vendor is omitted.Parameters
sentintegerform fieldOptional1 returns messages the seller accepted, 0 messages that failed to submit. Any other number returns both.
prefixstringform fieldOptionalOnly messages whose recipient number starts with this prefix.
date_fromstringform fieldOptionalStart of the period, as YYYY-MM-DD HH:MM:SS. Defaults to 24 hours ago.
date_tostringform fieldOptionalEnd of the period, as YYYY-MM-DD HH:MM:SS. Defaults to now.
pagerintegerform fieldOptionalMaximum number of records to return.
offintegerform fieldOptionalNumber of records to skip, for paging.
downloadintegerform fieldOptional1 returns all matching records as a CSV file (sms.csv) instead of JSON.
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X POST \
"https://apiv2.telecomsxchange.com/buyers/smshistory" \
-d sent=1 \
-d prefix=44 \
-d date_from='2026-10-21 00:00:00' \
-d date_to='2026-10-22 00:00:00'import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.post(
"https://apiv2.telecomsxchange.com/buyers/smshistory",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
data={"sent": 1, "prefix": "44", "date_from": "2026-10-21 00:00:00", "date_to": "2026-10-22 00:00:00"},
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/buyers/smshistory");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => http_build_query(['sent' => 1, 'prefix' => "44", 'date_from' => "2026-10-21 00:00:00", 'date_to' => "2026-10-22 00:00:00"]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"sms": [
{
"i_message": "567878",
"message_id": "5d309d43-d6b1-0810-c16e-6c844fa59aeb",
"ts": "2026-10-21 15:47:12",
"delivered": "1",
"sent": "1",
"i_account": "1855",
"i_customer": "1014",
"i_connection": "1160",
"i_vendor": "436",
"message_text": "Your verification code is 482913",
"from_number": "12025550143",
"to_number": "447700900123",
"i_rate": "117989386",
"delivered_in_sec": "3",
"error_text": null,
"billed_msgs_cnt": "1",
"vendor_name": "Northwind",
"account_name": "A2P traffic",
"connection_name": "UK Direct",
"anonymous": "0",
"link": "i_connection=1160",
"country_name": "UNITED KINGDOM",
"description": "Mobile - Vodafone",
"billing_price_1": 0.0255,
"billing_price_n": 0.0255,
"customer_amount": 0.0255
}
]
}Top destinations by traffic (buyers)
GET/buyers/toproutes
Returns the busiest destinations across the whole exchange over a period, grouped by country, busiest first. With smpp=1 it ranks SMS traffic by message count; with smpp=0 (the default) it ranks voice traffic by minutes. Each country lists its billing prefixes with the price billed, the route ID (id) and, for voice, the route type. Free.
{"status": "error", "message": "..."}. top_routes is always an object keyed by country name.Parameters
periodstringqueryRequiredtoday is the last 24 hours, yesterday the 24 hours before that, week the last 7 days, month the last month up to now.
smppintegerqueryOptional1 ranks SMS traffic. Leave unset or send 0 for voice.
numberintegerqueryOptionalHow many countries to return, from 1 to 20.
typestringqueryOptionalVoice only: count only traffic on routes of this type. Leave empty when smpp is 1.
Errors
| Message | When |
|---|---|
"period parameter error. Supported values are today, yesterday, week, month" | period is missing or not one of the four values |
"type parameter error. Supported values are <empty value>/<unset>, TDM, CLI, NCLI, NA" | type is set to anything other than TDM, CLI, NCLI or NA |
"smpp parameter error. Supported values are <empty value>/<unset>, 0, 1 " | smpp is not 0 or 1 |
"type parameter error. Only support for non-smpp reports" | type is set together with smpp=1 |
"number parameter error. Allowed values are from 1 to 20" | number is below 1, above 20, or not a number |
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X GET \
"https://apiv2.telecomsxchange.com/buyers/toproutes?period=week&smpp=1&number=10"import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.get(
"https://apiv2.telecomsxchange.com/buyers/toproutes?period=week&smpp=1&number=10",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/buyers/toproutes?period=week&smpp=1&number=10");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "success",
"top_routes": {
"SPAIN": {
"routes": [
{
"billing_prefix": "34607",
"price": "0.0255",
"id": "1160",
"description": "Mobile - Vodafone"
},
{
"billing_prefix": "34635",
"price": "0.0249",
"id": "1160",
"description": "Mobile - Orange"
}
]
},
"SAUDI ARABIA": {
"routes": [
{
"billing_prefix": "96650",
"price": "0.0133",
"id": "1202",
"description": "Mobile - Al Jawal"
}
]
}
}
}Start a route test call (signed URL)
GET/api/callback/initiate/{login}/{i_account}/{cld1}/{cli1}/{i_connection1}/{cld2}/{cli2}/{i_connection2}/{ts}/{signature}
Queues the same two-leg test call as POST /buyers/routetest, with every value in the URL and a SHA-256 signature. TCXC calls cld1 over i_connection1 showing cli1, then cld2 over i_connection2 showing cli2. Both routes must be purchased on i_account, and both legs are charged to i_account at the purchased routes' rates.
status_text, not status: errors also return status: ok.Parameters
loginstringpathRequiredYour buyer portal login. API access must be enabled for it.
i_accountintegerpathRequiredID of your account that places and pays for the test calls.
cld1stringpathRequiredFirst number to call, digits only (E.164 without the plus sign).
cli1stringpathRequiredCaller ID for the first call, digits only, with no leading 0 or plus sign.
i_connection1integerpathRequiredRoute ID for the first call. Must be purchased on
i_account.cld2stringpathRequiredSecond number to call, digits only.
cli2stringpathRequiredCaller ID for the second call, digits only, with no leading 0 or plus sign.
i_connection2integerpathRequiredRoute ID for the second call. Repeat
i_connection1to test one route.tsintegerpathRequiredCurrent Unix time in seconds. Must be within 12 hours of TCXC's clock.
signaturestringpathRequiredLower-case hex SHA-256 of the URL path up to and including the slash after
ts, followed directly by your API key: sha256('/api/callback/initiate/{login}/{i_account}/{cld1}/{cli1}/{i_connection1}/{cld2}/{cli2}/{i_connection2}/{ts}/' + api_key).
Errors
| Message | When |
|---|---|
"{"status":"error","status_text": "CLDs should be numeric only in E.164 format"}" | cld1 or cld2 contains anything other than digits |
"{"status":"error","status_text": "API authentication error (TS)"}" | ts is more than 12 hours away from TCXC's clock |
"API authentication error (<signed path>) <signature>" | the signature does not match, or the login does not exist or has API access disabled |
"Selected account does not have a purchased for selected route(s), please choose other combination or purchase selected route(s) on this account" | i_account is not one of your accounts or a route is not purchased on it |
curl --digest -u "$TCXC_USERNAME:$TCXC_API_KEY" -X GET \
"https://apiv2.telecomsxchange.com/api/callback/initiate/acme-voice/1501/447700900123/12025550143/653/4915112345678/12025550178/653/1792658400/9f2c4e1a7b0d3f5e8a6c2b4d1e7f9a3c5b8d0e2f4a6c8e1b3d5f7a9c0e2b4d6f"import os
import requests
from requests.auth import HTTPDigestAuth
resp = requests.get(
"https://apiv2.telecomsxchange.com/api/callback/initiate/acme-voice/1501/447700900123/12025550143/653/4915112345678/12025550178/653/1792658400/9f2c4e1a7b0d3f5e8a6c2b4d1e7f9a3c5b8d0e2f4a6c8e1b3d5f7a9c0e2b4d6f",
auth=HTTPDigestAuth(os.environ["TCXC_USERNAME"], os.environ["TCXC_API_KEY"]),
)
print(resp.json())$ch = curl_init("https://apiv2.telecomsxchange.com/api/callback/initiate/acme-voice/1501/447700900123/12025550143/653/4915112345678/12025550178/653/1792658400/9f2c4e1a7b0d3f5e8a6c2b4d1e7f9a3c5b8d0e2f4a6c8e1b3d5f7a9c0e2b4d6f");
curl_setopt_array($ch, [
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_USERPWD => getenv('TCXC_USERNAME') . ':' . getenv('TCXC_API_KEY'),
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);{
"status": "ok",
"status_text": "Test call has been initiated"
}