Skip to content
Markets open

API reference

Authentication

Log in, refresh tokens, sessions, email verification and password reset.

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

Create an account

POST/api/v1/auth/register

Access
Public. No key needed.
Rate limit
200 requests per hour

Creates the account, emails a verification link and signs you in. acceptTerms must be true. An invite code, when given, adds test credit once the email is verified. Returns the same session payload as login.

Request body (application/json)

FieldTypeDescription
emailrequiredstring (email)-
passwordrequiredstring-max 128 chars
contactNamerequiredstring-max 255 chars
companyNamestring-max 255 chars
countrystring-max 2 chars
inviteCodestring-
acceptTermsrequiredboolean-One of true

Response 201

FieldTypeDescription
datarequiredobject-
accessTokenrequireddata.accessTokenstringJWT access token. Send as Authorization: Bearer <token>.
refreshTokenrequireddata.refreshTokenstringRefresh token (7 days). Also set as an httpOnly cookie scoped to /api/v1/auth.
expiresInrequireddata.expiresInintegerAccess-token lifetime in seconds (900)
userrequireddata.userobject-
idrequireddata.user.idstring (uuid)-
emailrequireddata.user.emailstring (email)-
contactNamerequireddata.user.contactNamestring-
companyNamerequireddata.user.companyNamestring | null-
jobTitlerequireddata.user.jobTitlestring | null-
phonerequireddata.user.phonestring | null-
countryrequireddata.user.countrystring | nullISO-3166-1 alpha-2
timezonerequireddata.user.timezonestring-
companyLogoUrlrequireddata.user.companyLogoUrlstring | null-
avatarUrlrequireddata.user.avatarUrlstring | null-
rolerequireddata.user.rolestring-One of user, admin
statusrequireddata.user.statusstring-One of active, suspended
accountKindrequireddata.user.accountKindstring-
balancerequireddata.user.balancemoneyUSD as a decimal string with exactly 6 places, e.g. "0.012500".
testCreditrequireddata.user.testCreditmoneySandbox credit, spendable only by test API keys USD as a decimal string with exactly 6 places, e.g. "0.012500".
emailVerifiedAtrequireddata.user.emailVerifiedAtstring (date-time) | nullISO-8601 timestamp (UTC)
pendingEmailrequireddata.user.pendingEmailstring | nullAn address change waiting for confirmation
verificationStatusrequireddata.user.verificationStatusstring-One of unverified, verified
kycStatusrequireddata.user.kycStatusstring-One of not_started, pending, verified, rejected
totpEnabledrequireddata.user.totpEnabledbooleanTwo-factor authentication is on
taxIdrequireddata.user.taxIdstring | null-
taxCountryrequireddata.user.taxCountrystring | null-
payoutMethodrequireddata.user.payoutMethodstring | null-
onboardingGoalrequireddata.user.onboardingGoalstring | null-
onboardingDismissedrequireddata.user.onboardingDismissedboolean-
onboardingSeenrequireddata.user.onboardingSeenboolean-
emailNotificationsOptOutrequireddata.user.emailNotificationsOptOutboolean-
switchStatusrequireddata.user.switchStatusstring-One of none, active, past_due, canceled, comp
createdAtrequireddata.user.createdAtstring (date-time)ISO-8601 timestamp (UTC)
updatedAtrequireddata.user.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 }.
  • 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.

Log in with email and password

POST/api/v1/auth/login

Access
Public. No key needed.
Rate limit
20 requests per 5 minutes

Returns an access token, a refresh token and your profile. When two-factor authentication is on, returns { mfaRequired: true, mfaToken } instead: complete the login with POST /auth/2fa/verify. Repeated failures lock the account temporarily.

Request body (application/json)

FieldTypeDescription
emailrequiredstring (email)-
passwordrequiredstring-max 128 chars

Response 200

