Skip to content
Markets open

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/api/v1/routes

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

NameInTypeDescription
typequerystring-One of voice, sms
countryquerystring-
countryCodequerystring-
cliTypequerystring-One of full_cli, local_cli, mixed_cli, ncli, partial_cli
routeTypequerystring-One of direct, premium, standard, ncli
minPricequerystring-
maxPricequerystring-
minAsrquerystring-
minAcdquerystring-
maxPddquerystring-
minScorequeryinteger-
minCapacityqueryinteger-
billingquerystring-One of per_second, per_minute
wholesalequerystring-One of true, false
callcenterquerystring-One of true, false
retailquerystring-One of true, false
otpquerystring-One of true, false
openRtpquerystring-One of true, false
dialerquerystring-One of true, false
a2pquerystring-One of true, false
bundlesOnlyquerystring-One of true, false
searchquerystring-
sortquerystring-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
cursorquerystring (uuid)-
limitqueryinteger-Default 25

Response 200

FieldTypeDescription
datarequiredobject[]-
idrequireddata[].idstring (uuid)-
kindrequireddata[].kindstring-One of single, blend
typerequireddata[].typestring-One of voice, sms
countryrequireddata[].countrystring-
countryCoderequireddata[].countryCodestringE.164 country calling code, digits only
prefixrequireddata[].prefixstring[]Dial prefixes the route covers
destinationNamerequireddata[].destinationNamestringThe 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[].cliTypestring-One of full_cli, ncli, partial_cli, local_cli, mixed_cli
routeTyperequireddata[].routeTypestringQuality tierOne of direct, premium, standard, ncli
pricePerUnitrequireddata[].pricePerUnitmoneyUSD 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[].billingIncrementstring | nullFirst/subsequent increment in seconds, e.g. "60/60"
capacityrequireddata[].capacityintegerChannels (voice) or messages per second (SMS)
expectedAsrrequireddata[].expectedAsrstring | nullSeller-stated ASR %. The measured figure is in measured.asr
expectedAcdrequireddata[].expectedAcdstring | nullSeller-stated ACD in seconds
expectedPddrequireddata[].expectedPddstring | nullSeller-stated PDD in seconds
minAcdrequireddata[].minAcdinteger | null-
minAsrrequireddata[].minAsrstring | nullDecimal as a string, e.g. "92.50"
visibilityrequireddata[].visibilitystring-One of public, private
statusrequireddata[].statusstring-One of active, paused, suspended, pending_review
wholesaleCompatiblerequireddata[].wholesaleCompatibleboolean-
callcenterCompatiblerequireddata[].callcenterCompatibleboolean-
dialerCompatiblerequireddata[].dialerCompatibleboolean-
retailCompatiblerequireddata[].retailCompatibleboolean-
otpCompatiblerequireddata[].otpCompatibleboolean-
notesrequireddata[].notesstring | null-
smsTypedata[].smsTypestring | null-One of a2p, p2p, both
exchangeScorerequireddata[].exchangeScoreinteger | nullExchange 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[].lastQcAtstring (date-time) | nullISO-8601 timestamp (UTC)
measureddata[].measuredobject | nullMeasured quality from real calls; null until the listing has enough traffic from enough buyers
windowrequireddata[].measured.windowstringEvidence 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.fromstringFirst UTC day of the evidence, YYYY-MM-DD
torequireddata[].measured.tostringLast UTC day of the evidence, YYYY-MM-DD
sessionsrequireddata[].measured.sessionsintegerCall 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.sessionsBandedbooleanTrue when sessions is a band floor (anonymous callers)
buyersrequireddata[].measured.buyersinteger | nullDistinct buying accounts behind the figures (at least 2). Null for anonymous callers
asrrequireddata[].measured.asrnumber | nullAnswer-seizure ratio %: answered attempts / attempts
acdrequireddata[].measured.acdnumber | nullAverage call duration of answered attempts, seconds of talk time
nerrequireddata[].measured.nernumber | nullNetwork effectiveness ratio %: attempts the network delivered to the handset (answered, user busy, no answer, callee rejected) / attempts
pddMsrequireddata[].measured.pddMsinteger | nullMedian post-dial delay in milliseconds (to the nearest 100 ms); null when not captured
routeChecksdata[].routeChecksobject | nullRoute checks on this listing in the last 7 days. Null when there were none.
totalrequireddata[].routeChecks.totalintegerRoute checks in the last 7 days that count towards the listing's health (calls to registered test lines)
answeredrequireddata[].routeChecks.answeredintegerOf those, how many the test line answered through this route
lastAtrequireddata[].routeChecks.lastAtstring (date-time) | nullWhen the last check completed
lastResultrequireddata[].routeChecks.lastResultstring | nullThe last check's verdict: working, no_capacity or not_delivered
createdAtrequireddata[].createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtrequireddata[].updatedAtstring (date-time)ISO-8601 timestamp (UTC)
isOwnrequireddata[].isOwnbooleanTrue only on your own listings
listingRefdata[].listingRefstringAnonymous 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[].sellerProfileobject | nullTrust signals only. The marketplace never names the seller behind a listing.
verifiedrequireddata[].sellerProfile.verifiedbooleanSeller identity verified
sellerScorerequireddata[].sellerProfile.sellerScoreinteger | nullAverage Exchange Score across the seller's trafficked routes
rateCountrequireddata[].rateCountintegerActive per-destination deck rows; > 0 means an A-Z deck
priceTrenddata[].priceTrendobject | nullReal 24h price movement from the price history; null when the route has not repriced
changePctrequireddata[].priceTrend.changePctnumber-
pointsrequireddata[].priceTrend.pointsnumber[]-
nextCursorstring | null-
hasMoreboolean-
totalintegerRoutes matching the filters across all pages
statsobject-
totalrequiredstats.totalinteger-
voiceCountrequiredstats.voiceCountinteger-
smsCountrequiredstats.smsCountinteger-
destinationsrequiredstats.destinationsinteger-
avgPricestats.avgPricenumber | nullSigned-in callers only. Average list price (display figure)
avgAsrstats.avgAsrnumber | nullSigned-in only. Average seller-stated ASR %
measuredAsrstats.measuredAsrnumber | nullSigned-in only. Measured ASR % over 30 days of real calls
avgScorestats.avgScoreinteger | nullSigned-in only
totalCapacitystats.totalCapacityintegerSigned-in only

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List a new route for sale

POST/api/v1/routes

Access
API key. Scoped keys need routes:write.
Rate limit
30 requests per minute

Request body (application/json)

