API reference
Marketplace routes
Browse, resolve, list and manage voice and SMS termination routes.
43 operationsBase URL https://packetexchange.io/api/v1Postman collection
BrowseMarketplace routes
Browse the route marketplace
GET/
- Access
- Key optional. A key or token personalises the answer.
- Rate limit
- 100 requests per second (the default)
Public. Every row is anonymous: no seller name, id or endpoint. Signed-in callers get the full stats block; anonymous callers get counts only. Money fields are 6-decimal USD strings. Each row carries measured (ASR, ACD, NER and PDD measured from real calls, or null) beside the seller-stated expectedAsr/expectedAcd/expectedPdd; anonymous callers get the attempt count as a band and no buyer count. Sort by measured quality with sort=measured_asr_desc|measured_asr_asc|measured_acd_desc|measured_acd_asc|ner_desc|ner_asc, or quality_desc (measured NER then ASR where measured, else stated ASR): listings with measured figures come first.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
type | query | string | -One of voice, sms |
country | query | string | - |
countryCode | query | string | - |
cliType | query | string | -One of full_cli, local_cli, mixed_cli, ncli, partial_cli |
routeType | query | string | -One of direct, premium, standard, ncli |
minPrice | query | string | - |
maxPrice | query | string | - |
minAsr | query | string | - |
minAcd | query | string | - |
maxPdd | query | string | - |
minScore | query | integer | - |
minCapacity | query | integer | - |
billing | query | string | -One of per_second, per_minute |
wholesale | query | string | -One of true, false |
callcenter | query | string | -One of true, false |
retail | query | string | -One of true, false |
otp | query | string | -One of true, false |
openRtp | query | string | -One of true, false |
dialer | query | string | -One of true, false |
a2p | query | string | -One of true, false |
bundlesOnly | query | string | -One of true, false |
search | query | string | - |
sort | query | string | -One of price_asc, price_desc, asr_desc, asr_asc, acd_desc, acd_asc, pdd_asc, pdd_desc, capacity_desc, created_desc, country_asc, score_desc, score_asc, measured_asr_desc, measured_asr_asc, measured_acd_desc, measured_acd_asc, ner_desc, ner_asc, quality_desc |
cursor | query | string (uuid) | - |
limit | query | integer | -Default 25 |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
idrequireddata[].id | string (uuid) | - |
kindrequireddata[].kind | string | -One of single, blend |
typerequireddata[].type | string | -One of voice, sms |
countryrequireddata[].country | string | - |
countryCoderequireddata[].countryCode | string | E.164 country calling code, digits only |
prefixrequireddata[].prefix | string[] | Dial prefixes the route covers |
destinationNamerequireddata[].destinationName | string | The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: "<Country> <Operator?> <Mobile|Fixed|All Networks>" for one destination (e.g. "Niger Mobile", "Kenya Safaricom Mobile"), "A-Z Voice · <tier> · <CLI> · Ref XXXX" or "A-Z SMS · <quality> · Ref XXXX" for an A-Z bundle. The seller sees the name they gave it. |
cliTyperequireddata[].cliType | string | -One of full_cli, ncli, partial_cli, local_cli, mixed_cli |
routeTyperequireddata[].routeType | string | Quality tierOne of direct, premium, standard, ncli |
pricePerUnitrequireddata[].pricePerUnit | money | USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead. USD as a decimal string with exactly 6 places, e.g. "0.012500". |
billingIncrementrequireddata[].billingIncrement | string | null | First/subsequent increment in seconds, e.g. "60/60" |
capacityrequireddata[].capacity | integer | Channels (voice) or messages per second (SMS) |
expectedAsrrequireddata[].expectedAsr | string | null | Seller-stated ASR %. The measured figure is in measured.asr |
expectedAcdrequireddata[].expectedAcd | string | null | Seller-stated ACD in seconds |
expectedPddrequireddata[].expectedPdd | string | null | Seller-stated PDD in seconds |
minAcdrequireddata[].minAcd | integer | null | - |
minAsrrequireddata[].minAsr | string | null | Decimal as a string, e.g. "92.50" |
visibilityrequireddata[].visibility | string | -One of public, private |
statusrequireddata[].status | string | -One of active, paused, suspended, pending_review |
wholesaleCompatiblerequireddata[].wholesaleCompatible | boolean | - |
callcenterCompatiblerequireddata[].callcenterCompatible | boolean | - |
dialerCompatiblerequireddata[].dialerCompatible | boolean | - |
retailCompatiblerequireddata[].retailCompatible | boolean | - |
otpCompatiblerequireddata[].otpCompatible | boolean | - |
notesrequireddata[].notes | string | null | - |
smsTypedata[].smsType | string | null | -One of a2p, p2p, both |
exchangeScorerequireddata[].exchangeScore | integer | null | Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures |
lastQcAtrequireddata[].lastQcAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
measureddata[].measured | object | null | Measured quality from real calls; null until the listing has enough traffic from enough buyers |
windowrequireddata[].measured.window | string | Evidence window: the last 7 days if enough, else the last 30, else last = the most recent 30-day stretch that had enoughOne of 7d, 30d, last |
fromrequireddata[].measured.from | string | First UTC day of the evidence, YYYY-MM-DD |
torequireddata[].measured.to | string | Last UTC day of the evidence, YYYY-MM-DD |
sessionsrequireddata[].measured.sessions | integer | Call attempts on this listing the figures are built from (at least 50). For anonymous callers, floored to a band (50, 100, 250, 500, 1000, 5000, ...) with sessionsBanded: true |
sessionsBandeddata[].measured.sessionsBanded | boolean | True when sessions is a band floor (anonymous callers) |
buyersrequireddata[].measured.buyers | integer | null | Distinct buying accounts behind the figures (at least 2). Null for anonymous callers |
asrrequireddata[].measured.asr | number | null | Answer-seizure ratio %: answered attempts / attempts |
acdrequireddata[].measured.acd | number | null | Average call duration of answered attempts, seconds of talk time |
nerrequireddata[].measured.ner | number | null | Network effectiveness ratio %: attempts the network delivered to the handset (answered, user busy, no answer, callee rejected) / attempts |
pddMsrequireddata[].measured.pddMs | integer | null | Median post-dial delay in milliseconds (to the nearest 100 ms); null when not captured |
routeChecksdata[].routeChecks | object | null | Route checks on this listing in the last 7 days. Null when there were none. |
totalrequireddata[].routeChecks.total | integer | Route checks in the last 7 days that count towards the listing's health (calls to registered test lines) |
answeredrequireddata[].routeChecks.answered | integer | Of those, how many the test line answered through this route |
lastAtrequireddata[].routeChecks.lastAt | string (date-time) | null | When the last check completed |
lastResultrequireddata[].routeChecks.lastResult | string | null | The last check's verdict: working, no_capacity or not_delivered |
createdAtrequireddata[].createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtrequireddata[].updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
isOwnrequireddata[].isOwn | boolean | True only on your own listings |
listingRefdata[].listingRef | string | Anonymous short reference of the listing (4 characters, e.g. "7K2Q"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings. |
sellerProfilerequireddata[].sellerProfile | object | null | Trust signals only. The marketplace never names the seller behind a listing. |
verifiedrequireddata[].sellerProfile.verified | boolean | Seller identity verified |
sellerScorerequireddata[].sellerProfile.sellerScore | integer | null | Average Exchange Score across the seller's trafficked routes |
rateCountrequireddata[].rateCount | integer | Active per-destination deck rows; > 0 means an A-Z deck |
priceTrenddata[].priceTrend | object | null | Real 24h price movement from the price history; null when the route has not repriced |
changePctrequireddata[].priceTrend.changePct | number | - |
pointsrequireddata[].priceTrend.points | number[] | - |
nextCursor | string | null | - |
hasMore | boolean | - |
total | integer | Routes matching the filters across all pages |
stats | object | - |
totalrequiredstats.total | integer | - |
voiceCountrequiredstats.voiceCount | integer | - |
smsCountrequiredstats.smsCount | integer | - |
destinationsrequiredstats.destinations | integer | - |
avgPricestats.avgPrice | number | null | Signed-in callers only. Average list price (display figure) |
avgAsrstats.avgAsr | number | null | Signed-in only. Average seller-stated ASR % |
measuredAsrstats.measuredAsr | number | null | Signed-in only. Measured ASR % over 30 days of real calls |
avgScorestats.avgScore | integer | null | Signed-in only |
totalCapacitystats.totalCapacity | integer | Signed-in only |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List a new route for sale
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 30 requests per minute
Request body (application/json)
| Field | Type | Description |
|---|---|---|
typerequired | string | -One of voice, sms |
countryrequired | string | -max 100 chars |
countryCoderequired | string | - |
prefixrequired | string[] | - |
destinationNamerequired | string | -max 255 chars |
pricePerUnitrequired | string | - |
cliTyperequired | string | -One of full_cli, local_cli, mixed_cli, ncli, partial_cli |
capacityrequired | integer | -0 to 1000000 |
expectedAsr | string | - |
expectedAcd | string | - |
expectedPdd | string | - |
minAsr | string | - |
minAcd | integer | -min 0 |
billingIncrementrequired | string | - |
routeTyperequired | string | -One of direct, premium, standard, ncli |
wholesaleCompatible | boolean | -default true |
callcenterCompatible | boolean | -default true |
dialerCompatible | boolean | -default true |
retailCompatible | boolean | -default true |
otpCompatible | boolean | -default true |
openRtp | boolean | -default false |
visibility | string | -default "public"One of public, private |
jingleEnabled | boolean | -default false |
jingleApiUrl | string (uri) | null | - |
smsDeliveryUrl | string (uri) | null | - |
smsDeliveryMethod | string | -One of http, smpp |
smppHost | string | null | - |
smppPort | integer | null | -1 to 65535 |
smppSystemId | string | null | - |
smppPassword | string | null | -max 64 chars |
smppBindType | string | null | -One of transceiver, transmitter |
smppSystemType | string | null | -max 13 chars |
smppTps | integer | null | -1 to 1000 |
smppSourceTon | integer | null | -0 to 6 |
smppSourceNpi | integer | null | -0 to 18 |
smppDestTon | integer | null | -0 to 6 |
smppDestNpi | integer | null | -0 to 18 |
jingleSipIp | string | null | - |
sipPort | integer | null | -1 to 65535 |
sipAuthUsername | string | null | -max 128 chars |
sipAuthPassword | string | null | -max 128 chars |
techPrefix | string | null | - |
numberFormat | object | null | - |
modenumberFormat.mode | string | -One of custom |
nationalPrefixnumberFormat.nationalPrefix | string | - |
stripnumberFormat.strip | integer | -0 to 10 |
addnumberFormat.add | string | - |
t38Support | boolean | -default false |
supportedCodecs | string[] | - |
maxCallDuration | integer | -min 0 |
smsType | string | -One of a2p, p2p, both |
smsDlrSupport | boolean | - |
smsConcatSupport | boolean | - |
smsSenderIdType | string | -One of alphanumeric, numeric, preregistered |
smsContentRestrictions | string | - |
smsRouteQuality | string | null | -One of hq, direct, aggregator, sim |
smsSenderIdBehavior | string | null | -One of alphanumeric_preserved, numeric_long, overwritten, not_guaranteed |
smsDlrLevel | string | null | -One of real_operator, intermediate, submit_only, none |
smsDlrPercent | string | null | - |
smsUnicodeSupport | boolean | null | - |
smsAcceptedTraffic | string[] | null | -One of wholesale, transactional, otp, marketing, promo_shortcode |
timeOfDayPricing | object | - |
notes | string | -max 2000 chars |
Response 201
| Field | Type | Description |
|---|---|---|
datarequired | object | A route you listed, as only you (the seller) see it. Passwords are never returned. |
idrequireddata.id | string (uuid) | - |
kindrequireddata.kind | string | -One of single, blend |
typerequireddata.type | string | -One of voice, sms |
countryrequireddata.country | string | - |
countryCoderequireddata.countryCode | string | E.164 country calling code, digits only |
prefixrequireddata.prefix | string[] | Dial prefixes the route covers |
destinationNamerequireddata.destinationName | string | The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: "<Country> <Operator?> <Mobile|Fixed|All Networks>" for one destination (e.g. "Niger Mobile", "Kenya Safaricom Mobile"), "A-Z Voice · <tier> · <CLI> · Ref XXXX" or "A-Z SMS · <quality> · Ref XXXX" for an A-Z bundle. The seller sees the name they gave it. |
cliTyperequireddata.cliType | string | -One of full_cli, ncli, partial_cli, local_cli, mixed_cli |
routeTyperequireddata.routeType | string | Quality tierOne of direct, premium, standard, ncli |
pricePerUnitrequireddata.pricePerUnit | money | USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead. USD as a decimal string with exactly 6 places, e.g. "0.012500". |
billingIncrementrequireddata.billingIncrement | string | null | First/subsequent increment in seconds, e.g. "60/60" |
capacityrequireddata.capacity | integer | Channels (voice) or messages per second (SMS) |
expectedAsrrequireddata.expectedAsr | string | null | Seller-stated ASR %. The measured figure is in measured.asr |
expectedAcdrequireddata.expectedAcd | string | null | Seller-stated ACD in seconds |
expectedPddrequireddata.expectedPdd | string | null | Seller-stated PDD in seconds |
minAcdrequireddata.minAcd | integer | null | - |
minAsrrequireddata.minAsr | string | null | Decimal as a string, e.g. "92.50" |
visibilityrequireddata.visibility | string | -One of public, private |
statusrequireddata.status | string | -One of active, paused, suspended, pending_review |
wholesaleCompatiblerequireddata.wholesaleCompatible | boolean | - |
callcenterCompatiblerequireddata.callcenterCompatible | boolean | - |
dialerCompatiblerequireddata.dialerCompatible | boolean | - |
retailCompatiblerequireddata.retailCompatible | boolean | - |
otpCompatiblerequireddata.otpCompatible | boolean | - |
notesrequireddata.notes | string | null | - |
smsTypedata.smsType | string | null | -One of a2p, p2p, both |
exchangeScorerequireddata.exchangeScore | integer | null | Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures |
lastQcAtrequireddata.lastQcAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
measureddata.measured | object | null | Measured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page. |
routeChecksdata.routeChecks | object | null | Route checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page. |
createdAtrequireddata.createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtrequireddata.updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
sellerIdrequireddata.sellerId | string (uuid) | Your own account id |
isOwnerdata.isOwner | boolean | -One of true |
parentRouteIdrequireddata.parentRouteId | string (uuid) | null | - |
isBundlerequireddata.isBundle | boolean | - |
jingleSipIprequireddata.jingleSipIp | string | null | Your SIP endpoint |
sipPortrequireddata.sipPort | integer | null | - |
techPrefixrequireddata.techPrefix | string | null | - |
sipAuthUsernamerequireddata.sipAuthUsername | string | null | - |
sipAuthPasswordSetrequireddata.sipAuthPasswordSet | boolean | A SIP digest password is stored (never returned) |
smsDeliveryMethoddata.smsDeliveryMethod | string | null | -One of http, smpp |
smsDeliveryUrlrequireddata.smsDeliveryUrl | string | null | - |
smppHostrequireddata.smppHost | string | null | - |
smppPortrequireddata.smppPort | integer | null | - |
smppSystemIdrequireddata.smppSystemId | string | null | - |
smppPasswordSetrequireddata.smppPasswordSet | boolean | An SMPP password is stored (never returned) |
endpointReachablerequireddata.endpointReachable | boolean | null | - |
endpointCheckedAtrequireddata.endpointCheckedAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
sellerProfiledata.sellerProfile | object | null | Trust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page. |
rateCountdata.rateCount | integer | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get marketplace totals for a filter
GET/
- Access
- Key optional. A key or token personalises the answer.
- Rate limit
- 100 requests per second (the default)
Same filters as the listing. Anonymous callers get counts only; price, ASR, score and capacity figures need a signed-in caller.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
type | query | string | -One of voice, sms |
country | query | string | - |
countryCode | query | string | - |
cliType | query | string | -One of full_cli, local_cli, mixed_cli, ncli, partial_cli |
routeType | query | string | -One of direct, premium, standard, ncli |
minPrice | query | string | - |
maxPrice | query | string | - |
minAsr | query | string | - |
minAcd | query | string | - |
maxPdd | query | string | - |
minScore | query | integer | - |
minCapacity | query | integer | - |
billing | query | string | -One of per_second, per_minute |
wholesale | query | string | -One of true, false |
callcenter | query | string | -One of true, false |
retail | query | string | -One of true, false |
otp | query | string | -One of true, false |
openRtp | query | string | -One of true, false |
dialer | query | string | -One of true, false |
a2p | query | string | -One of true, false |
bundlesOnly | query | string | -One of true, false |
search | query | string | - |
sort | query | string | -One of price_asc, price_desc, asr_desc, asr_asc, acd_desc, acd_asc, pdd_asc, pdd_desc, capacity_desc, created_desc, country_asc, score_desc, score_asc, measured_asr_desc, measured_asr_asc, measured_acd_desc, measured_acd_asc, ner_desc, ner_asc, quality_desc |
cursor | query | string (uuid) | - |
limit | query | integer | -Default 25 |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | Same fields as MarketplaceStats, shown earlier on this page. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Price a phone number across the marketplace
GET/
- Access
- Key optional. A key or token personalises the answer.
- Rate limit
- 30 requests per minute
Every buyer-visible route that serves the number, at the rate it would actually charge for it, cheapest first. A route with a rate sheet is priced by its longest matching active prefix (if that row is blocked the route does not serve the number); a single-price route serves it when a listed prefix, or failing that its country code, starts the number. This is the public list price: negotiated prices and private grants are not applied. SMS prices are by destination network on routes that price a country per mobile network: network says which network rate is for and countryRate is the price for other or unknown networks. The network is determined from the number's range (ported numbers may be priced at the network the range belongs to). The number is normalised to digits (a leading 00 is dropped). At most 100 routes are returned; total counts all of them. An embargoed destination returns no routes and notice: "sanctioned". Seller identities are never included.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
numberrequired | query | string | A full number or dial code, any formatting |
type | query | string | -One of voice, smsDefault "voice" |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
numberrequireddata.number | string | The number as priced: digits only |
typerequireddata.type | string | -One of voice, sms |
unitrequireddata.unit | string | What rate is per: a minute (voice) or a message (SMS)One of min, msg |
totalrequireddata.total | integer | Routes that serve the number, before the 100-row cap |
routesrequireddata.routes | object[] | Cheapest first |
idrequireddata.routes[].id | string (uuid) | - |
typerequireddata.routes[].type | string | -One of voice, sms |
namerequireddata.routes[].name | string | The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. "Niger Mobile · Ref 7K2Q", "A-Z Voice · Premium · Full CLI · Ref 3MX9"). Your own listings keep the name you gave them. |
listingRefdata.routes[].listingRef | string | Anonymous short reference of the listing (4 characters, e.g. "7K2Q"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings. |
countryrequireddata.routes[].country | string | - |
countryCoderequireddata.routes[].countryCode | string | E.164 country calling code, digits only |
matchedPrefixrequireddata.routes[].matchedPrefix | string | The dial prefix the number matched on this route (the longest one, on a deck) |
destinationrequireddata.routes[].destination | string | The destination that prefix belongs to, e.g. "United Kingdom-Mobile"; the country for a flat-priced listing |
raterequireddata.routes[].rate | money | What this route charges for THIS number: USD per minute (voice) or per message (SMS) USD as a decimal string with exactly 6 places, e.g. "0.012500". |
billingIncrementrequireddata.routes[].billingIncrement | string | null | e.g. "60/60" or "1/1"; null when the listing does not state one |
pricedByrequireddata.routes[].pricedBy | string | deck = priced by the matching rate-sheet row; flat = the listing's single priceOne of deck, flat |
expectedAsrrequireddata.routes[].expectedAsr | string | null | Seller-stated ASR %. The measured figure is in measured.asr |
expectedAcdrequireddata.routes[].expectedAcd | string | null | Seller-stated ACD in seconds |
cliTyperequireddata.routes[].cliType | string | - |
routeTyperequireddata.routes[].routeType | string | Quality tier |
capacityrequireddata.routes[].capacity | integer | Channels (voice) or messages per second (SMS) |
exchangeScorerequireddata.routes[].exchangeScore | integer | null | Exchange Score 1-100; null ("New") until the route has carried traffic |
measuredrequireddata.routes[].measured | object | null | Measured quality of the listing from real calls; null until it has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page. |
routeChecksrequireddata.routes[].routeChecks | object | null | Route checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page. |
isOwnrequireddata.routes[].isOwn | boolean | True only on your own listing (signed-in callers), so you are not offered your own route |
networkdata.routes[].network | object | null | SMS routes that price the country per mobile network: which network rate is for. Absent otherwise |
mccMncrequireddata.routes[].network.mccMnc | string | null | Mobile network code (MCC-MNC) rate is for, e.g. "234-10"; null when unknown |
operatorrequireddata.routes[].network.operator | string | null | Network name from public number-range data, e.g. "O2" |
sourcerequireddata.routes[].network.source | string | range = number-range data; none = not determinedOne of range, hlr, none |
rateBasisrequireddata.routes[].network.rateBasis | string | network = that network's own rate; all_operators = the route's rate for networks it does not list separately; country = the price for other or unknown networksOne of network, all_operators, country |
countryRatedata.routes[].countryRate | money | null | SMS routes that price per network: the price for other or unknown networks USD as a decimal string with exactly 6 places, e.g. "0.012500". |
noticerequireddata.notice | string | null | Why the list is empty when it is empty for a reason other than "no route covers it"One of sanctioned |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List destinations on the marketplace
GET/
- Access
- Public. No key needed.
- Rate limit
- 100 requests per second (the default)
Every country with at least one live public route, with its route count, A to Z.
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
countryrequireddata[].country | string | - |
countryCoderequireddata[].countryCode | string | - |
countrequireddata[].count | integer | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get a route
GET/
- Access
- Key optional. A key or token personalises the answer.
- Rate limit
- 100 requests per second (the default)
Public for live public routes. The seller gets the full owner view; a granted buyer sees a private route; any other signed-in caller gets an access stub for a private route. Carries measured (quality measured from real calls, or null) and routeChecks (the last 7 days of route checks, or null).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
iddata.id | string (uuid) | - |
kinddata.kind | string | -One of single, blend |
typedata.type | string | -One of voice, sms |
countrydata.country | string | - |
countryCodedata.countryCode | string | - |
prefixdata.prefix | string[] | Dial prefixes the route covers |
destinationNamedata.destinationName | string | The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: "<Country> <Operator?> <Mobile|Fixed|All Networks>" for one destination (e.g. "Niger Mobile", "Kenya Safaricom Mobile"), "A-Z Voice · <tier> · <CLI> · Ref XXXX" or "A-Z SMS · <quality> · Ref XXXX" for an A-Z bundle. The seller sees the name they gave it. |
cliTypedata.cliType | string | -One of full_cli, ncli, partial_cli, local_cli, mixed_cli |
routeTypedata.routeType | string | Quality tierOne of direct, premium, standard, ncli |
pricePerUnitdata.pricePerUnit | money | USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead. USD as a decimal string with exactly 6 places, e.g. "0.012500". |
billingIncrementdata.billingIncrement | string | null | First/subsequent increment in seconds, e.g. "60/60" |
capacitydata.capacity | integer | Channels (voice) or messages per second (SMS) |
expectedAsrdata.expectedAsr | string | null | Seller-stated ASR %. The measured figure is in measured.asr |
expectedAcddata.expectedAcd | string | null | Seller-stated ACD in seconds |
expectedPdddata.expectedPdd | string | null | Seller-stated PDD in seconds |
minAcddata.minAcd | integer | null | - |
minAsrdata.minAsr | string | null | Decimal as a string, e.g. "92.50" |
visibilitydata.visibility | string | -One of private |
statusdata.status | string | -One of active, paused, suspended, pending_review |
wholesaleCompatibledata.wholesaleCompatible | boolean | - |
callcenterCompatibledata.callcenterCompatible | boolean | - |
dialerCompatibledata.dialerCompatible | boolean | - |
retailCompatibledata.retailCompatible | boolean | - |
otpCompatibledata.otpCompatible | boolean | - |
notesdata.notes | string | null | - |
smsTypedata.smsType | string | null | -One of a2p, p2p, both |
exchangeScoredata.exchangeScore | integer | null | Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures |
lastQcAtdata.lastQcAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
measureddata.measured | object | null | Measured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page. |
routeChecksdata.routeChecks | object | null | Route checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page. |
createdAtdata.createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtdata.updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
isOwndata.isOwn | boolean | True only on your own listings |
listingRefdata.listingRef | string | Anonymous short reference of the listing (4 characters, e.g. "7K2Q"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings. |
sellerProfiledata.sellerProfile | object | null | Trust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page. |
rateCountdata.rateCount | integer | - |
priceTrenddata.priceTrend | object | null | Real 24h price movement from the price history; null when the route has not repriced |
changePctrequireddata.priceTrend.changePct | number | - |
pointsrequireddata.priceTrend.points | number[] | - |
sellerIddata.sellerId | string (uuid) | Your own account id |
isOwnerdata.isOwner | boolean | -One of true |
parentRouteIddata.parentRouteId | string (uuid) | null | - |
isBundledata.isBundle | boolean | - |
jingleSipIpdata.jingleSipIp | string | null | Your SIP endpoint |
sipPortdata.sipPort | integer | null | - |
techPrefixdata.techPrefix | string | null | - |
sipAuthUsernamedata.sipAuthUsername | string | null | - |
sipAuthPasswordSetdata.sipAuthPasswordSet | boolean | A SIP digest password is stored (never returned) |
smsDeliveryMethoddata.smsDeliveryMethod | string | null | -One of http, smpp |
smsDeliveryUrldata.smsDeliveryUrl | string | null | - |
smppHostdata.smppHost | string | null | - |
smppPortdata.smppPort | integer | null | - |
smppSystemIddata.smppSystemId | string | null | - |
smppPasswordSetdata.smppPasswordSet | boolean | An SMPP password is stored (never returned) |
endpointReachabledata.endpointReachable | boolean | null | - |
endpointCheckedAtdata.endpointCheckedAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
accessRequireddata.accessRequired | boolean | -One of true |
accessRequestPendingdata.accessRequestPending | boolean | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Update a route you listed
PUT/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
The price of an ACTIVE route cannot change in place (400 VALIDATION_ERROR): schedule the change with POST /routes/{id}/rate-changes/flat, or pause the route first. On a paused route a price increase pauses buyers who pay the list rate until they accept it (see POST /purchases/{id}/accept-rate).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Request body (application/json)
| Field | Type | Description |
|---|---|---|
type | string | -One of voice, sms |
country | string | -max 100 chars |
countryCode | string | - |
prefix | string[] | - |
destinationName | string | -max 255 chars |
pricePerUnit | string | - |
cliType | string | -One of full_cli, local_cli, mixed_cli, ncli, partial_cli |
capacity | integer | -0 to 1000000 |
expectedAsr | string | - |
expectedAcd | string | - |
expectedPdd | string | - |
minAsr | string | - |
minAcd | integer | -min 0 |
billingIncrement | string | - |
routeType | string | -One of direct, premium, standard, ncli |
wholesaleCompatible | boolean | -default true |
callcenterCompatible | boolean | -default true |
dialerCompatible | boolean | -default true |
retailCompatible | boolean | -default true |
otpCompatible | boolean | -default true |
openRtp | boolean | -default false |
visibility | string | -default "public"One of public, private |
jingleEnabled | boolean | -default false |
jingleApiUrl | string (uri) | null | - |
smsDeliveryUrl | string (uri) | null | - |
smsDeliveryMethod | string | -One of http, smpp |
smppHost | string | null | - |
smppPort | integer | null | -1 to 65535 |
smppSystemId | string | null | - |
smppPassword | string | null | -max 64 chars |
smppBindType | string | null | -One of transceiver, transmitter |
smppSystemType | string | null | -max 13 chars |
smppTps | integer | null | -1 to 1000 |
smppSourceTon | integer | null | -0 to 6 |
smppSourceNpi | integer | null | -0 to 18 |
smppDestTon | integer | null | -0 to 6 |
smppDestNpi | integer | null | -0 to 18 |
jingleSipIp | string | null | - |
sipPort | integer | null | -1 to 65535 |
sipAuthUsername | string | null | -max 128 chars |
sipAuthPassword | string | null | -max 128 chars |
techPrefix | string | null | - |
numberFormat | object | null | - |
modenumberFormat.mode | string | -One of custom |
nationalPrefixnumberFormat.nationalPrefix | string | - |
stripnumberFormat.strip | integer | -0 to 10 |
addnumberFormat.add | string | - |
t38Support | boolean | -default false |
supportedCodecs | string[] | - |
maxCallDuration | integer | -min 0 |
smsType | string | -One of a2p, p2p, both |
smsDlrSupport | boolean | - |
smsConcatSupport | boolean | - |
smsSenderIdType | string | -One of alphanumeric, numeric, preregistered |
smsContentRestrictions | string | - |
smsRouteQuality | string | null | -One of hq, direct, aggregator, sim |
smsSenderIdBehavior | string | null | -One of alphanumeric_preserved, numeric_long, overwritten, not_guaranteed |
smsDlrLevel | string | null | -One of real_operator, intermediate, submit_only, none |
smsDlrPercent | string | null | - |
smsUnicodeSupport | boolean | null | - |
smsAcceptedTraffic | string[] | null | -One of wholesale, transactional, otp, marketing, promo_shortcode |
timeOfDayPricing | object | - |
notes | string | -max 2000 chars |
status | string | -One of active, paused |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | A route you listed, as only you (the seller) see it. Passwords are never returned.Same fields as OwnRoute, shown earlier on this page. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Delete a route you listed
DELETE/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
Restorable for restoreWindowDays via POST /routes/{id}/restore.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
messagerequireddata.message | string | - |
restorablerequireddata.restorable | boolean | -One of true |
restoreWindowDaysrequireddata.restoreWindowDays | integer | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Draft a listing from a rate sheet
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 10 requests per minute
Upload a CSV or Excel sheet (multipart field file, optional note). Returns a proposed listing and the questions a sheet cannot answer. Writes nothing.
Request body (multipart/form-data)
| Field | Type | Description |
|---|---|---|
filerequired | string | CSV or Excel rate sheet (binary) |
note | string | -max 500 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | A proposed listing form plus open questions |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Test an endpoint before listing a route
POST/
- Access
- API key. Full-access keys only; not reachable by scoped keys.
- Rate limit
- 20 requests per minute
Sends a real SIP probe (voice), SMPP bind (SMS over SMPP) or URL check (SMS over HTTP) to the details you enter. Nothing is stored.
Request body (application/json)
| Field | Type | Description |
|---|---|---|
typerequired | string | -One of voice, sms |
jingleSipIp | string | null | -max 255 chars |
sipPort | integer | null | -1 to 65535 |
techPrefix | string | null | -max 24 chars |
smsDeliveryUrl | string | null | -max 2048 chars |
smsDeliveryMethod | string | null | -One of http, smpp |
smppHost | string | null | -max 255 chars |
smppPort | integer | null | -1 to 65535 |
smppSystemId | string | null | Short account code your SMS supplier issued (max 16 chars). An email address is rejected.max 16 chars |
smppPassword | string | null | Used for one bind attempt, never storedmax 64 chars |
smppBindType | string | null | -One of transceiver, transmitter |
smppSystemType | string | null | -max 13 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
passrequireddata.pass | boolean | True when the endpoint answered from every one of our media addresses |
barreddata.barred | boolean | Reachable but refusing our calls |
degradeddata.degraded | boolean | Refusing some of our source addresses |
checksrequireddata.checks | object[] | - |
labelrequireddata.checks[].label | string | - |
valuerequireddata.checks[].value | string | - |
okrequireddata.checks[].ok | boolean | - |
egressAddressesrequireddata.egressAddresses | string | The addresses our traffic comes from; whitelist these |
gatewayIprequireddata.gatewayIp | string | Deprecated alias of egressAddresses |
diagnosticsdata.diagnostics | object | - |
messagerequireddata.message | string | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List your call-centre routes and their call screening
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
routeIdrequireddata[].routeId | string (uuid) | - |
namerequireddata[].name | string | - |
countryrequireddata[].country | string | - |
enabledrequireddata[].enabled | boolean | - |
consentAtrequireddata[].consentAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
statusrequireddata[].status | string | -One of active, paused, suspended, pending_review |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get call screening settings, stats and flagged calls
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | Screening config, statistics and the flagged calls |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Turn call screening on or off for a route
PATCH/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
Only for call-centre voice routes. Turning it on records your recording consent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Request body (application/json)
| Field | Type | Description |
|---|---|---|
enabledrequired | boolean | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Classify a sample transcript with call screening
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 20 requests per minute
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Request body (application/json)
| Field | Type | Description |
|---|---|---|
transcriptrequired | string | -max 20000 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | The classification the transcript would receive |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List your saved listing presets
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
presetsrequireddata.presets | object[] | - |
namerequireddata.presets[].name | string | - |
valuesrequireddata.presets[].values | object | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Save a listing preset
PUT/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
Upserts by name; keeps your 12 most recent presets.
Request body (application/json)
| Field | Type | Description |
|---|---|---|
namerequired | string | -max 60 chars |
valuesrequired | object | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
presetsrequireddata.presets | object[] | - |
namerequireddata.presets[].name | string | - |
valuesrequireddata.presets[].values | object | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Delete a listing preset
DELETE/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
namerequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
presetsrequireddata.presets | object[] | - |
namerequireddata.presets[].name | string | - |
valuesrequireddata.presets[].values | object | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Preview the listings publishing a deck will create
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | Per-country listings that publishing would produce |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List your recently deleted routes
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
routesrequireddata.routes | object[] | - |
iddata.routes[].id | string (uuid) | - |
kinddata.routes[].kind | string | -One of single, blend |
typedata.routes[].type | string | -One of voice, sms |
countrydata.routes[].country | string | - |
countryCodedata.routes[].countryCode | string | E.164 country calling code, digits only |
prefixdata.routes[].prefix | string[] | Dial prefixes the route covers |
destinationNamedata.routes[].destinationName | string | The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: "<Country> <Operator?> <Mobile|Fixed|All Networks>" for one destination (e.g. "Niger Mobile", "Kenya Safaricom Mobile"), "A-Z Voice · <tier> · <CLI> · Ref XXXX" or "A-Z SMS · <quality> · Ref XXXX" for an A-Z bundle. The seller sees the name they gave it. |
cliTypedata.routes[].cliType | string | -One of full_cli, ncli, partial_cli, local_cli, mixed_cli |
routeTypedata.routes[].routeType | string | Quality tierOne of direct, premium, standard, ncli |
pricePerUnitdata.routes[].pricePerUnit | money | USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead. USD as a decimal string with exactly 6 places, e.g. "0.012500". |
billingIncrementdata.routes[].billingIncrement | string | null | First/subsequent increment in seconds, e.g. "60/60" |
capacitydata.routes[].capacity | integer | Channels (voice) or messages per second (SMS) |
expectedAsrdata.routes[].expectedAsr | string | null | Seller-stated ASR %. The measured figure is in measured.asr |
expectedAcddata.routes[].expectedAcd | string | null | Seller-stated ACD in seconds |
expectedPdddata.routes[].expectedPdd | string | null | Seller-stated PDD in seconds |
minAcddata.routes[].minAcd | integer | null | - |
minAsrdata.routes[].minAsr | string | null | Decimal as a string, e.g. "92.50" |
visibilitydata.routes[].visibility | string | -One of public, private |
statusdata.routes[].status | string | -One of active, paused, suspended, pending_review |
wholesaleCompatibledata.routes[].wholesaleCompatible | boolean | - |
callcenterCompatibledata.routes[].callcenterCompatible | boolean | - |
dialerCompatibledata.routes[].dialerCompatible | boolean | - |
retailCompatibledata.routes[].retailCompatible | boolean | - |
otpCompatibledata.routes[].otpCompatible | boolean | - |
notesdata.routes[].notes | string | null | - |
smsTypedata.routes[].smsType | string | null | -One of a2p, p2p, both |
exchangeScoredata.routes[].exchangeScore | integer | null | Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures |
lastQcAtdata.routes[].lastQcAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
measureddata.routes[].measured | object | null | Measured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page. |
routeChecksdata.routes[].routeChecks | object | null | Route checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page. |
createdAtdata.routes[].createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtdata.routes[].updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
sellerIddata.routes[].sellerId | string (uuid) | Your own account id |
isOwnerdata.routes[].isOwner | boolean | -One of true |
parentRouteIddata.routes[].parentRouteId | string (uuid) | null | - |
isBundledata.routes[].isBundle | boolean | - |
jingleSipIpdata.routes[].jingleSipIp | string | null | Your SIP endpoint |
sipPortdata.routes[].sipPort | integer | null | - |
techPrefixdata.routes[].techPrefix | string | null | - |
sipAuthUsernamedata.routes[].sipAuthUsername | string | null | - |
sipAuthPasswordSetdata.routes[].sipAuthPasswordSet | boolean | A SIP digest password is stored (never returned) |
smsDeliveryMethoddata.routes[].smsDeliveryMethod | string | null | -One of http, smpp |
smsDeliveryUrldata.routes[].smsDeliveryUrl | string | null | - |
smppHostdata.routes[].smppHost | string | null | - |
smppPortdata.routes[].smppPort | integer | null | - |
smppSystemIddata.routes[].smppSystemId | string | null | - |
smppPasswordSetdata.routes[].smppPasswordSet | boolean | An SMPP password is stored (never returned) |
endpointReachabledata.routes[].endpointReachable | boolean | null | - |
endpointCheckedAtdata.routes[].endpointCheckedAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
sellerProfiledata.routes[].sellerProfile | object | null | Trust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page. |
rateCountdata.routes[].rateCount | integer | - |
restoreWindowDaysrequireddata.restoreWindowDays | integer | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Restore a deleted route
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
The route comes back paused and private; publish it again when ready.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
messagerequireddata.message | string | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List your saved SIP endpoints
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
iddata[].id | string (uuid) | null | - |
iprequireddata[].ip | string | - |
labeldata[].label | string | null | - |
routeCountdata[].routeCount | integer | How many of your routes use this IP |
usedBydata[].usedBy | string | null | Name of the newest route using this IP |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Save a SIP endpoint
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
Request body (application/json)
| Field | Type | Description |
|---|---|---|
iprequired | string | - |
label | string | null | -max 60 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
iddata.id | string (uuid) | null | - |
iprequireddata.ip | string | - |
labeldata.label | string | null | - |
routeCountdata.routeCount | integer | How many of your routes use this IP |
usedBydata.usedBy | string | null | Name of the newest route using this IP |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Label a saved SIP endpoint
PATCH/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 60 requests per minute
Sets the label shown next to the IP in "My IPs" and in the SIP endpoint pickers, so a seller with several switches can tell them apart. The label is trimmed, control and bidirectional-override characters are removed, and it is cut to 60 characters; an empty string or null clears it. Only saved endpoints (those with an id in GET /routes/my-endpoints) can be labelled; an unknown id, or someone else's, answers 404.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | - |
Request body (application/json)
| Field | Type | Description |
|---|---|---|
labelrequired | string | null | The new label; "" or null clears itmax 60 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
idrequireddata.id | string (uuid) | - |
iprequireddata.ip | string | - |
labelrequireddata.label | string | null | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Remove a saved SIP endpoint
DELETE/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Preview which route would carry a destination
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Resolves as your account (including private routes you bought). price is a 6-decimal USD string.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
torequired | query | string | Destination number or prefix |
type | query | string | -One of voice, smsDefault "voice" |
strategy | query | string | -One of cheapest, best_quality, balancedDefault "balanced" |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
strategyrequireddata.strategy | string | -One of cheapest, best_quality, balanced |
selectedrequireddata.selected | object | null | - |
idrequireddata.selected.id | string (uuid) | - |
destinationNamerequireddata.selected.destinationName | string | The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. "Niger Mobile · Ref 7K2Q", "A-Z Voice · Premium · Full CLI · Ref 3MX9"). Your own listings keep the name you gave them. |
countryrequireddata.selected.country | string | - |
countryCoderequireddata.selected.countryCode | string | - |
typerequireddata.selected.type | string | -One of voice, sms |
cliTyperequireddata.selected.cliType | string | null | - |
pricerequireddata.selected.price | money | Rate for this destination: USD per minute or message, 6-decimal string USD as a decimal string with exactly 6 places, e.g. "0.012500". |
asrrequireddata.selected.asr | number | null | - |
acdrequireddata.selected.acd | number | null | - |
matchedPrefixrequireddata.selected.matchedPrefix | string | null | - |
alternativesrequireddata.alternatives | object[] | Same fields as ResolvedRoute, shown earlier on this page. |
countrequireddata.count | integer | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Test connectivity to your route endpoint
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 100 requests per second (the default)
- Real traffic
- Places a real test call over the route.
Sends a real SIP probe to the route endpoint from every one of our media addresses.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | Same fields as ConnectivityTestResult, shown earlier on this page. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Capture a SIP trace of a test call on a route
POST/
- Access
- API key. Full-access keys only; not reachable by scoped keys.
- Rate limit
- 10 requests per minute
- Real traffic
- Places a real test call over the route.
For the seller or an active buyer. Optionally dials a real number. Buyers receive the trace with seller addresses masked.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Request body (application/json)
| Field | Type | Description |
|---|---|---|
number | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | The SIP ladder: messages, timings and the final response |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get a route's price history
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
For the seller and buyers of the route. Newest first.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
idrequireddata[].id | string (uuid) | - |
routeIdrequireddata[].routeId | string (uuid) | - |
oldPricerequireddata[].oldPrice | money | null | US dollars as a decimal string with exactly 6 decimal places, e.g. "0.012500". Do money arithmetic with a decimal type, not floating point. USD as a decimal string with exactly 6 places, e.g. "0.012500". |
newPricerequireddata[].newPrice | money | USD as a decimal string with exactly 6 places, e.g. "0.012500". |
changedAtrequireddata[].changedAt | string (date-time) | ISO-8601 timestamp (UTC) |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get traffic and revenue stats for your route
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
activePurchasesrequireddata.activePurchases | integer | - |
volumerequireddata.volume | object | Keyed 24h, 7d, 30d. revenue is USD (display figure, 2 decimals) |
measuredAsrrequireddata.measuredAsr | number | null | - |
measuredAcdrequireddata.measuredAcd | number | null | - |
recentOffersrequireddata.recentOffers | object[] | - |
idrequireddata.recentOffers[].id | string (uuid) | - |
proposedPricerequireddata.recentOffers[].proposedPrice | money | USD as a decimal string with exactly 6 places, e.g. "0.012500". |
agreedPricerequireddata.recentOffers[].agreedPrice | money | null | US dollars as a decimal string with exactly 6 decimal places, e.g. "0.012500". Do money arithmetic with a decimal type, not floating point. USD as a decimal string with exactly 6 places, e.g. "0.012500". |
statusrequireddata.recentOffers[].status | string | - |
lastActorrequireddata.recentOffers[].lastActor | string | - |
createdAtrequireddata.recentOffers[].createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtrequireddata.recentOffers[].updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List the routes you sell
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Two modes. Cursor mode (only cursor, limit, includeChildren): newest first, A-Z deck children hidden unless includeChildren=true. Paged mode (any of offset, search, type, status, visibility, live, hiddenReason, scope, endpoint, deck, sort, dir): up to 200 rows a page, with total, and each row carries origin (its endpoint, your label for it, and the deck and rate sheet it came from). scope=listings lists every row a buyer could see as a listing (single routes and deck children); hiddenReason lists exactly the routes counted under that reason by GET /routes/my/listing-health. search matches the route name, country, endpoint IP or host, your IP label, the deck name and a route id prefix; a number such as +44 is a dial code (country code or coverage prefix). endpoint and deck take a group key from GET /routes/my/groups.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
cursor | query | string (uuid) | - |
limit | query | integer | Cursor mode: default 25, max 100. Paged mode: default 50, max 200. |
includeChildren | query | string | Include the per-country children of A-Z decksOne of true, false, 1, 0 |
search | query | string | - |
type | query | string | -One of voice, sms |
status | query | string | -One of active, paused, pending_review, suspended |
visibility | query | string | -One of public, private |
live | query | boolean | string | - |
hiddenReason | query | string | -One of sms_no_delivery, voice_no_endpoint |
scope | query | string | -One of listings, decks |
endpoint | query | string | - |
deck | query | string (uuid) | string | - |
offset | query | integer | - |
sort | query | string | -One of created, name, country, type, price, status |
dir | query | string | -One of asc, desc |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
idrequireddata[].id | string (uuid) | - |
kindrequireddata[].kind | string | -One of single, blend |
typerequireddata[].type | string | -One of voice, sms |
countryrequireddata[].country | string | - |
countryCoderequireddata[].countryCode | string | E.164 country calling code, digits only |
prefixrequireddata[].prefix | string[] | Dial prefixes the route covers |
destinationNamerequireddata[].destinationName | string | The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: "<Country> <Operator?> <Mobile|Fixed|All Networks>" for one destination (e.g. "Niger Mobile", "Kenya Safaricom Mobile"), "A-Z Voice · <tier> · <CLI> · Ref XXXX" or "A-Z SMS · <quality> · Ref XXXX" for an A-Z bundle. The seller sees the name they gave it. |
cliTyperequireddata[].cliType | string | -One of full_cli, ncli, partial_cli, local_cli, mixed_cli |
routeTyperequireddata[].routeType | string | Quality tierOne of direct, premium, standard, ncli |
pricePerUnitrequireddata[].pricePerUnit | money | USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead. USD as a decimal string with exactly 6 places, e.g. "0.012500". |
billingIncrementrequireddata[].billingIncrement | string | null | First/subsequent increment in seconds, e.g. "60/60" |
capacityrequireddata[].capacity | integer | Channels (voice) or messages per second (SMS) |
expectedAsrrequireddata[].expectedAsr | string | null | Seller-stated ASR %. The measured figure is in measured.asr |
expectedAcdrequireddata[].expectedAcd | string | null | Seller-stated ACD in seconds |
expectedPddrequireddata[].expectedPdd | string | null | Seller-stated PDD in seconds |
minAcdrequireddata[].minAcd | integer | null | - |
minAsrrequireddata[].minAsr | string | null | Decimal as a string, e.g. "92.50" |
visibilityrequireddata[].visibility | string | -One of public, private |
statusrequireddata[].status | string | -One of active, paused, suspended, pending_review |
wholesaleCompatiblerequireddata[].wholesaleCompatible | boolean | - |
callcenterCompatiblerequireddata[].callcenterCompatible | boolean | - |
dialerCompatiblerequireddata[].dialerCompatible | boolean | - |
retailCompatiblerequireddata[].retailCompatible | boolean | - |
otpCompatiblerequireddata[].otpCompatible | boolean | - |
notesrequireddata[].notes | string | null | - |
smsTypedata[].smsType | string | null | -One of a2p, p2p, both |
exchangeScorerequireddata[].exchangeScore | integer | null | Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures |
lastQcAtrequireddata[].lastQcAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
measureddata[].measured | object | null | Measured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page. |
routeChecksdata[].routeChecks | object | null | Route checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page. |
createdAtrequireddata[].createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtrequireddata[].updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
sellerIdrequireddata[].sellerId | string (uuid) | Your own account id |
isOwnerdata[].isOwner | boolean | -One of true |
parentRouteIdrequireddata[].parentRouteId | string (uuid) | null | - |
isBundlerequireddata[].isBundle | boolean | - |
jingleSipIprequireddata[].jingleSipIp | string | null | Your SIP endpoint |
sipPortrequireddata[].sipPort | integer | null | - |
techPrefixrequireddata[].techPrefix | string | null | - |
sipAuthUsernamerequireddata[].sipAuthUsername | string | null | - |
sipAuthPasswordSetrequireddata[].sipAuthPasswordSet | boolean | A SIP digest password is stored (never returned) |
smsDeliveryMethoddata[].smsDeliveryMethod | string | null | -One of http, smpp |
smsDeliveryUrlrequireddata[].smsDeliveryUrl | string | null | - |
smppHostrequireddata[].smppHost | string | null | - |
smppPortrequireddata[].smppPort | integer | null | - |
smppSystemIdrequireddata[].smppSystemId | string | null | - |
smppPasswordSetrequireddata[].smppPasswordSet | boolean | An SMPP password is stored (never returned) |
endpointReachablerequireddata[].endpointReachable | boolean | null | - |
endpointCheckedAtrequireddata[].endpointCheckedAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
sellerProfiledata[].sellerProfile | object | null | Trust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page. |
rateCountdata[].rateCount | integer | - |
revenue30drequireddata[].revenue30d | number | USD seller credit over 30 days (display figure, 2 decimals) |
liveChannelsrequireddata[].liveChannels | integer | - |
childCountrequireddata[].childCount | integer | Per-country child listings created from this deck |
origindata[].origin | object | Paged mode only: where the route terminates and where it came from |
endpointKeyrequireddata[].origin.endpointKey | string | The endpoint group key: the host, "~none" (no endpoint) or "~blend". Pass it as ?endpoint= to list every route on it |
kindrequireddata[].origin.kind | string | sip = voice SIP endpoint, smpp = SMSC bind, http = delivery URL, blend = terminates via its members, none = no endpoint yetOne of sip, smpp, http, blend, none |
hostrequireddata[].origin.host | string | null | The SIP IP, the SMSC host, or the delivery URL's host |
portrequireddata[].origin.port | integer | null | SIP port (default 5060) or SMPP port (default 2775) |
systemIdrequireddata[].origin.systemId | string | null | SMPP only: the System ID bound with |
labelrequireddata[].origin.label | string | null | Your own label for this IP (see GET /routes/my-endpoints), voice only |
deckIdrequireddata[].origin.deckId | string (uuid) | null | The A-Z deck this route was split out of, when it was |
deckNamerequireddata[].origin.deckName | string | null | - |
sheetNamerequireddata[].origin.sheetName | string | null | File name of the latest applied rate sheet behind the deck (or behind the route itself) |
nextCursorrequired | string | null | Cursor mode only; always null in paged mode |
hasMorerequired | boolean | - |
total | integer | Paged mode only: rows matching the filters across all pages |
offset | integer | Paged mode only |
limit | integer | Paged mode only (max 200) |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Count your SMS routes hidden for lack of an endpoint
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
countrequireddata.count | integer | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Set one delivery endpoint on all your endpoint-less SMS routes
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 6 requests per minute
An SMPP method runs a real bind first; if it fails nothing changes and error.details carries the reason and the addresses to whitelist.
Request body (application/json)
| Field | Type | Description |
|---|---|---|
methodrequired | string | -One of http, smpp |
smsDeliveryUrl | string | - |
smppHost | string | - |
smppPort | integer | - |
smppSystemId | string | - |
smppPassword | string | - |
smppBindType | string | -One of transceiver, transmitter |
smppSystemType | string | - |
routeIds | string (uuid)[] | Narrow to these routes; never widens the set |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
updatedrequireddata.updated | integer | - |
methodrequireddata.method | string | -One of http, smpp |
binddata.bind | string | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Count your listed routes that are live, and why the rest are hidden
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Answers "why does my route count differ from the marketplace?". listed counts your active, public routes (A-Z deck parents excluded); live counts the ones buyers can see, using the marketplace's own filters, so the two numbers cannot disagree with the board. Each reason carries a count, a label and the fix. The routes behind sms_no_delivery and voice_no_endpoint can be listed with GET /routes/my/list?hiddenReason=<key> and fixed in one call with POST /routes/my/bulk-sms-delivery or /routes/my/bulk-sip-endpoint.
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
listedrequireddata.listed | integer | Your routes that are active, public and not an A-Z deck parent: what you have put on sale |
liverequireddata.live | integer | How many of those buyers can actually see on the marketplace (counted with the marketplace's own filters) |
hiddenrequireddata.hidden | integer | listed - live |
reasonsrequireddata.reasons | object[] | Why the hidden routes are hidden, in the order to fix them. Only reasons with a non-zero count are present. |
keyrequireddata.reasons[].key | string | sms_no_delivery and voice_no_endpoint can be listed with GET /routes/my/list?hiddenReason=<key> and fixed in bulk; restricted = a destination the exchange does not carryOne of sms_no_delivery, voice_no_endpoint, restricted |
countrequireddata.reasons[].count | integer | - |
labelrequireddata.reasons[].label | string | The reason in plain words |
fixrequireddata.reasons[].fix | string | What to do about it |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Set one SMS delivery method on many of your SMS routes
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 10 requests per minute
Applies one delivery method (SMPP or HTTP) to a selection of your SMS routes: an explicit routeIds list, or every route matching filter (at most 5,000). Only your own live routes are touched; each route that is not eligible is returned in skipped with a reason. Send dryRun: true first to see how many would change: nothing is probed or written. On a real run the endpoint is checked ONCE for the whole batch: SMPP gets a real bind (no message is sent) and HTTP gets a URL check. If the bind is refused NO route is changed and the call answers 400 VALIDATION_ERROR with error.details = { kind: "smpp_bind_failed", host, port, systemId, bindType, reason, whitelistIps, failoverIps }: whitelistIps is the one SMS source address your SMSC must allow (every bind and message leaves from it); failoverIps are used only while that address is down, so allowing them is optional. A field that fails validation answers 400 with one { path, message } per field. All routes change in one transaction.
Request body (application/json)
| Field | Type | Description |
|---|---|---|
routeIds | string (uuid)[] | An explicit selection of your route ids (max 5000). Send this OR filter, not both. |
filter | object | "Every route matching this filter", re-derived on the server with the same rules as GET /routes/my/list (scope defaults to listings). Refused when it matches more than 5,000 routes. |
searchfilter.search | string | -max 100 chars |
typefilter.type | string | -One of voice, sms |
statusfilter.status | string | -One of active, paused, pending_review, suspended |
visibilityfilter.visibility | string | -One of public, private |
livefilter.live | boolean | string | - |
hiddenReasonfilter.hiddenReason | string | -One of sms_no_delivery, voice_no_endpoint |
scopefilter.scope | string | -One of listings, decks |
endpointfilter.endpoint | string | -max 255 chars |
deckfilter.deck | string (uuid) | string | - |
dryRun | boolean | Count and classify only: nothing is probed or written, and the answer carries wouldUpdate |
deliveryrequired | object | The SMS delivery method to set, validated exactly as PUT /routes/{id} validates it. It must be complete: smsDeliveryMethod "smpp" needs smppHost and smppSystemId; "http" needs smsDeliveryUrl. A blank smppPassword keeps each route's stored one; null clears it. |
smsDeliveryMethoddelivery.smsDeliveryMethod | string | -One of http, smpp |
smsDeliveryUrldelivery.smsDeliveryUrl | string (uri) | null | - |
smppHostdelivery.smppHost | string | null | - |
smppPortdelivery.smppPort | integer | null | -1 to 65535 |
smppSystemIddelivery.smppSystemId | string | null | - |
smppPassworddelivery.smppPassword | string | null | -max 64 chars |
smppBindTypedelivery.smppBindType | string | null | -One of transceiver, transmitter |
smppSystemTypedelivery.smppSystemType | string | null | -max 13 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
updatedrequireddata.updated | integer | Routes changed. Always 0 on a dry run. |
wouldUpdatedata.wouldUpdate | integer | Dry run (or nothing eligible): how many routes the call would change |
skippedrequireddata.skipped | object[] | Routes left untouched, each with the reason |
idrequireddata.skipped[].id | string (uuid) | - |
reasonrequireddata.skipped[].reason | string | not_found: not one of your live routes. not_sms / not_voice: wrong route type for this action. deck_parent: set it on the deck's own Edit page. blend: a blend has no endpoint of its own. duplicate_listing (SIP only): another of your routes already lists this country and prefixes on that IP and tech prefix.One of not_found, not_sms, not_voice, deck_parent, blend, duplicate_listing |
checkdata.check | object | The one endpoint check run for the whole batch (an SMPP bind, a URL check or a SIP probe). pass is false only when confirmUnreachable applied a SIP endpoint anyway. |
passrequireddata.check.pass | boolean | - |
messagerequireddata.check.message | string | - |
dryRundata.dryRun | boolean | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Set one SIP endpoint on many of your voice routes
POST/
- Access
- API key. Scoped keys need
routes:write. - Rate limit
- 10 requests per minute
Applies one SIP endpoint (IP or host, port, technical prefix and optional digest credentials) to a selection of your voice routes: an explicit routeIds list, or every route matching filter (at most 5,000). Only your own live routes are touched; routes that are not eligible, or that would duplicate another of your listings on the same IP and tech prefix (same country and prefixes), are returned in skipped. Send dryRun: true first to see how many would change. An invalid, private or reserved address, or one of our own addresses, is refused outright (400, on jingleSipIp). Otherwise one SIP probe is sent to the endpoint; if it gets no answer the call answers 400 VALIDATION_ERROR with error.details = { kind: "sip_probe_failed", message, checks } and nothing changes. Repeat with confirmUnreachable: true to apply anyway (a single-route edit never probes, so bulk is never stricter). The IP is also added to your saved endpoints. All routes change in one transaction.
Request body (application/json)
| Field | Type | Description |
|---|---|---|
routeIds | string (uuid)[] | An explicit selection of your route ids (max 5000). Send this OR filter, not both. |
filter | object | "Every route matching this filter", re-derived on the server with the same rules as GET /routes/my/list (scope defaults to listings). Refused when it matches more than 5,000 routes. |
searchfilter.search | string | -max 100 chars |
typefilter.type | string | -One of voice, sms |
statusfilter.status | string | -One of active, paused, pending_review, suspended |
visibilityfilter.visibility | string | -One of public, private |
livefilter.live | boolean | string | - |
hiddenReasonfilter.hiddenReason | string | -One of sms_no_delivery, voice_no_endpoint |
scopefilter.scope | string | -One of listings, decks |
endpointfilter.endpoint | string | -max 255 chars |
deckfilter.deck | string (uuid) | string | - |
dryRun | boolean | Count and classify only: nothing is probed or written, and the answer carries wouldUpdate |
deliveryrequired | object | The SIP endpoint to set, validated exactly as PUT /routes/{id} validates it. jingleSipIp is required. A blank sipAuthPassword keeps each route's stored one; null clears it. |
jingleSipIpdelivery.jingleSipIp | string | null | - |
sipPortdelivery.sipPort | integer | null | -1 to 65535 |
techPrefixdelivery.techPrefix | string | null | - |
sipAuthUsernamedelivery.sipAuthUsername | string | null | -max 128 chars |
sipAuthPassworddelivery.sipAuthPassword | string | null | -max 128 chars |
confirmUnreachable | boolean | Apply even though the SIP probe got no answer (the first attempt is refused with the probe's diagnosis in error.details) |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | Same fields as BulkEndpointResult, shown earlier on this page. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Group the routes you sell by endpoint or by A-Z deck
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Your routes matching the same filters as GET /routes/my/list (paged mode), grouped by by=endpoint (the SIP IP, SMSC host or delivery URL host, with your label for the IP) or by=deck (the A-Z deck a route was split out of, with the rate sheet behind it). Each group has total, live and hidden counts. List a group's routes with GET /routes/my/list?endpoint=<key> or ?deck=<key>; the bulk actions accept the same keys in filter. Only your own routes are counted.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
search | query | string | - |
type | query | string | -One of voice, sms |
status | query | string | -One of active, paused, pending_review, suspended |
visibility | query | string | -One of public, private |
live | query | boolean | string | - |
hiddenReason | query | string | -One of sms_no_delivery, voice_no_endpoint |
scope | query | string | -One of listings, decks |
endpoint | query | string | - |
deck | query | string (uuid) | string | - |
byrequired | query | string | -One of endpoint, deck |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
byrequireddata.by | string | -One of endpoint, deck |
groupsrequireddata.groups | object[] | Largest group first, at most 500 |
keyrequireddata.groups[].key | string | Pass back as ?endpoint= (by=endpoint) or ?deck= (by=deck) on GET /routes/my/list to page this group's routes. Sentinels: "~none", "~blend", "~single" |
kindrequireddata.groups[].kind | string | by=endpoint: how routes on this host are handed over (mixed when a host serves more than one kind). by=deck: deck, or single for routes listed on their ownOne of sip, smpp, http, mixed, blend, none, deck, single |
hostrequireddata.groups[].host | string | null | - |
labelrequireddata.groups[].label | string | null | Your label for this IP |
portrequireddata.groups[].port | integer | null | The port when every route in the group uses the same one |
systemIdrequireddata.groups[].systemId | string | null | SMPP: the System ID when every route in the group uses the same one |
deckIdrequireddata.groups[].deckId | string (uuid) | null | - |
deckNamerequireddata.groups[].deckName | string | null | - |
sheetNamerequireddata.groups[].sheetName | string | null | File name of the deck's latest applied rate sheet |
totalrequireddata.groups[].total | integer | - |
liverequireddata.groups[].live | integer | Visible to buyers, by the marketplace's own filters |
hiddenrequireddata.groups[].hidden | integer | total - live |
totalrequireddata.total | integer | Routes across the returned groups |
truncatedrequireddata.truncated | boolean | More than 500 groups matched; narrow the filter |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Check whether your switches are refusing our calls
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
One entry per SIP endpoint (IP or host) used by your active voice routes. refusing is true when we have evidence your switch is turning our calls away: calls we sent it in the last 6 hours answered with SIP 401, 403 or 407 (at least 3 of them, and at least half of the calls that got an answer), or our own test call to it was barred or refused from some of our addresses (partial, with the refused addresses in refusedIps when known). evidence is that finding in one sentence, routeId is a route on the endpoint you can test from, and since is when the current incident was first seen. allow lists the addresses to allow on your switch: every one of egressIps, for SIP on sipPort (UDP and TCP) and RTP media on the UDP rtpPortRange, the same values GET /sip/network-info publishes. Only your own endpoints and your own calls are counted.
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
endpointsrequireddata.endpoints | object[] | - |
endpointKeyrequireddata.endpoints[].endpointKey | string | - |
hostrequireddata.endpoints[].host | string | - |
endpointrequireddata.endpoints[].endpoint | string | - |
kindrequireddata.endpoints[].kind | string | -One of voice |
routeCountrequireddata.endpoints[].routeCount | integer | - |
routeIdrequireddata.endpoints[].routeId | string (uuid) | - |
refusingrequireddata.endpoints[].refusing | boolean | - |
partialrequireddata.endpoints[].partial | boolean | - |
refusedIpsrequireddata.endpoints[].refusedIps | string[] | - |
evidencerequireddata.endpoints[].evidence | string | null | - |
sourcerequireddata.endpoints[].source | string | null | -One of traffic, probe |
sincerequireddata.endpoints[].since | string (date-time) | null | ISO-8601 timestamp (UTC) |
allowrequireddata.allow | object | - |
egressIpsrequireddata.allow.egressIps | string[] | - |
sipPortrequireddata.allow.sipPort | integer | - |
rtpPortRangerequireddata.allow.rtpPortRange | string | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List the buyers of your route
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Owner only: anyone other than the route's seller gets 403 FORBIDDEN. One row per buyer, identified only by a pseudonym scoped to this route (the same "Buyer #3F2A" that appears on offers for the route), so it cannot be matched to an account or across your other routes. No account id, name, company, email, IP or dialled number is returned. Figures cover the last 30 days; for an A-Z deck they include its per-country listings. status is the buyer's current relationship (ended = cancelled; ended buyers with no traffic in the window are left out). asr30d and calls30d are voice only, counted per call attempt group, and null until a call has been measured. Sorted by revenue.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
windowDaysrequireddata.windowDays | integer | - |
unitrequireddata.unit | string | -One of minutes, messages |
buyersrequireddata.buyers | object[] | - |
buyerrequireddata.buyers[].buyer | string | Pseudonym, stable per route |
statusrequireddata.buyers[].status | string | -One of active, paused, pending_review, ended |
volume30drequireddata.buyers[].volume30d | number | - |
revenue30drequireddata.buyers[].revenue30d | number | USD (display figure, 2 decimals) |
asr30drequireddata.buyers[].asr30d | number | null | - |
calls30drequireddata.buyers[].calls30d | integer | null | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Show the billing increments your rate sheet sets
GET/
- Access
- API key. Scoped keys need
routes:read. - Rate limit
- 100 requests per second (the default)
Owner only: anyone other than the route's seller gets 403 FORBIDDEN. Groups the route's active rate rows by billing increment (e.g. 1/1 on some destinations, 60/60 on others). Rows with a null increment inherit fallback, the route-level increment.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
mixrequireddata.mix | object[] | - |
incrementrequireddata.mix[].increment | string | null | e.g. "60/60"; null = the row uses the route fallback |
destinationsrequireddata.mix[].destinations | integer | Active rate rows with this increment |
fallbackrequireddata.fallback | string | null | The route-level billing increment |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Read a rate sheet into a draft listing (no account needed)
POST/
- Access
- Public. No key needed.
- Rate limit
- 6 requests per minute
Multipart upload (field file, optional note). Returns the proposed listing and parsed rates; stores nothing.
Request body (multipart/form-data)
| Field | Type | Description |
|---|---|---|
filerequired | string | CSV or Excel rate sheet (binary) |
note | string | -max 500 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | Proposed listing, parsed rates and truncated |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Save a draft listing to claim after sign-up
POST/
- Access
- Public. No key needed.
- Rate limit
- 10 requests per 10 minutes
Returns a token; the listing is created only when a signed-in account claims it.
Request body (application/json)
| Field | Type | Description |
|---|---|---|
payload | any | - |
rates | object[] | - |
destinationNamerates[].destinationName | string | - |
operatorrates[].operator | string | null | - |
prefixrequiredrates[].prefix | string | - |
ratePerUnitrequiredrates[].ratePerUnit | string | - |
billingIncrementrates[].billingIncrement | string | null | - |
minDurationrates[].minDuration | number | null | - |
sourceFilename | string | -max 512 chars |
contactEmail | string (email) | -max 255 chars |
contactCompany | string | -max 255 chars |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
tokenrequireddata.token | string | - |
expiresAtrequireddata.expiresAt | string (date-time) | ISO-8601 timestamp (UTC) |
rateCountrequireddata.rateCount | integer | - |
destinationNamerequireddata.destinationName | string | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Look at a saved draft listing
GET/
- Access
- Public. No key needed.
- Rate limit
- 30 requests per minute
Parameters
| Name | In | Type | Description |
|---|---|---|---|
tokenrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
alreadyClaimedrequireddata.alreadyClaimed | boolean | - |
routeIddata.routeId | string (uuid) | null | - |
destinationNamedata.destinationName | string | - |
typedata.type | string | -One of voice, sms |
countrydata.country | string | - |
rateCountdata.rateCount | integer | - |
sourceFilenamedata.sourceFilename | string | null | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Create a route from a saved draft listing
POST/
- Access
- API key. Full-access keys only; not reachable by scoped keys.
- Rate limit
- 20 requests per minute
Idempotent per token: claiming twice returns the route already created.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
tokenrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
routeIdrequireddata.routeId | string (uuid) | null | - |
rateCountrequireddata.rateCount | integer | - |
alreadyClaimedrequireddata.alreadyClaimed | boolean | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.