Skip to content

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

  • role

    query · string

    Default allOne of buyer, seller, all
  • status

    query · string

    One of pending, countered, accepted, rejected, withdrawn, expired

Response 200

  • datarequired

    object[]

  • idrequired

    string (uuid) · data[].id

  • routeIdrequired

    string (uuid) · data[].routeId

  • groupIdrequired

    string (uuid) | null · data[].groupId

    Set when the offer is part of a bulk (multi-route) offer
  • listPricerequired

    money | null · data[].listPrice

    The route list price when the offer was made USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • proposedPricerequired

    money · data[].proposedPrice

    The latest price on the table USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • agreedPricerequired

    money | null · data[].agreedPrice

    Set once accepted USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • statusrequired

    string · data[].status

    One of pending, countered, accepted, rejected, withdrawn, expired
  • lastActorrequired

    string · data[].lastActor

    One of buyer, seller
  • messagerequired

    string | null · data[].message

    Cleaned of contact details
  • expiresAtrequired

    string (date-time) | null · data[].expiresAt

    ISO-8601 timestamp (UTC)
  • createdAtrequired

    string (date-time) · data[].createdAt

    ISO-8601 timestamp (UTC)
  • updatedAtrequired

    string (date-time) · data[].updatedAt

    ISO-8601 timestamp (UTC)
  • rolerequired

    string · data[].role

    Your side of this offerOne of buyer, seller
  • yourTurnrequired

    boolean · data[].yourTurn

  • counterpartyrequired

    string · data[].counterparty

    Pseudonym for the other side, stable per route
  • routerequired

    object | null · data[].route

  • idrequired

    string (uuid) · data[].route.id

  • destinationNamerequired

    string · data[].route.destinationName

    The seller reads the name they gave the route; the buyer reads the platform-generated name (see MarketplaceRoute.destinationName)
  • listingRef

    string · data[].route.listingRef

    Anonymous short reference of the listing (4 characters, e.g. "7K2Q"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings.
  • countryrequired

    string · data[].route.country

  • countryCoderequired

    string · data[].route.countryCode

  • typerequired

    string · data[].route.type

    One of voice, sms
  • routeTyperequired

    string · data[].route.routeType

  • pricePerUnitrequired

    money · data[].route.pricePerUnit

    USD 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

  • X-Idempotency-Key

    header · string

    Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.

Request body (application/json)

  • routeIdrequired

    string (uuid)

  • proposedPricerequired

    string

  • message

    string

    max 500 chars

Response 200

  • datarequired

    object

    Same 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)

  • itemsrequired

    object[]

  • routeIdrequired

    string (uuid) · items[].routeId

  • proposedPricerequired

    string · items[].proposedPrice

  • message

    string

    max 500 chars

Response 200

  • datarequired

    object

  • grouprequired

    object · data.group

  • idrequired

    string (uuid) · data.group.id

  • messagerequired

    string | null · data.group.message

  • statusrequired

    string · data.group.status

  • createdAtrequired

    string (date-time) · data.group.createdAt

    ISO-8601 timestamp (UTC)
  • offersrequired

    object[] · data.offers

    Same fields as Offer, shown earlier on this page.
  • skippedrequired

    object[] · data.skipped

  • routeIdrequired

    string (uuid) · data.skipped[].routeId

  • reasonrequired

    string · data.skipped[].reason

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

  • datarequired

    object[]

  • idrequired

    string (uuid) · data[].id

  • messagerequired

    string | null · data[].message

  • statusrequired

    string · data[].status

  • createdAtrequired

    string (date-time) · data[].createdAt

    ISO-8601 timestamp (UTC)
  • offersrequired

    object[] · data[].offers

    Same fields as Offer, shown earlier on this page.
  • totalrequired

    integer · data[].total

  • countsrequired

    object · data[].counts

    Child 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

  • idrequired

    path · string

Request body (application/json)

  • actionrequired

    string

    One of accept, reject
  • message

    string

    max 500 chars

Response 200

  • datarequired

    object

  • groupIdrequired

    string (uuid) · data.groupId

  • appliedrequired

    integer · data.applied

  • resultsrequired

    object[] · data.results

  • okrequired

    boolean · data.results[].ok

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

  • idrequired

    path · string

Response 200

  • datarequired

    object

  • idrequired

    string (uuid) · data.id

  • routeIdrequired

    string (uuid) · data.routeId

  • groupIdrequired

    string (uuid) | null · data.groupId

    Set when the offer is part of a bulk (multi-route) offer
  • listPricerequired

    money | null · data.listPrice

    The route list price when the offer was made USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • proposedPricerequired

    money · data.proposedPrice

    The latest price on the table USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • agreedPricerequired

    money | null · data.agreedPrice

    Set once accepted USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • statusrequired

    string · data.status

    One of pending, countered, accepted, rejected, withdrawn, expired
  • lastActorrequired

    string · data.lastActor

    One of buyer, seller
  • messagerequired

    string | null · data.message

    Cleaned of contact details
  • expiresAtrequired

    string (date-time) | null · data.expiresAt

    ISO-8601 timestamp (UTC)
  • createdAtrequired

    string (date-time) · data.createdAt

    ISO-8601 timestamp (UTC)
  • updatedAtrequired

    string (date-time) · data.updatedAt

    ISO-8601 timestamp (UTC)
  • rolerequired

    string · data.role

    Your side of this offerOne of buyer, seller
  • yourTurnrequired

    boolean · data.yourTurn

  • counterpartyrequired

    string · data.counterparty

    Pseudonym for the other side, stable per route
  • routerequired

    object | null · data.route

  • idrequired

    string (uuid) · data.route.id

  • destinationNamerequired

    string · data.route.destinationName

    The seller reads the name they gave the route; the buyer reads the platform-generated name (see MarketplaceRoute.destinationName)
  • listingRef

    string · data.route.listingRef

    Anonymous short reference of the listing (4 characters, e.g. "7K2Q"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings.
  • countryrequired

    string · data.route.country

  • countryCoderequired

    string · data.route.countryCode

  • typerequired

    string · data.route.type

    One of voice, sms
  • routeTyperequired

    string · data.route.routeType

  • pricePerUnitrequired

    money · data.route.pricePerUnit

    USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • eventsrequired

    object[] · data.events

    The negotiation timeline, oldest first
  • idrequired

    string (uuid) · data.events[].id

  • offerIdrequired

    string (uuid) · data.events[].offerId

  • actorrequired

    string · data.events[].actor

  • actionrequired

    string · data.events[].action

  • pricerequired

    money | null · data.events[].price

    US dollars as a decimal string with exactly 6 decimal places, e.g. "0.012500". Do money arithmetic with a decimal type, not floating point. USD as a decimal string with exactly 6 places, e.g. "0.012500".
  • messagerequired

    string | null · data.events[].message

  • createdAtrequired

    string (date-time) · data.events[].createdAt

    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

  • idrequired

    path · string

  • X-Idempotency-Key

    header · string

    Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.

Request body (application/json)

  • actionrequired

    string

    One of counter, accept, reject, withdraw
  • price

    string

  • message

    string

    max 500 chars

Response 200

  • datarequired

    object

    Same 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.