FieldTypeDescription
typerequiredstring-One of voice, sms
countryrequiredstring-max 100 chars
countryCoderequiredstring-
prefixrequiredstring[]-
destinationNamerequiredstring-max 255 chars
pricePerUnitrequiredstring-
cliTyperequiredstring-One of full_cli, local_cli, mixed_cli, ncli, partial_cli
capacityrequiredinteger-0 to 1000000
expectedAsrstring-
expectedAcdstring-
expectedPddstring-
minAsrstring-
minAcdinteger-min 0
billingIncrementrequiredstring-
routeTyperequiredstring-One of direct, premium, standard, ncli
wholesaleCompatibleboolean-default true
callcenterCompatibleboolean-default true
dialerCompatibleboolean-default true
retailCompatibleboolean-default true
otpCompatibleboolean-default true
openRtpboolean-default false
visibilitystring-default "public"One of public, private
jingleEnabledboolean-default false
jingleApiUrlstring (uri) | null-
smsDeliveryUrlstring (uri) | null-
smsDeliveryMethodstring-One of http, smpp
smppHoststring | null-
smppPortinteger | null-1 to 65535
smppSystemIdstring | null-
smppPasswordstring | null-max 64 chars
smppBindTypestring | null-One of transceiver, transmitter
smppSystemTypestring | null-max 13 chars
smppTpsinteger | null-1 to 1000
smppSourceToninteger | null-0 to 6
smppSourceNpiinteger | null-0 to 18
smppDestToninteger | null-0 to 6
smppDestNpiinteger | null-0 to 18
jingleSipIpstring | null-
sipPortinteger | null-1 to 65535
sipAuthUsernamestring | null-max 128 chars
sipAuthPasswordstring | null-max 128 chars
techPrefixstring | null-
numberFormatobject | null-
modenumberFormat.modestring-One of custom
nationalPrefixnumberFormat.nationalPrefixstring-
stripnumberFormat.stripinteger-0 to 10
addnumberFormat.addstring-
t38Supportboolean-default false
supportedCodecsstring[]-
maxCallDurationinteger-min 0
smsTypestring-One of a2p, p2p, both
smsDlrSupportboolean-
smsConcatSupportboolean-
smsSenderIdTypestring-One of alphanumeric, numeric, preregistered
smsContentRestrictionsstring-
smsRouteQualitystring | null-One of hq, direct, aggregator, sim
smsSenderIdBehaviorstring | null-One of alphanumeric_preserved, numeric_long, overwritten, not_guaranteed
smsDlrLevelstring | null-One of real_operator, intermediate, submit_only, none
smsDlrPercentstring | null-
smsUnicodeSupportboolean | null-
smsAcceptedTrafficstring[] | null-One of wholesale, transactional, otp, marketing, promo_shortcode
timeOfDayPricingobject-
notesstring-max 2000 chars

Response 201

FieldTypeDescription
datarequiredobjectA route you listed, as only you (the seller) see it. Passwords are never returned.
idrequireddata.idstring (uuid)-
kindrequireddata.kindstring-One of single, blend
typerequireddata.typestring-One of voice, sms
countryrequireddata.countrystring-
countryCoderequireddata.countryCodestringE.164 country calling code, digits only
prefixrequireddata.prefixstring[]Dial prefixes the route covers
destinationNamerequireddata.destinationNamestringThe 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.cliTypestring-One of full_cli, ncli, partial_cli, local_cli, mixed_cli
routeTyperequireddata.routeTypestringQuality tierOne of direct, premium, standard, ncli
pricePerUnitrequireddata.pricePerUnitmoneyUSD 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.billingIncrementstring | nullFirst/subsequent increment in seconds, e.g. "60/60"
capacityrequireddata.capacityintegerChannels (voice) or messages per second (SMS)
expectedAsrrequireddata.expectedAsrstring | nullSeller-stated ASR %. The measured figure is in measured.asr
expectedAcdrequireddata.expectedAcdstring | nullSeller-stated ACD in seconds
expectedPddrequireddata.expectedPddstring | nullSeller-stated PDD in seconds
minAcdrequireddata.minAcdinteger | null-
minAsrrequireddata.minAsrstring | nullDecimal as a string, e.g. "92.50"
visibilityrequireddata.visibilitystring-One of public, private
statusrequireddata.statusstring-One of active, paused, suspended, pending_review
wholesaleCompatiblerequireddata.wholesaleCompatibleboolean-
callcenterCompatiblerequireddata.callcenterCompatibleboolean-
dialerCompatiblerequireddata.dialerCompatibleboolean-
retailCompatiblerequireddata.retailCompatibleboolean-
otpCompatiblerequireddata.otpCompatibleboolean-
notesrequireddata.notesstring | null-
smsTypedata.smsTypestring | null-One of a2p, p2p, both
exchangeScorerequireddata.exchangeScoreinteger | nullExchange 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.lastQcAtstring (date-time) | nullISO-8601 timestamp (UTC)
measureddata.measuredobject | nullMeasured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page.
routeChecksdata.routeChecksobject | nullRoute checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page.
createdAtrequireddata.createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtrequireddata.updatedAtstring (date-time)ISO-8601 timestamp (UTC)
sellerIdrequireddata.sellerIdstring (uuid)Your own account id
isOwnerdata.isOwnerboolean-One of true
parentRouteIdrequireddata.parentRouteIdstring (uuid) | null-
isBundlerequireddata.isBundleboolean-
jingleSipIprequireddata.jingleSipIpstring | nullYour SIP endpoint
sipPortrequireddata.sipPortinteger | null-
techPrefixrequireddata.techPrefixstring | null-
sipAuthUsernamerequireddata.sipAuthUsernamestring | null-
sipAuthPasswordSetrequireddata.sipAuthPasswordSetbooleanA SIP digest password is stored (never returned)
smsDeliveryMethoddata.smsDeliveryMethodstring | null-One of http, smpp
smsDeliveryUrlrequireddata.smsDeliveryUrlstring | null-
smppHostrequireddata.smppHoststring | null-
smppPortrequireddata.smppPortinteger | null-
smppSystemIdrequireddata.smppSystemIdstring | null-
smppPasswordSetrequireddata.smppPasswordSetbooleanAn SMPP password is stored (never returned)
endpointReachablerequireddata.endpointReachableboolean | null-
endpointCheckedAtrequireddata.endpointCheckedAtstring (date-time) | nullISO-8601 timestamp (UTC)
sellerProfiledata.sellerProfileobject | nullTrust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page.
rateCountdata.rateCountinteger-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Get marketplace totals for a filter

GET/api/v1/routes/stats

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

NameInTypeDescription
typequerystring-One of voice, sms
countryquerystring-
countryCodequerystring-
cliTypequerystring-One of full_cli, local_cli, mixed_cli, ncli, partial_cli
routeTypequerystring-One of direct, premium, standard, ncli
minPricequerystring-
maxPricequerystring-
minAsrquerystring-
minAcdquerystring-
maxPddquerystring-
minScorequeryinteger-
minCapacityqueryinteger-
billingquerystring-One of per_second, per_minute
wholesalequerystring-One of true, false
callcenterquerystring-One of true, false
retailquerystring-One of true, false
otpquerystring-One of true, false
openRtpquerystring-One of true, false
dialerquerystring-One of true, false
a2pquerystring-One of true, false
bundlesOnlyquerystring-One of true, false
searchquerystring-
sortquerystring-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
cursorquerystring (uuid)-
limitqueryinteger-Default 25

