Skip to content
Markets open

API reference

Offers

Propose, counter and accept prices on marketplace routes.

7 operationsBase URL https://packetexchange.io/api/v1Postman collection

List offers you made and received

GET/api/v1/offers

Access
API key. Full-access keys only; not reachable by scoped keys.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
rolequerystringDefault allOne of buyer, seller, all
statusquerystring-One of pending, countered, accepted, rejected, withdrawn, expired

Response 200

FieldTypeDescription
datarequiredobject[]-
idrequireddata[].idstring (uuid)-
routeIdrequireddata[].routeIdstring (uuid)-
groupIdrequireddata[].groupIdstring (uuid) | nullSet when the offer is part of a bulk (multi-route) offer
listPricerequireddata[].listPricemoney | nullThe route list price when the offer was made USD as a decimal string with exactly 6 places, e.g. "0.012500".
proposedPricerequireddata[].proposedPricemoneyThe latest price on the table USD as a decimal string with exactly 6 places, e.g. "0.012500".
agreedPricerequireddata[].agreedPricemoney | nullSet once accepted USD as a decimal string with exactly 6 places, e.g. "0.012500".
statusrequireddata[].statusstring-One of pending, countered, accepted, rejected, withdrawn, expired
lastActorrequireddata[].lastActorstring-One of buyer, seller
messagerequireddata[].messagestring | nullCleaned of contact details
expiresAtrequireddata[].expiresAtstring (date-time) | nullISO-8601 timestamp (UTC)
createdAtrequireddata[].createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtrequireddata[].updatedAtstring (date-time)ISO-8601 timestamp (UTC)
rolerequireddata[].rolestringYour side of this offerOne of buyer, seller
yourTurnrequireddata[].yourTurnboolean-
counterpartyrequireddata[].counterpartystringPseudonym for the other side, stable per route
routerequireddata[].routeobject | null-
idrequireddata[].route.idstring (uuid)-
destinationNamerequireddata[].route.destinationNamestringThe seller reads the name they gave the route; the buyer reads the platform-generated name (see MarketplaceRoute.destinationName)
listingRefdata[].route.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[].route.countrystring-
countryCoderequireddata[].route.countryCodestring-
typerequireddata[].route.typestring-One of voice, sms
routeTyperequireddata[].route.routeTypestring-
pricePerUnitrequireddata[].route.pricePerUnitmoneyUSD as a decimal string with exactly 6 places, e.g. "0.012500".

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.

Make an offer on a route

POST/api/v1/offers

Access
API key. Scoped keys need offers:write.
Rate limit
100 requests per second (the default)
Safe retries
Send X-Idempotency-Key; a replay within 24 hours returns the first response.
Moves money
Makes or answers a binding offer on a route.

Opens a negotiation at proposedPrice (6-decimal USD string). The seller can accept, reject or counter.

Parameters

NameInTypeDescription
X-Idempotency-KeyheaderstringAny unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.

Request body (application/json)

FieldTypeDescription
routeIdrequiredstring (uuid)-
proposedPricerequiredstring-
messagestring-max 500 chars

Response 200

FieldTypeDescription
datarequiredobjectSame fields as Offer, 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.

Make offers on several routes at once

POST/api/v1/offers/bulk

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

One offer per item, grouped. Routes that cannot take an offer (your own, inactive, already negotiating) are skipped and reported back.

Request body (application/json)

FieldTypeDescription
itemsrequiredobject[]-
routeIdrequireditems[].routeIdstring (uuid)-
proposedPricerequireditems[].proposedPricestring-
messagestring-max 500 chars

Response 200

FieldTypeDescription
datarequiredobject-
grouprequireddata.groupobject-
idrequireddata.group.idstring (uuid)-
messagerequireddata.group.messagestring | null-
statusrequireddata.group.statusstring-
createdAtrequireddata.group.createdAtstring (date-time)ISO-8601 timestamp (UTC)
offersrequireddata.offersobject[]Same fields as Offer, shown earlier on this page.
skippedrequireddata.skippedobject[]-
routeIdrequireddata.skipped[].routeIdstring (uuid)-
reasonrequireddata.skipped[].reasonstring-

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 bulk offers

GET/api/v1/offers/groups

Access
API key. Full-access keys only; not reachable by scoped keys.
Rate limit
100 requests per second (the default)