FieldTypeDescription
datarequiredobject-
accessTokendata.accessTokenstringJWT access token. Send as Authorization: Bearer <token>.
refreshTokendata.refreshTokenstringRefresh token (7 days). Also set as an httpOnly cookie scoped to /api/v1/auth.
expiresIndata.expiresInintegerAccess-token lifetime in seconds (900)
userdata.userobjectSame fields as AccountProfile, shown earlier on this page.
mfaRequireddata.mfaRequiredboolean-One of true
mfaTokendata.mfaTokenstringShort-lived (5 minutes) token to send with a TOTP code to POST /auth/2fa/verify

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.

Complete a two-factor login

POST/api/v1/auth/2fa/verify

Access
Public. No key needed.
Rate limit
15 requests per 5 minutes

Exchanges the mfaToken from login plus an authenticator (or backup) code for a session.

Request body (application/json)

FieldTypeDescription
mfaTokenrequiredstringFrom the login response
coderequiredstring6-digit authenticator code, or one of your backup codes

Response 200

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

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.

Refresh an access token

POST/api/v1/auth/refresh

Access
Public. No key needed.
Rate limit
100 requests per second (the default)

Reads the refresh token from the httpOnly cookie, or from the body for non-browser clients. Rotates the refresh token: store the new one. Cross-site browser requests are refused with CSRF_BLOCKED; a missing token is MISSING_TOKEN.

Request body (application/json)

FieldTypeDescription
refreshTokenstring-

Response 200

FieldTypeDescription
datarequiredobject-
accessTokenrequireddata.accessTokenstringJWT access token. Send as Authorization: Bearer <token>.
refreshTokenrequireddata.refreshTokenstringRefresh token (7 days). Also set as an httpOnly cookie scoped to /api/v1/auth.
expiresInrequireddata.expiresInintegerAccess-token lifetime in seconds (900)

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.
  • AlsoMISSING_TOKEN, CSRF_BLOCKED

Log out the current session

POST/api/v1/auth/logout

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

Revokes only this session (other devices stay signed in) and clears the refresh cookie.

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.
  • 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 active sessions

GET/api/v1/auth/sessions

Access
Dashboard session. API keys are refused with 403. Use a login access token.
Rate limit
100 requests per second (the default)

Signed-in devices, most recently seen first. current marks the one making the request.

Response 200

FieldTypeDescription
datarequiredobject[]-
idrequireddata[].idstring (uuid)-
iprequireddata[].ipstring | null-
userAgentrequireddata[].userAgentstring | null-
createdAtrequireddata[].createdAtstring (date-time)ISO-8601 timestamp (UTC)
lastSeenAtrequireddata[].lastSeenAtstring (date-time) | nullISO-8601 timestamp (UTC)
currentrequireddata[].currentbooleanTrue for the session making this request (matched via the refresh token)

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.

Sign out one session

DELETE/api/v1/auth/sessions/{id}

Access
Dashboard session. API keys are refused with 403. Use a login access token.
Rate limit
100 requests per second (the default)

Parameters

NameInTypeDescription
idrequiredpathstring-

Response 200

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

Sign out every other session

POST/api/v1/auth/sessions/revoke-others

Access
Dashboard session. API keys are refused with 403. Use a login access token.
Rate limit
100 requests per second (the default)

Keeps the current session. Needs the refresh token (cookie or body) to know which session is current; without it the answer is NO_SESSION.

Response 200

FieldTypeDescription
datarequiredobjectSame fields as Message, 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.
  • AlsoNO_SESSION

Verify your email address

POST/api/v1/auth/verify-email

Access
Public. No key needed.
Rate limit
100 requests per second (the default)

Consumes the token from the verification email. Any invite-code test credit is added at this point.

Request body (application/json)

FieldTypeDescription
tokenrequiredstring-

Response 200

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

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.

Confirm an email address change

POST/api/v1/auth/confirm-email-change