Response 200

FieldTypeDescription
datarequiredobjectSame fields as MarketplaceStats, shown earlier on this page.

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Price a phone number across the marketplace

GET/api/v1/routes/price-number

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

NameInTypeDescription
numberrequiredquerystringA full number or dial code, any formatting
typequerystring-One of voice, smsDefault "voice"

Response 200

FieldTypeDescription
datarequiredobject-
numberrequireddata.numberstringThe number as priced: digits only
typerequireddata.typestring-One of voice, sms
unitrequireddata.unitstringWhat rate is per: a minute (voice) or a message (SMS)One of min, msg
totalrequireddata.totalintegerRoutes that serve the number, before the 100-row cap
routesrequireddata.routesobject[]Cheapest first
idrequireddata.routes[].idstring (uuid)-
typerequireddata.routes[].typestring-One of voice, sms
namerequireddata.routes[].namestringThe 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[].listingRefstringAnonymous 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[].countrystring-
countryCoderequireddata.routes[].countryCodestringE.164 country calling code, digits only
matchedPrefixrequireddata.routes[].matchedPrefixstringThe dial prefix the number matched on this route (the longest one, on a deck)
destinationrequireddata.routes[].destinationstringThe destination that prefix belongs to, e.g. "United Kingdom-Mobile"; the country for a flat-priced listing
raterequireddata.routes[].ratemoneyWhat 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[].billingIncrementstring | nulle.g. "60/60" or "1/1"; null when the listing does not state one
pricedByrequireddata.routes[].pricedBystringdeck = priced by the matching rate-sheet row; flat = the listing's single priceOne of deck, flat
expectedAsrrequireddata.routes[].expectedAsrstring | nullSeller-stated ASR %. The measured figure is in measured.asr
expectedAcdrequireddata.routes[].expectedAcdstring | nullSeller-stated ACD in seconds
cliTyperequireddata.routes[].cliTypestring-
routeTyperequireddata.routes[].routeTypestringQuality tier
capacityrequireddata.routes[].capacityintegerChannels (voice) or messages per second (SMS)
exchangeScorerequireddata.routes[].exchangeScoreinteger | nullExchange Score 1-100; null ("New") until the route has carried traffic
measuredrequireddata.routes[].measuredobject | nullMeasured 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[].routeChecksobject | nullRoute 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[].isOwnbooleanTrue only on your own listing (signed-in callers), so you are not offered your own route
networkdata.routes[].networkobject | nullSMS routes that price the country per mobile network: which network rate is for. Absent otherwise
mccMncrequireddata.routes[].network.mccMncstring | nullMobile network code (MCC-MNC) rate is for, e.g. "234-10"; null when unknown
operatorrequireddata.routes[].network.operatorstring | nullNetwork name from public number-range data, e.g. "O2"
sourcerequireddata.routes[].network.sourcestringrange = number-range data; none = not determinedOne of range, hlr, none
rateBasisrequireddata.routes[].network.rateBasisstringnetwork = 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[].countryRatemoney | nullSMS 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.noticestring | nullWhy the list is empty when it is empty for a reason other than "no route covers it"One of sanctioned

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List destinations on the marketplace

GET/api/v1/routes/countries

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

FieldTypeDescription
datarequiredobject[]-
countryrequireddata[].countrystring-
countryCoderequireddata[].countryCodestring-
countrequireddata[].countinteger-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Get a route

GET/api/v1/routes/{id}

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

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
iddata.idstring (uuid)-
kinddata.kindstring-One of single, blend
typedata.typestring-One of voice, sms
countrydata.countrystring-
countryCodedata.countryCodestring-
prefixdata.prefixstring[]Dial prefixes the route covers
destinationNamedata.destinationNamestringThe 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.cliTypestring-One of full_cli, ncli, partial_cli, local_cli, mixed_cli
routeTypedata.routeTypestringQuality tierOne of direct, premium, standard, ncli
pricePerUnitdata.pricePerUnitmoneyUSD 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.billingIncrementstring | nullFirst/subsequent increment in seconds, e.g. "60/60"
capacitydata.capacityintegerChannels (voice) or messages per second (SMS)
expectedAsrdata.expectedAsrstring | nullSeller-stated ASR %. The measured figure is in measured.asr
expectedAcddata.expectedAcdstring | nullSeller-stated ACD in seconds
expectedPdddata.expectedPddstring | nullSeller-stated PDD in seconds
minAcddata.minAcdinteger | null-
minAsrdata.minAsrstring | nullDecimal as a string, e.g. "92.50"
visibilitydata.visibilitystring-One of private
statusdata.statusstring-One of active, paused, suspended, pending_review
wholesaleCompatibledata.wholesaleCompatibleboolean-
callcenterCompatibledata.callcenterCompatibleboolean-
dialerCompatibledata.dialerCompatibleboolean-
retailCompatibledata.retailCompatibleboolean-
otpCompatibledata.otpCompatibleboolean-
notesdata.notesstring | null-
smsTypedata.smsTypestring | null-One of a2p, p2p, both
exchangeScoredata.exchangeScoreinteger | nullExchange 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.lastQcAtstring (date-time) | nullISO-8601 timestamp (UTC)
measureddata.measuredobject | nullMeasured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page.
routeChecksdata.routeChecksobject | nullRoute checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page.
createdAtdata.createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtdata.updatedAtstring (date-time)ISO-8601 timestamp (UTC)
isOwndata.isOwnbooleanTrue only on your own listings
listingRefdata.listingRefstringAnonymous 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.sellerProfileobject | nullTrust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page.
rateCountdata.rateCountinteger-
priceTrenddata.priceTrendobject | nullReal 24h price movement from the price history; null when the route has not repriced
changePctrequireddata.priceTrend.changePctnumber-
pointsrequireddata.priceTrend.pointsnumber[]-
sellerIddata.sellerIdstring (uuid)Your own account id
isOwnerdata.isOwnerboolean-One of true
parentRouteIddata.parentRouteIdstring (uuid) | null-
isBundledata.isBundleboolean-
jingleSipIpdata.jingleSipIpstring | nullYour SIP endpoint
sipPortdata.sipPortinteger | null-
techPrefixdata.techPrefixstring | null-
sipAuthUsernamedata.sipAuthUsernamestring | null-
sipAuthPasswordSetdata.sipAuthPasswordSetbooleanA SIP digest password is stored (never returned)
smsDeliveryMethoddata.smsDeliveryMethodstring | null-One of http, smpp
smsDeliveryUrldata.smsDeliveryUrlstring | null-
smppHostdata.smppHoststring | null-
smppPortdata.smppPortinteger | null-
smppSystemIddata.smppSystemIdstring | null-
smppPasswordSetdata.smppPasswordSetbooleanAn SMPP password is stored (never returned)
endpointReachabledata.endpointReachableboolean | null-
endpointCheckedAtdata.endpointCheckedAtstring (date-time) | nullISO-8601 timestamp (UTC)
accessRequireddata.accessRequiredboolean-One of true
accessRequestPendingdata.accessRequestPendingboolean-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Update a route you listed