Response 200

FieldTypeDescription
datarequiredobject[]-
idrequireddata[].idstring (uuid)-
messagerequireddata[].messagestring | null-
statusrequireddata[].statusstring-
createdAtrequireddata[].createdAtstring (date-time)ISO-8601 timestamp (UTC)
offersrequireddata[].offersobject[]Same fields as Offer, shown earlier on this page.
totalrequireddata[].totalinteger-
countsrequireddata[].countsobjectChild offers per status

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.

Accept or reject every open offer in a bulk offer

POST/api/v1/offers/groups/{id}/respond

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

Parameters

NameInTypeDescription
idrequiredpathstring-

Request body (application/json)

FieldTypeDescription
actionrequiredstring-One of accept, reject
messagestring-max 500 chars

Response 200

FieldTypeDescription
datarequiredobject-
groupIdrequireddata.groupIdstring (uuid)-
appliedrequireddata.appliedinteger-
resultsrequireddata.resultsobject[]-
okrequireddata.results[].okboolean-

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 an offer with its negotiation history

GET/api/v1/offers/{id}

Access
API key. Full-access keys only; not reachable by scoped keys.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
idrequiredpathstring-

Response 200

FieldTypeDescription
datarequiredobject-
idrequireddata.idstring (uuid)-
routeIdrequireddata.routeIdstring (uuid)-
groupIdrequireddata.groupIdstring (uuid) | nullSet when the offer is part of a bulk (multi-route) offer
listPricerequireddata.listPricemoney | nullThe route list price when the offer was made USD as a decimal string with exactly 6 places, e.g. "0.012500".
proposedPricerequireddata.proposedPricemoneyThe latest price on the table USD as a decimal string with exactly 6 places, e.g. "0.012500".
agreedPricerequireddata.agreedPricemoney | nullSet once accepted USD as a decimal string with exactly 6 places, e.g. "0.012500".
statusrequireddata.statusstring-One of pending, countered, accepted, rejected, withdrawn, expired
lastActorrequireddata.lastActorstring-One of buyer, seller
messagerequireddata.messagestring | nullCleaned of contact details
expiresAtrequireddata.expiresAtstring (date-time) | nullISO-8601 timestamp (UTC)
createdAtrequireddata.createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtrequireddata.updatedAtstring (date-time)ISO-8601 timestamp (UTC)
rolerequireddata.rolestringYour side of this offerOne of buyer, seller
yourTurnrequireddata.yourTurnboolean-
counterpartyrequireddata.counterpartystringPseudonym for the other side, stable per route
routerequireddata.routeobject | null-
idrequireddata.route.idstring (uuid)-
destinationNamerequireddata.route.destinationNamestringThe seller reads the name they gave the route; the buyer reads the platform-generated name (see MarketplaceRoute.destinationName)
listingRefdata.route.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.route.countrystring-
countryCoderequireddata.route.countryCodestring-
typerequireddata.route.typestring-One of voice, sms
routeTyperequireddata.route.routeTypestring-
pricePerUnitrequireddata.route.pricePerUnitmoneyUSD as a decimal string with exactly 6 places, e.g. "0.012500".
eventsrequireddata.eventsobject[]The negotiation timeline, oldest first
idrequireddata.events[].idstring (uuid)-
offerIdrequireddata.events[].offerIdstring (uuid)-
actorrequireddata.events[].actorstring-
actionrequireddata.events[].actionstring-
pricerequireddata.events[].pricemoney | 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".
messagerequireddata.events[].messagestring | null-
createdAtrequireddata.events[].createdAtstring (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.

Accept, reject, counter or withdraw an offer

PATCH/api/v1/offers/{id}

Access
API key. Scoped keys need offers:write.
Rate limit
100 requests per second (the default)
Safe retries
Send X-Idempotency-Key; a replay within 24 hours returns the first response.
Moves money
Makes or answers a binding offer on a route.

price is required for counter. Accepting creates or reprices the purchase at the agreed price.

Parameters

NameInTypeDescription
idrequiredpathstring-
X-Idempotency-KeyheaderstringAny unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.

Request body (application/json)

FieldTypeDescription
actionrequiredstring-One of counter, accept, reject, withdraw
pricestring-
messagestring-max 500 chars

Response 200

FieldTypeDescription
datarequiredobjectSame fields as Offer, 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.