Access
Public. No key needed.
Rate limit
10 requests per 10 minutes

Finishes a change requested with POST /account/email, using the token from the link sent to the NEW address. Public on purpose: the single-use token is the proof, so the link works on any device.

Request body (application/json)

FieldTypeDescription
tokenrequiredstringThe token from the confirmation link sent to the new address

Response 200

FieldTypeDescription
datarequiredobject-
emailrequireddata.emailstring (email)The address now on the account

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.

Resend the verification email

POST/api/v1/auth/resend-verification

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

Response 200

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

Redeem an invite code after sign-up

POST/api/v1/auth/invite/redeem

Access
API key. Full-access keys only; not reachable by scoped keys.
Rate limit
10 requests per 10 minutes

For social sign-ups, or a code mistyped at registration. ok: false carries the reason. When the email is not verified yet, the credit is held (pending: true) and added on verification.

Request body (application/json)

FieldTypeDescription
coderequiredstring-max 64 chars

Response 200

FieldTypeDescription
datarequiredobject-
okrequireddata.okboolean-
amountdata.amountmoneyTest credit granted USD as a decimal string with exactly 6 places, e.g. "0.012500".
pendingdata.pendingbooleanTrue when the credit waits for email verification
reasondata.reasonstringWhy the code was not applied

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.

Resend a verification email by address

POST/api/v1/auth/resend-verification-public

Access
Public. No key needed.
Rate limit
5 requests per hour

For users whose link expired and who cannot sign in. Always answers the same way, whether or not the account exists.

Request body (application/json)

FieldTypeDescription
emailrequiredstring (email)-

Response 200

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

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.

Request a password reset email

POST/api/v1/auth/forgot-password

Access
Public. No key needed.
Rate limit
5 requests per hour

Always answers the same way, whether or not the account exists.

Request body (application/json)

FieldTypeDescription
emailrequiredstring (email)-

Response 200

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

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.

Reset your password with a reset token

POST/api/v1/auth/reset-password

Access
Public. No key needed.
Rate limit
15 requests per hour

Request body (application/json)

FieldTypeDescription
tokenrequiredstring-
newPasswordrequiredstring-max 128 chars

Response 200

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

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.

Change your password

POST/api/v1/auth/change-password

Access
Dashboard session. API keys are refused with 403. Use a login access token.
Rate limit
100 requests per second (the default)

Requires the current password. Signs out every session, including this one once its access token expires, and emails a confirmation.

Request body (application/json)

FieldTypeDescription
currentPasswordrequiredstring-
newPasswordrequiredstringAt least 8 characters and different from the current password

Response 200

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

List the social login providers that are enabled

GET/api/v1/auth/oauth/providers

Access
Public. No key needed.
Rate limit
100 requests per second (the default)

Response 200

FieldTypeDescription
datarequiredobject-
googlerequireddata.googleboolean-
linkedinrequireddata.linkedinboolean-

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.

Start a social login

GET/api/v1/auth/oauth/{provider}/start

Access
Public. No key needed.
Rate limit
100 requests per second (the default)

A browser navigation, not an API call. Redirects to the provider; next is a same-site path to land on afterwards.

Parameters

NameInTypeDescription
providerrequiredpathstring-One of google, linkedin
nextquerystringRelative path to open after signing in, e.g. /dashboard

Response 302

Redirect to the provider, or to /login?oauth_error=unavailable when the provider is not configured.

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.

Finish a social login (provider callback)

GET/api/v1/auth/oauth/{provider}/callback

Access
Public. No key needed.
Rate limit
100 requests per second (the default)

Called by the provider after consent. Signs the browser in and redirects into the app, or to /login?oauth_error=... on failure.

Parameters

NameInTypeDescription
providerrequiredpathstring-One of google, linkedin
codequerystring-
statequerystring-
errorquerystring-

Response 302

Redirect into the app when signed in, or to /login with an oauth_error reason.

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.