PUT/api/v1/routes/{id}

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

NameInTypeDescription
idrequiredpathstring-

Request body (application/json)

FieldTypeDescription
typestring-One of voice, sms
countrystring-max 100 chars
countryCodestring-
prefixstring[]-
destinationNamestring-max 255 chars
pricePerUnitstring-
cliTypestring-One of full_cli, local_cli, mixed_cli, ncli, partial_cli
capacityinteger-0 to 1000000
expectedAsrstring-
expectedAcdstring-
expectedPddstring-
minAsrstring-
minAcdinteger-min 0
billingIncrementstring-
routeTypestring-One of direct, premium, standard, ncli
wholesaleCompatibleboolean-default true
callcenterCompatibleboolean-default true
dialerCompatibleboolean-default true
retailCompatibleboolean-default true
otpCompatibleboolean-default true
openRtpboolean-default false
visibilitystring-default "public"One of public, private
jingleEnabledboolean-default false
jingleApiUrlstring (uri) | null-
smsDeliveryUrlstring (uri) | null-
smsDeliveryMethodstring-One of http, smpp
smppHoststring | null-
smppPortinteger | null-1 to 65535
smppSystemIdstring | null-
smppPasswordstring | null-max 64 chars
smppBindTypestring | null-One of transceiver, transmitter
smppSystemTypestring | null-max 13 chars
smppTpsinteger | null-1 to 1000
smppSourceToninteger | null-0 to 6
smppSourceNpiinteger | null-0 to 18
smppDestToninteger | null-0 to 6
smppDestNpiinteger | null-0 to 18
jingleSipIpstring | null-
sipPortinteger | null-1 to 65535
sipAuthUsernamestring | null-max 128 chars
sipAuthPasswordstring | null-max 128 chars
techPrefixstring | null-
numberFormatobject | null-
modenumberFormat.modestring-One of custom
nationalPrefixnumberFormat.nationalPrefixstring-
stripnumberFormat.stripinteger-0 to 10
addnumberFormat.addstring-
t38Supportboolean-default false
supportedCodecsstring[]-
maxCallDurationinteger-min 0
smsTypestring-One of a2p, p2p, both
smsDlrSupportboolean-
smsConcatSupportboolean-
smsSenderIdTypestring-One of alphanumeric, numeric, preregistered
smsContentRestrictionsstring-
smsRouteQualitystring | null-One of hq, direct, aggregator, sim
smsSenderIdBehaviorstring | null-One of alphanumeric_preserved, numeric_long, overwritten, not_guaranteed
smsDlrLevelstring | null-One of real_operator, intermediate, submit_only, none
smsDlrPercentstring | null-
smsUnicodeSupportboolean | null-
smsAcceptedTrafficstring[] | null-One of wholesale, transactional, otp, marketing, promo_shortcode
timeOfDayPricingobject-
notesstring-max 2000 chars
statusstring-One of active, paused

Response 200

FieldTypeDescription
datarequiredobjectA route you listed, as only you (the seller) see it. Passwords are never returned.Same fields as OwnRoute, shown earlier on this page.

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Delete a route you listed

DELETE/api/v1/routes/{id}

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

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
messagerequireddata.messagestring-
restorablerequireddata.restorableboolean-One of true
restoreWindowDaysrequireddata.restoreWindowDaysinteger-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Draft a listing from a rate sheet

POST/api/v1/routes/autopilot/draft

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)

FieldTypeDescription
filerequiredstringCSV or Excel rate sheet (binary)
notestring-max 500 chars

Response 200

FieldTypeDescription
datarequiredobjectA proposed listing form plus open questions

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Test an endpoint before listing a route

POST/api/v1/routes/probe-endpoint

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)

FieldTypeDescription
typerequiredstring-One of voice, sms
jingleSipIpstring | null-max 255 chars
sipPortinteger | null-1 to 65535
techPrefixstring | null-max 24 chars
smsDeliveryUrlstring | null-max 2048 chars
smsDeliveryMethodstring | null-One of http, smpp
smppHoststring | null-max 255 chars
smppPortinteger | null-1 to 65535
smppSystemIdstring | nullShort account code your SMS supplier issued (max 16 chars). An email address is rejected.max 16 chars
smppPasswordstring | nullUsed for one bind attempt, never storedmax 64 chars
smppBindTypestring | null-One of transceiver, transmitter
smppSystemTypestring | null-max 13 chars

Response 200

FieldTypeDescription
datarequiredobject-
passrequireddata.passbooleanTrue when the endpoint answered from every one of our media addresses
barreddata.barredbooleanReachable but refusing our calls
degradeddata.degradedbooleanRefusing some of our source addresses
checksrequireddata.checksobject[]-
labelrequireddata.checks[].labelstring-
valuerequireddata.checks[].valuestring-
okrequireddata.checks[].okboolean-
egressAddressesrequireddata.egressAddressesstringThe addresses our traffic comes from; whitelist these
gatewayIprequireddata.gatewayIpstringDeprecated alias of egressAddresses
diagnosticsdata.diagnosticsobject-
messagerequireddata.messagestring-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List your call-centre routes and their call screening

GET/api/v1/routes/callguard

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Response 200

FieldTypeDescription
datarequiredobject[]-
routeIdrequireddata[].routeIdstring (uuid)-
namerequireddata[].namestring-
countryrequireddata[].countrystring-
enabledrequireddata[].enabledboolean-
consentAtrequireddata[].consentAtstring (date-time) | nullISO-8601 timestamp (UTC)
statusrequireddata[].statusstring-One of active, paused, suspended, pending_review

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Get call screening settings, stats and flagged calls

GET/api/v1/routes/{id}/screening

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobjectScreening config, statistics and the flagged calls

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Turn call screening on or off for a route

PATCH/api/v1/routes/{id}/screening

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

NameInTypeDescription
idrequiredpathstring-

Request body (application/json)

FieldTypeDescription
enabledrequiredboolean-

Response 200

FieldTypeDescription
datarequiredobject-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Classify a sample transcript with call screening

POST/api/v1/routes/{id}/screening/test

Access
API key. Scoped keys need routes:write.
Rate limit
20 requests per minute

Parameters

NameInTypeDescription
idrequiredpathstring-

Request body (application/json)

FieldTypeDescription
transcriptrequiredstring-max 20000 chars

Response 200

FieldTypeDescription
datarequiredobjectThe classification the transcript would receive

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List your saved listing presets

GET/api/v1/routes/listing-presets

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Response 200

FieldTypeDescription
datarequiredobject-
presetsrequireddata.presetsobject[]-
namerequireddata.presets[].namestring-
valuesrequireddata.presets[].valuesobject-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Save a listing preset

PUT/api/v1/routes/listing-presets

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)

FieldTypeDescription
namerequiredstring-max 60 chars
valuesrequiredobject-

Response 200

FieldTypeDescription
datarequiredobject-
presetsrequireddata.presetsobject[]-
namerequireddata.presets[].namestring-
valuesrequireddata.presets[].valuesobject-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Delete a listing preset

DELETE/api/v1/routes/listing-presets/{name}

Access
API key. Scoped keys need routes:write.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
namerequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
presetsrequireddata.presetsobject[]-
namerequireddata.presets[].namestring-
valuesrequireddata.presets[].valuesobject-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Preview the listings publishing a deck will create

GET/api/v1/routes/{id}/split-preview

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobjectPer-country listings that publishing would produce

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List your recently deleted routes

GET/api/v1/routes/deleted

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Response 200

FieldTypeDescription
datarequiredobject-
routesrequireddata.routesobject[]-
iddata.routes[].idstring (uuid)-
kinddata.routes[].kindstring-One of single, blend
typedata.routes[].typestring-One of voice, sms
countrydata.routes[].countrystring-
countryCodedata.routes[].countryCodestringE.164 country calling code, digits only
prefixdata.routes[].prefixstring[]Dial prefixes the route covers
destinationNamedata.routes[].destinationNamestringThe 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[].cliTypestring-One of full_cli, ncli, partial_cli, local_cli, mixed_cli
routeTypedata.routes[].routeTypestringQuality tierOne of direct, premium, standard, ncli
pricePerUnitdata.routes[].pricePerUnitmoneyUSD 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[].billingIncrementstring | nullFirst/subsequent increment in seconds, e.g. "60/60"
capacitydata.routes[].capacityintegerChannels (voice) or messages per second (SMS)
expectedAsrdata.routes[].expectedAsrstring | nullSeller-stated ASR %. The measured figure is in measured.asr
expectedAcddata.routes[].expectedAcdstring | nullSeller-stated ACD in seconds
expectedPdddata.routes[].expectedPddstring | nullSeller-stated PDD in seconds
minAcddata.routes[].minAcdinteger | null-
minAsrdata.routes[].minAsrstring | nullDecimal as a string, e.g. "92.50"
visibilitydata.routes[].visibilitystring-One of public, private
statusdata.routes[].statusstring-One of active, paused, suspended, pending_review
wholesaleCompatibledata.routes[].wholesaleCompatibleboolean-
callcenterCompatibledata.routes[].callcenterCompatibleboolean-
dialerCompatibledata.routes[].dialerCompatibleboolean-
retailCompatibledata.routes[].retailCompatibleboolean-
otpCompatibledata.routes[].otpCompatibleboolean-
notesdata.routes[].notesstring | null-
smsTypedata.routes[].smsTypestring | null-One of a2p, p2p, both
exchangeScoredata.routes[].exchangeScoreinteger | nullExchange 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[].lastQcAtstring (date-time) | nullISO-8601 timestamp (UTC)
measureddata.routes[].measuredobject | nullMeasured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page.
routeChecksdata.routes[].routeChecksobject | nullRoute 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[].createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtdata.routes[].updatedAtstring (date-time)ISO-8601 timestamp (UTC)
sellerIddata.routes[].sellerIdstring (uuid)Your own account id
isOwnerdata.routes[].isOwnerboolean-One of true
parentRouteIddata.routes[].parentRouteIdstring (uuid) | null-
isBundledata.routes[].isBundleboolean-
jingleSipIpdata.routes[].jingleSipIpstring | nullYour SIP endpoint
sipPortdata.routes[].sipPortinteger | null-
techPrefixdata.routes[].techPrefixstring | null-
sipAuthUsernamedata.routes[].sipAuthUsernamestring | null-
sipAuthPasswordSetdata.routes[].sipAuthPasswordSetbooleanA SIP digest password is stored (never returned)
smsDeliveryMethoddata.routes[].smsDeliveryMethodstring | null-One of http, smpp
smsDeliveryUrldata.routes[].smsDeliveryUrlstring | null-
smppHostdata.routes[].smppHoststring | null-
smppPortdata.routes[].smppPortinteger | null-
smppSystemIddata.routes[].smppSystemIdstring | null-
smppPasswordSetdata.routes[].smppPasswordSetbooleanAn SMPP password is stored (never returned)
endpointReachabledata.routes[].endpointReachableboolean | null-
endpointCheckedAtdata.routes[].endpointCheckedAtstring (date-time) | nullISO-8601 timestamp (UTC)
sellerProfiledata.routes[].sellerProfileobject | nullTrust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page.
rateCountdata.routes[].rateCountinteger-
restoreWindowDaysrequireddata.restoreWindowDaysinteger-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Restore a deleted route

POST/api/v1/routes/{id}/restore

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

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
messagerequireddata.messagestring-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List your saved SIP endpoints

GET/api/v1/routes/my-endpoints

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Response 200

FieldTypeDescription
datarequiredobject[]-
iddata[].idstring (uuid) | null-
iprequireddata[].ipstring-
labeldata[].labelstring | null-
routeCountdata[].routeCountintegerHow many of your routes use this IP
usedBydata[].usedBystring | nullName of the newest route using this IP

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Save a SIP endpoint

POST/api/v1/routes/my-endpoints

Access
API key. Scoped keys need routes:write.
Rate limit
100 requests per second (the default)

Request body (application/json)

FieldTypeDescription
iprequiredstring-
labelstring | null-max 60 chars

Response 200

FieldTypeDescription
datarequiredobject-
iddata.idstring (uuid) | null-
iprequireddata.ipstring-
labeldata.labelstring | null-
routeCountdata.routeCountintegerHow many of your routes use this IP
usedBydata.usedBystring | nullName of the newest route using this IP

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Label a saved SIP endpoint

PATCH/api/v1/routes/my-endpoints/{id}

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

NameInTypeDescription
idrequiredpathstring (uuid)-

Request body (application/json)

FieldTypeDescription
labelrequiredstring | nullThe new label; "" or null clears itmax 60 chars

Response 200

FieldTypeDescription
datarequiredobject-
idrequireddata.idstring (uuid)-
iprequireddata.ipstring-
labelrequireddata.labelstring | null-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Remove a saved SIP endpoint

DELETE/api/v1/routes/my-endpoints/{id}

Access
API key. Scoped keys need routes:write.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Preview which route would carry a destination

GET/api/v1/routes/resolve

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

NameInTypeDescription
torequiredquerystringDestination number or prefix
typequerystring-One of voice, smsDefault "voice"
strategyquerystring-One of cheapest, best_quality, balancedDefault "balanced"

Response 200

FieldTypeDescription
datarequiredobject-
strategyrequireddata.strategystring-One of cheapest, best_quality, balanced
selectedrequireddata.selectedobject | null-
idrequireddata.selected.idstring (uuid)-
destinationNamerequireddata.selected.destinationNamestringThe 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.countrystring-
countryCoderequireddata.selected.countryCodestring-
typerequireddata.selected.typestring-One of voice, sms
cliTyperequireddata.selected.cliTypestring | null-
pricerequireddata.selected.pricemoneyRate 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.asrnumber | null-
acdrequireddata.selected.acdnumber | null-
matchedPrefixrequireddata.selected.matchedPrefixstring | null-
alternativesrequireddata.alternativesobject[]Same fields as ResolvedRoute, shown earlier on this page.
countrequireddata.countinteger-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Test connectivity to your route endpoint

POST/api/v1/routes/{id}/test

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

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobjectSame fields as ConnectivityTestResult, shown earlier on this page.

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Capture a SIP trace of a test call on a route

POST/api/v1/routes/{id}/sip-trace

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

NameInTypeDescription
idrequiredpathstring-

Request body (application/json)

FieldTypeDescription
numberstring-

Response 200

FieldTypeDescription
datarequiredobjectThe SIP ladder: messages, timings and the final response

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Get a route's price history

GET/api/v1/routes/{id}/price-history

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

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject[]-
idrequireddata[].idstring (uuid)-
routeIdrequireddata[].routeIdstring (uuid)-
oldPricerequireddata[].oldPricemoney | nullUS 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[].newPricemoneyUSD as a decimal string with exactly 6 places, e.g. "0.012500".
changedAtrequireddata[].changedAtstring (date-time)ISO-8601 timestamp (UTC)

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Get traffic and revenue stats for your route

GET/api/v1/routes/{id}/stats

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
activePurchasesrequireddata.activePurchasesinteger-
volumerequireddata.volumeobjectKeyed 24h, 7d, 30d. revenue is USD (display figure, 2 decimals)
measuredAsrrequireddata.measuredAsrnumber | null-
measuredAcdrequireddata.measuredAcdnumber | null-
recentOffersrequireddata.recentOffersobject[]-
idrequireddata.recentOffers[].idstring (uuid)-
proposedPricerequireddata.recentOffers[].proposedPricemoneyUSD as a decimal string with exactly 6 places, e.g. "0.012500".
agreedPricerequireddata.recentOffers[].agreedPricemoney | nullUS 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[].statusstring-
lastActorrequireddata.recentOffers[].lastActorstring-
createdAtrequireddata.recentOffers[].createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtrequireddata.recentOffers[].updatedAtstring (date-time)ISO-8601 timestamp (UTC)

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List the routes you sell

GET/api/v1/routes/my/list

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

NameInTypeDescription
cursorquerystring (uuid)-
limitqueryintegerCursor mode: default 25, max 100. Paged mode: default 50, max 200.
includeChildrenquerystringInclude the per-country children of A-Z decksOne of true, false, 1, 0
searchquerystring-
typequerystring-One of voice, sms
statusquerystring-One of active, paused, pending_review, suspended
visibilityquerystring-One of public, private
livequeryboolean | string-
hiddenReasonquerystring-One of sms_no_delivery, voice_no_endpoint
scopequerystring-One of listings, decks
endpointquerystring-
deckquerystring (uuid) | string-
offsetqueryinteger-
sortquerystring-One of created, name, country, type, price, status
dirquerystring-One of asc, desc

Response 200

FieldTypeDescription
datarequiredobject[]-
idrequireddata[].idstring (uuid)-
kindrequireddata[].kindstring-One of single, blend
typerequireddata[].typestring-One of voice, sms
countryrequireddata[].countrystring-
countryCoderequireddata[].countryCodestringE.164 country calling code, digits only
prefixrequireddata[].prefixstring[]Dial prefixes the route covers
destinationNamerequireddata[].destinationNamestringThe 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[].cliTypestring-One of full_cli, ncli, partial_cli, local_cli, mixed_cli
routeTyperequireddata[].routeTypestringQuality tierOne of direct, premium, standard, ncli
pricePerUnitrequireddata[].pricePerUnitmoneyUSD 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[].billingIncrementstring | nullFirst/subsequent increment in seconds, e.g. "60/60"
capacityrequireddata[].capacityintegerChannels (voice) or messages per second (SMS)
expectedAsrrequireddata[].expectedAsrstring | nullSeller-stated ASR %. The measured figure is in measured.asr
expectedAcdrequireddata[].expectedAcdstring | nullSeller-stated ACD in seconds
expectedPddrequireddata[].expectedPddstring | nullSeller-stated PDD in seconds
minAcdrequireddata[].minAcdinteger | null-
minAsrrequireddata[].minAsrstring | nullDecimal as a string, e.g. "92.50"
visibilityrequireddata[].visibilitystring-One of public, private
statusrequireddata[].statusstring-One of active, paused, suspended, pending_review
wholesaleCompatiblerequireddata[].wholesaleCompatibleboolean-
callcenterCompatiblerequireddata[].callcenterCompatibleboolean-
dialerCompatiblerequireddata[].dialerCompatibleboolean-
retailCompatiblerequireddata[].retailCompatibleboolean-
otpCompatiblerequireddata[].otpCompatibleboolean-
notesrequireddata[].notesstring | null-
smsTypedata[].smsTypestring | null-One of a2p, p2p, both
exchangeScorerequireddata[].exchangeScoreinteger | nullExchange 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[].lastQcAtstring (date-time) | nullISO-8601 timestamp (UTC)
measureddata[].measuredobject | nullMeasured quality from real calls; null until the listing has enough traffic from enough buyersSame fields as MeasuredRouteQuality, shown earlier on this page.
routeChecksdata[].routeChecksobject | nullRoute checks on this listing in the last 7 days. Null when there were none.Same fields as RouteCheckRecord, shown earlier on this page.
createdAtrequireddata[].createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtrequireddata[].updatedAtstring (date-time)ISO-8601 timestamp (UTC)
sellerIdrequireddata[].sellerIdstring (uuid)Your own account id
isOwnerdata[].isOwnerboolean-One of true
parentRouteIdrequireddata[].parentRouteIdstring (uuid) | null-
isBundlerequireddata[].isBundleboolean-
jingleSipIprequireddata[].jingleSipIpstring | nullYour SIP endpoint
sipPortrequireddata[].sipPortinteger | null-
techPrefixrequireddata[].techPrefixstring | null-
sipAuthUsernamerequireddata[].sipAuthUsernamestring | null-
sipAuthPasswordSetrequireddata[].sipAuthPasswordSetbooleanA SIP digest password is stored (never returned)
smsDeliveryMethoddata[].smsDeliveryMethodstring | null-One of http, smpp
smsDeliveryUrlrequireddata[].smsDeliveryUrlstring | null-
smppHostrequireddata[].smppHoststring | null-
smppPortrequireddata[].smppPortinteger | null-
smppSystemIdrequireddata[].smppSystemIdstring | null-
smppPasswordSetrequireddata[].smppPasswordSetbooleanAn SMPP password is stored (never returned)
endpointReachablerequireddata[].endpointReachableboolean | null-
endpointCheckedAtrequireddata[].endpointCheckedAtstring (date-time) | nullISO-8601 timestamp (UTC)
sellerProfiledata[].sellerProfileobject | nullTrust signals only. The marketplace never names the seller behind a listing.Same fields as MarketplaceSellerProfile, shown earlier on this page.
rateCountdata[].rateCountinteger-
revenue30drequireddata[].revenue30dnumberUSD seller credit over 30 days (display figure, 2 decimals)
liveChannelsrequireddata[].liveChannelsinteger-
childCountrequireddata[].childCountintegerPer-country child listings created from this deck
origindata[].originobjectPaged mode only: where the route terminates and where it came from
endpointKeyrequireddata[].origin.endpointKeystringThe endpoint group key: the host, "~none" (no endpoint) or "~blend". Pass it as ?endpoint= to list every route on it
kindrequireddata[].origin.kindstringsip = 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.hoststring | nullThe SIP IP, the SMSC host, or the delivery URL's host
portrequireddata[].origin.portinteger | nullSIP port (default 5060) or SMPP port (default 2775)
systemIdrequireddata[].origin.systemIdstring | nullSMPP only: the System ID bound with
labelrequireddata[].origin.labelstring | nullYour own label for this IP (see GET /routes/my-endpoints), voice only
deckIdrequireddata[].origin.deckIdstring (uuid) | nullThe A-Z deck this route was split out of, when it was
deckNamerequireddata[].origin.deckNamestring | null-
sheetNamerequireddata[].origin.sheetNamestring | nullFile name of the latest applied rate sheet behind the deck (or behind the route itself)
nextCursorrequiredstring | nullCursor mode only; always null in paged mode
hasMorerequiredboolean-
totalintegerPaged mode only: rows matching the filters across all pages
offsetintegerPaged mode only
limitintegerPaged mode only (max 200)

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Count your SMS routes hidden for lack of an endpoint

GET/api/v1/routes/sms-endpoint-gap

Access
API key. Scoped keys need routes:read.
Rate limit
100 requests per second (the default)

Response 200

FieldTypeDescription
datarequiredobject-
countrequireddata.countinteger-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Set one delivery endpoint on all your endpoint-less SMS routes

POST/api/v1/routes/sms-endpoint/bulk

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)

FieldTypeDescription
methodrequiredstring-One of http, smpp
smsDeliveryUrlstring-
smppHoststring-
smppPortinteger-
smppSystemIdstring-
smppPasswordstring-
smppBindTypestring-One of transceiver, transmitter
smppSystemTypestring-
routeIdsstring (uuid)[]Narrow to these routes; never widens the set

Response 200

FieldTypeDescription
datarequiredobject-
updatedrequireddata.updatedinteger-
methodrequireddata.methodstring-One of http, smpp
binddata.bindstring-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Count your listed routes that are live, and why the rest are hidden

GET/api/v1/routes/my/listing-health

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

FieldTypeDescription
datarequiredobject-
listedrequireddata.listedintegerYour routes that are active, public and not an A-Z deck parent: what you have put on sale
liverequireddata.liveintegerHow many of those buyers can actually see on the marketplace (counted with the marketplace's own filters)
hiddenrequireddata.hiddenintegerlisted - live
reasonsrequireddata.reasonsobject[]Why the hidden routes are hidden, in the order to fix them. Only reasons with a non-zero count are present.
keyrequireddata.reasons[].keystringsms_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[].countinteger-
labelrequireddata.reasons[].labelstringThe reason in plain words
fixrequireddata.reasons[].fixstringWhat to do about it

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Set one SMS delivery method on many of your SMS routes

POST/api/v1/routes/my/bulk-sms-delivery

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)

FieldTypeDescription
routeIdsstring (uuid)[]An explicit selection of your route ids (max 5000). Send this OR filter, not both.
filterobject"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.searchstring-max 100 chars
typefilter.typestring-One of voice, sms
statusfilter.statusstring-One of active, paused, pending_review, suspended
visibilityfilter.visibilitystring-One of public, private
livefilter.liveboolean | string-
hiddenReasonfilter.hiddenReasonstring-One of sms_no_delivery, voice_no_endpoint
scopefilter.scopestring-One of listings, decks
endpointfilter.endpointstring-max 255 chars
deckfilter.deckstring (uuid) | string-
dryRunbooleanCount and classify only: nothing is probed or written, and the answer carries wouldUpdate
deliveryrequiredobjectThe 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.smsDeliveryMethodstring-One of http, smpp
smsDeliveryUrldelivery.smsDeliveryUrlstring (uri) | null-
smppHostdelivery.smppHoststring | null-
smppPortdelivery.smppPortinteger | null-1 to 65535
smppSystemIddelivery.smppSystemIdstring | null-
smppPassworddelivery.smppPasswordstring | null-max 64 chars
smppBindTypedelivery.smppBindTypestring | null-One of transceiver, transmitter
smppSystemTypedelivery.smppSystemTypestring | null-max 13 chars

Response 200

FieldTypeDescription
datarequiredobject-
updatedrequireddata.updatedintegerRoutes changed. Always 0 on a dry run.
wouldUpdatedata.wouldUpdateintegerDry run (or nothing eligible): how many routes the call would change
skippedrequireddata.skippedobject[]Routes left untouched, each with the reason
idrequireddata.skipped[].idstring (uuid)-
reasonrequireddata.skipped[].reasonstringnot_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.checkobjectThe 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.passboolean-
messagerequireddata.check.messagestring-
dryRundata.dryRunboolean-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Set one SIP endpoint on many of your voice routes

POST/api/v1/routes/my/bulk-sip-endpoint

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)

FieldTypeDescription
routeIdsstring (uuid)[]An explicit selection of your route ids (max 5000). Send this OR filter, not both.
filterobject"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.searchstring-max 100 chars
typefilter.typestring-One of voice, sms
statusfilter.statusstring-One of active, paused, pending_review, suspended
visibilityfilter.visibilitystring-One of public, private
livefilter.liveboolean | string-
hiddenReasonfilter.hiddenReasonstring-One of sms_no_delivery, voice_no_endpoint
scopefilter.scopestring-One of listings, decks
endpointfilter.endpointstring-max 255 chars
deckfilter.deckstring (uuid) | string-
dryRunbooleanCount and classify only: nothing is probed or written, and the answer carries wouldUpdate
deliveryrequiredobjectThe 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.jingleSipIpstring | null-
sipPortdelivery.sipPortinteger | null-1 to 65535
techPrefixdelivery.techPrefixstring | null-
sipAuthUsernamedelivery.sipAuthUsernamestring | null-max 128 chars
sipAuthPassworddelivery.sipAuthPasswordstring | null-max 128 chars
confirmUnreachablebooleanApply even though the SIP probe got no answer (the first attempt is refused with the probe's diagnosis in error.details)

Response 200

FieldTypeDescription
datarequiredobjectSame fields as BulkEndpointResult, shown earlier on this page.

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Group the routes you sell by endpoint or by A-Z deck

GET/api/v1/routes/my/groups

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

NameInTypeDescription
searchquerystring-
typequerystring-One of voice, sms
statusquerystring-One of active, paused, pending_review, suspended
visibilityquerystring-One of public, private
livequeryboolean | string-
hiddenReasonquerystring-One of sms_no_delivery, voice_no_endpoint
scopequerystring-One of listings, decks
endpointquerystring-
deckquerystring (uuid) | string-
byrequiredquerystring-One of endpoint, deck

Response 200

FieldTypeDescription
datarequiredobject-
byrequireddata.bystring-One of endpoint, deck
groupsrequireddata.groupsobject[]Largest group first, at most 500
keyrequireddata.groups[].keystringPass 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[].kindstringby=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[].hoststring | null-
labelrequireddata.groups[].labelstring | nullYour label for this IP
portrequireddata.groups[].portinteger | nullThe port when every route in the group uses the same one
systemIdrequireddata.groups[].systemIdstring | nullSMPP: the System ID when every route in the group uses the same one
deckIdrequireddata.groups[].deckIdstring (uuid) | null-
deckNamerequireddata.groups[].deckNamestring | null-
sheetNamerequireddata.groups[].sheetNamestring | nullFile name of the deck's latest applied rate sheet
totalrequireddata.groups[].totalinteger-
liverequireddata.groups[].liveintegerVisible to buyers, by the marketplace's own filters
hiddenrequireddata.groups[].hiddenintegertotal - live
totalrequireddata.totalintegerRoutes across the returned groups
truncatedrequireddata.truncatedbooleanMore than 500 groups matched; narrow the filter

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Check whether your switches are refusing our calls

GET/api/v1/routes/my/endpoint-status

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

FieldTypeDescription
datarequiredobject-
endpointsrequireddata.endpointsobject[]-
endpointKeyrequireddata.endpoints[].endpointKeystring-
hostrequireddata.endpoints[].hoststring-
endpointrequireddata.endpoints[].endpointstring-
kindrequireddata.endpoints[].kindstring-One of voice
routeCountrequireddata.endpoints[].routeCountinteger-
routeIdrequireddata.endpoints[].routeIdstring (uuid)-
refusingrequireddata.endpoints[].refusingboolean-
partialrequireddata.endpoints[].partialboolean-
refusedIpsrequireddata.endpoints[].refusedIpsstring[]-
evidencerequireddata.endpoints[].evidencestring | null-
sourcerequireddata.endpoints[].sourcestring | null-One of traffic, probe
sincerequireddata.endpoints[].sincestring (date-time) | nullISO-8601 timestamp (UTC)
allowrequireddata.allowobject-
egressIpsrequireddata.allow.egressIpsstring[]-
sipPortrequireddata.allow.sipPortinteger-
rtpPortRangerequireddata.allow.rtpPortRangestring-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

List the buyers of your route

GET/api/v1/routes/{id}/buyers

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

NameInTypeDescription
idrequiredpathstring (uuid)-

Response 200

FieldTypeDescription
datarequiredobject-
windowDaysrequireddata.windowDaysinteger-
unitrequireddata.unitstring-One of minutes, messages
buyersrequireddata.buyersobject[]-
buyerrequireddata.buyers[].buyerstringPseudonym, stable per route
statusrequireddata.buyers[].statusstring-One of active, paused, pending_review, ended
volume30drequireddata.buyers[].volume30dnumber-
revenue30drequireddata.buyers[].revenue30dnumberUSD (display figure, 2 decimals)
asr30drequireddata.buyers[].asr30dnumber | null-
calls30drequireddata.buyers[].calls30dinteger | null-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Show the billing increments your rate sheet sets

GET/api/v1/routes/{id}/rate-increments

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

NameInTypeDescription
idrequiredpathstring (uuid)-

Response 200

FieldTypeDescription
datarequiredobject-
mixrequireddata.mixobject[]-
incrementrequireddata.mix[].incrementstring | nulle.g. "60/60"; null = the row uses the route fallback
destinationsrequireddata.mix[].destinationsintegerActive rate rows with this increment
fallbackrequireddata.fallbackstring | nullThe route-level billing increment

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Read a rate sheet into a draft listing (no account needed)

POST/api/v1/public/listings/parse

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)

FieldTypeDescription
filerequiredstringCSV or Excel rate sheet (binary)
notestring-max 500 chars

Response 200

FieldTypeDescription
datarequiredobjectProposed listing, parsed rates and truncated

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Save a draft listing to claim after sign-up

POST/api/v1/public/listings

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)

FieldTypeDescription
payloadany-
ratesobject[]-
destinationNamerates[].destinationNamestring-
operatorrates[].operatorstring | null-
prefixrequiredrates[].prefixstring-
ratePerUnitrequiredrates[].ratePerUnitstring-
billingIncrementrates[].billingIncrementstring | null-
minDurationrates[].minDurationnumber | null-
sourceFilenamestring-max 512 chars
contactEmailstring (email)-max 255 chars
contactCompanystring-max 255 chars

Response 200

FieldTypeDescription
datarequiredobject-
tokenrequireddata.tokenstring-
expiresAtrequireddata.expiresAtstring (date-time)ISO-8601 timestamp (UTC)
rateCountrequireddata.rateCountinteger-
destinationNamerequireddata.destinationNamestring-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Look at a saved draft listing

GET/api/v1/public/listings/{token}

Access
Public. No key needed.
Rate limit
30 requests per minute

Parameters

NameInTypeDescription
tokenrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
alreadyClaimedrequireddata.alreadyClaimedboolean-
routeIddata.routeIdstring (uuid) | null-
destinationNamedata.destinationNamestring-
typedata.typestring-One of voice, sms
countrydata.countrystring-
rateCountdata.rateCountinteger-
sourceFilenamedata.sourceFilenamestring | null-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 404NOT_FOUND: no such resource on your account.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.

Create a route from a saved draft listing

POST/api/v1/listings/{token}/claim

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

NameInTypeDescription
tokenrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
routeIdrequireddata.routeIdstring (uuid) | null-
rateCountrequireddata.rateCountinteger-
alreadyClaimedrequireddata.alreadyClaimedboolean-

Errors

  • 400VALIDATION_ERROR, INVALID_INPUT or BAD_REQUEST. For VALIDATION_ERROR, error.details is an array of { path, message }.
  • 401UNAUTHORIZED: missing, invalid, expired or revoked credential.
  • 403FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only.
  • 404NOT_FOUND: no such resource on your account.
  • 409CONFLICT (or a code-specific 409): the change clashes with existing state.
  • 429RATE_LIMITED: slow down and retry after the Retry-After seconds.
  • 500INTERNAL_ERROR: unexpected failure. Quote X-Request-Id to support.