Curated reference

API Surface by Integration Task

Start here for the endpoints most native checkout integrations need. Use the full OpenAPI reference when you need every schema and response field.

Checkout Sessions and Embedded Checkout

Create checkout sessions from your backend, render the hosted iframe in the browser, and complete buyer-facing payment flows.

POST /api/v1/checkout-sessions/embed-token Server-side

Create a payment-ready proxy checkout session.

X-API-Key Guide
Implementation details

Use this for payment-only provider proxy mode when your application owns cart, shipping, and order summary UI. The response returns a Throttle session id plus hosted and embedded URLs.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
amountintegerYesAmount to charge in minor units, for example 2599 for $25.99.
currencystringYesThree-letter ISO 4217 currency code.
countrystringNoTwo-letter ISO 3166-1 country code. Defaults to US.
Default: US
externalCartIdstringNoYour cart reference. Stored on session metadata for reconciliation.

Responses

200 Session created and embed URLs returned.

Response fields

FieldTypeRequiredDescription
checkoutSessionIdstringYesDurable Throttle session id. Use this as the React embed sessionId.
embedTokenstringYesShort-lived provider embed JWT. The hosted iframe can re-mint it later.
hostedUrlurlYesStandalone hosted checkout URL.
embedUrlurlYesChromeless iframe URL for embedded checkout.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
402 workspace_not_live A production-environment credential was used but the workspace has not completed the go-live flow (lifecycleStage is still sandbox). Use a non-production environment key for sandbox testing, or complete the go-live action in the dashboard to unlock production paths.
402 workspace_not_entitled_for_live A production-environment credential was used but the workspace does not have an active paying subscription (and is not a partner). Production payments are paused. Subscribe (or restore your subscription) from the workspace billing page to accept production payments. Non-production environment keys remain fully functional.
402 trial_expired The workspace trial period has ended and no payment method is on file. Add a payment method and subscribe from the workspace billing page.
400 allowed_methods_unsupported allowedMethods was sent to the payment-only embed-token endpoint. The payment widget renders the methods configured on your connection and cannot be filtered here. Remove allowedMethods. To restrict methods, configure the payment connection, or use the full hosted checkout where allowedMethods filters the selection.
422 no_payment_connection The merchant does not have an active payment connection. Connect a payment processor before creating card checkout sessions.

SDK coverage

@usethrottle/checkout-sdk/server · Server-side SDK. Pair the returned session id with @usethrottle/checkout-sdk in React.

  • createCheckoutClient().createEmbedToken(input)

Never mint embed tokens from the browser. The React SDK renders the session id returned by this server helper.

Create session
curl -X POST https://api.usethrottle.dev/api/v1/checkout-sessions/embed-token \
  -H "x-api-key: $THROTTLE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "amount": 2599,
    "currency": "USD",
    "country": "US",
    "externalCartId": "cart_123"
  }'

Production notes

  • Never call this endpoint directly from a browser; it requires your secret API key.
  • The session id is the durable handle. The embed token is short-lived and can be refreshed by the hosted checkout page.
POST /api/v1/checkout/sessions Server-side

Create a cart-backed hosted checkout session.

X-API-Key Guide
Implementation details

Use this when Throttle owns or can reference the cart that should become an order. This is the preferred session creation path for native carts, subscriptions, collect flags, and full checkout.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
applicationIduuidYesApplication that owns the checkout session.
cartIduuidNoThrottle native cart id. Required unless externalCartId is provided.
externalCartIdstringNoMerchant/provider cart reference. Required unless cartId is provided.
returnUrlurlYesBuyer return URL after hosted checkout success.
cancelUrlurlYesBuyer return URL when checkout is cancelled.
customerEmailstringNoBuyer email used for checkout and recurring setup when customer is not supplied.
customerobjectNoOptional prefill object with customerId, externalCustomerId, email, names, phone, shippingAddress, billingAddress, and metadata.
allowedMethodsstring[]NoOptional card/net30 payment method allowlist for this session.
paymentTerms.netNinteger | nullNoOptional cart-level Invoice Terms override, 0-365. Customer netN still wins; null clears the cart override.
recurringobjectNoSubscription intent: plan, interval, amount, trialDays, planName, and create mode auto/manual.
collectobjectNoControls required checkout fields. shippingAddress defaults to true; billingAddress defaults to false.
discountCodestringNoOptional promotion code to validate and apply synchronously during session creation.
metadataobjectNoUp to 50 keys and 10 KB of merchant-owned JSON metadata.

Responses

201 Checkout session created.

Response fields

FieldTypeRequiredDescription
idstringYesSession id used by hosted checkout and React embed components.
statusopen | completed | expired | cancelledYesSession lifecycle state.
hostedUrl, embedUrlurlNoHosted and iframe-ready checkout URLs when returned by the service.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
402 workspace_not_live A production-environment credential was used but the workspace has not completed the go-live flow (lifecycleStage is still sandbox). Use a non-production environment key for sandbox testing, or complete the go-live action in the dashboard to unlock production paths.
402 workspace_not_entitled_for_live A production-environment credential was used but the workspace does not have an active paying subscription (and is not a partner). Production payments are paused. Subscribe (or restore your subscription) from the workspace billing page to accept production payments. Non-production environment keys remain fully functional.
402 trial_expired The workspace trial period has ended and no payment method is on file. Add a payment method and subscribe from the workspace billing page.
422 discount_invalid discountCode is expired, inactive, over limit, or not valid for this cart. Preview the code first or retry session creation without the code.

SDK coverage

@usethrottle/checkout-sdk/server · Server-side checkout SDK.

  • createCheckoutClient().createSession(input)

@usethrottle/checkout-sdk/server creates the session; @usethrottle/checkout-sdk renders and tracks it in React.

Create cart-backed session
curl -X POST https://api.usethrottle.dev/api/v1/checkout/sessions \
  -H "x-api-key: $THROTTLE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "applicationId": "00000000-0000-0000-0000-000000000000",
    "cartId": "11111111-1111-1111-1111-111111111111",
    "returnUrl": "https://shop.example.com/thank-you",
    "cancelUrl": "https://shop.example.com/cart",
    "allowedMethods": ["card", "net30"],
    "paymentTerms": { "netN": 45 },
    "collect": { "shippingAddress": true, "billingAddress": true }
  }'
GET /api/v1/checkout-sessions/{id}/embed-token Browser-safe

Refresh the iframe embed token for an existing session.

Session id Guide
Implementation details

The hosted checkout app calls this without a merchant API key so buyers can load or reload a checkout after the original embed JWT expires.

Path parameters

FieldTypeRequiredDescription
idstringYesOpen checkout session id.

Responses

200 Fresh embed token and payment processor context.

Response fields

FieldTypeRequiredDescription
embedTokenstringYesFresh provider embed JWT.
amount, currencyinteger, stringNoAmount and currency resolved from session metadata, cart totals, or the latest calculation snapshot.
processorCheckoutSessionIdstringNoProcessor-side checkout session id.
environment'sandbox' | 'production'NoWhich processor environment the token was signed for, resolved from the session. Mount the payment widget against this value — a single checkout front end serves both sandbox and production sessions, so it cannot be a build-time constant.

Common errors

Status Code Cause Fix
404 not_found No checkout session exists for the supplied id. Create a new session and update the iframe src.
410 session_expired The checkout session expired. Return the buyer to your cart and create a new checkout session.
422 session_not_open The session is completed, cancelled, expired, or otherwise not open. Do not re-use completed sessions. Start a new checkout.

Production notes

  • Most workspaces do not call this directly; the hosted checkout and React SDK paths handle refresh during render.
GET /api/v1/checkout-sessions/{id}/payment-methods Browser-safe

List eligible payment methods for a checkout session.

Session id Guide
Implementation details

The iframe uses this to decide which payment method tiles to show. The server checks connector eligibility and then applies the session allowedMethods filter.

Path parameters

FieldTypeRequiredDescription
idstringYesOpen checkout session id.

Responses

200 Eligible payment method list.

Response fields

FieldTypeRequiredDescription
methods[].methodcard | net30 | stringYesPayment method key used by the completion payload.
methods[].displayNamestringYesBuyer-facing method label.
methods[].connectorIdstringNoConnector that supplied the method.
unavailableReasonobject | undefinedNoOnly present when methods is empty AND a provider is connected but currently renders nothing (e.g. not configured for this environment yet). Contains { code, message }; show message to the buyer instead of a generic empty state.

Common errors

Status Code Cause Fix
404 session_not_found The session id is unknown. Create a new session and re-render checkout.
POST /api/v1/checkout-sessions/{id}/complete Browser-safe

Complete a buyer-facing checkout session.

Session id Guide
Implementation details

Called by the hosted iframe after the buyer submits payment. The session id scopes the operation; your backend should listen for webhooks rather than calling this directly.

Headers

FieldTypeRequiredDescription
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
idstringYesOpen checkout session id.

Request body

FieldTypeRequiredDescription
paymentMethodcard | gr4vy | net30YesCompletion path selected by the buyer.
emailstringNoBuyer email. Required for card and net30 modes when not already collected.
shippingAddressobjectNoShipping address object when the session collect flags require it.
billingAddressobjectNoBilling address object when the session collect flags require it.
paymentTokenstringNoCard payment token for the unified card path.
processorTransactionIdstringNoProvider transaction id for proxy mode.
net30AcceptanceobjectNotermsHash, acceptedAt, companyName, and billingEmail for Net 30 checkout.

Responses

200 Checkout completed.

Response fields

FieldTypeRequiredDescription
orderIduuidYesCreated or updated order id.
paymentIduuidYesPayment record created for the completed checkout.
subscriptionIduuidNoReturned when recurring create:auto creates a subscription.

Common errors

Status Code Cause Fix
404 not_found Session does not exist. Create a fresh checkout session.
422 missing_required_field The session collect flags require email, shipping, billing, or payment-specific fields. Collect the required fields in the iframe or supply them in the completion payload.
402 payment_failed The processor declined or failed the payment. Show the buyer the failure message and let them retry with a different method.
409 checkout_in_progress Another completion for this session is already in flight. Completion is single-flight to prevent a double charge. Do not submit the same session twice concurrently. Wait for the in-flight completion to resolve; retry only after a returned failure.

SDK coverage

@usethrottle/checkout-sdk/server · Server-side checkout SDK for authenticated proxy-mode completion.

  • createCheckoutClient().completeSession(sessionId, input)

Most storefronts let the hosted iframe call the public complete route. Use the SDK when your backend intentionally owns the completion step.

Carts and Items

Create native carts, mutate line items, select shipping, persist taxes, and convert carts into orders.

POST /api/v1/carts Server-side

Create a native Throttle cart.

X-API-Key Guide
Implementation details

Start here when Throttle should own cart state before checkout. Create the cart from your backend, then add items and calculate totals before converting it to an order.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
applicationIduuidYesApplication that owns the cart.
customerIduuidNoOptional Throttle customer id to attach to the cart.
customerEmailstringNoOptional lightweight email capture (no full customer record). Makes an otherwise-anonymous abandoned cart recoverable. A linked customer’s email takes precedence.
currencystringNoThree-letter currency code.
Default: USD
metadataobjectNoMerchant-owned JSON metadata.

Responses

201 Cart created.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.carts.create(input)
  • client.carts.get(id)
  • client.carts.update(id, input)

The SDK uses camelCase input fields such as applicationId and unitPrice, then maps to the REST API.

GET /api/v1/carts/{id} Server-side

Fetch a cart snapshot.

X-API-Key Guide
Implementation details

Read the current cart, including totals, line items, selected shipping, tax lines, and applied discount state.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Responses

200 Cart snapshot returned.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 cart_not_found The cart id is invalid or belongs to another merchant. Confirm the cart id and API key merchant match.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.carts.get(id)

Use after mutations when your backend needs the authoritative cart snapshot.

PATCH /api/v1/carts/{id} Server-side

Update cart-level buyer and metadata fields.

X-API-Key Guide
Implementation details

Patch the customer id, addresses, notes, or metadata on an open native cart.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Request body

FieldTypeRequiredDescription
customerIduuidNoThrottle customer id.
customerEmailstringNoLightweight email capture; pass null to clear.
shippingAddressCartAddressNoCanonical address (required addressLine1, city, countryCode). Non-canonical keys are rejected at write time.
billingAddressCartAddressNoCanonical address (same shape as shippingAddress).
notesstringNoInternal cart notes.
metadataobjectNoMerchant-owned JSON metadata.

Responses

200 Updated cart returned.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.carts.update(id, input)

SDK input names are camelCase: customerId, billingAddress, shippingAddress.

POST /api/v1/carts/{id}/items Server-side

Add a line item to a cart.

X-API-Key Guide
Implementation details

Use this for products, services, tickets, donations, custom items, and subscription line items before checkout.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Request body

FieldTypeRequiredDescription
typeproduct | subscription | service | ticket | donation | customNoLine item type.
Default: product
referenceIdstringNoYour SKU, plan id, ticket id, or other external item reference.
namestringYesBuyer-facing item name.
descriptionstringNoOptional item description.
unitPriceintegerYesUnit price in minor units (cents).
quantityintegerNoQuantity, minimum 1.
Default: 1
taxAmountintegerNoOptional item tax amount in minor units.
discountAmountintegerNoOptional item discount amount in minor units.
imageUrlstringNoOptional product image. Accepts an absolute http(s) URL or a relative path (e.g. "/images/x.png"). Relative paths are resolved to an absolute URL against the application storefront base URL (set storefrontBaseUrl via PUT /v1/embed-config; falls back to the first allowedOrigin) so the image renders on the hosted checkout.
requiresShippingbooleanNoWhether this item is physically shippable. For external/ad-hoc catalogs with no Throttle product behind the item. Omit to infer from type (everything except service ships); set explicitly to force-include or force-exclude the item from calculated shipping.
metadataobjectNoMerchant-owned item metadata.

Responses

201 Line item added.

Response fields

FieldTypeRequiredDescription
iduuidYesLine item id.
namestringYesItem name.
unitPrice, quantity, totalintegerNoPricing fields in minor units.
metadataobjectNoItem metadata.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 cart_not_found The cart id is invalid or belongs to another merchant. Read the cart before mutating it and confirm you are using the correct merchant API key.
400 image_url_unresolvable imageUrl is a relative path but the application has no storefront base URL to resolve it against. Send an absolute http(s) imageUrl, or set storefrontBaseUrl via PUT /v1/embed-config (the first allowedOrigin is used as a fallback).

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.items.add(cartId, input)
  • client.items.update(cartId, itemId, input)
  • client.items.remove(cartId, itemId)

SDK inputs use camelCase: referenceId, unitPrice, taxAmount, discountAmount, imageUrl, requiresShipping.

PATCH /api/v1/carts/{cartId}/items/{id} Server-side

Update a line item.

X-API-Key Guide
Implementation details

Patch quantity, price, tax, discount, or metadata for an existing cart line item.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
cartIduuidYesCart id.
iduuidYesLine item id.

Request body

FieldTypeRequiredDescription
quantityintegerNoQuantity, minimum 1.
unitPriceintegerNoUnit price in minor units.
taxAmountintegerNoTax amount in minor units.
discountAmountintegerNoDiscount amount in minor units.
metadataobjectNoReplacement item metadata.

Responses

200 Updated line item returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.items.update(cartId, itemId, input)

SDK input names are camelCase, matching the wire format.

DELETE /api/v1/carts/{cartId}/items/{id} Server-side

Remove a line item.

X-API-Key Guide
Implementation details

Deletes a line item from an open native cart.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
cartIduuidYesCart id.
iduuidYesLine item id.

Responses

204 Line item removed. No JSON body is returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.items.remove(cartId, itemId)

Read the cart after removal if your backend needs recalculated totals.

POST /api/v1/carts/{id}/shipping Server-side

Select a shipping method for a cart.

X-API-Key Guide
Implementation details

Persist the buyer-selected shipping option before final checkout. Use the id returned from shipping/tax calculation when possible.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Request body

FieldTypeRequiredDescription
methodIdstringYesShipping method id.
displayNamestringYesBuyer-facing shipping label.
rateAmountintegerYesShipping rate in minor units.
currencystringNoThree-letter currency code.
carrierstringNoOptional carrier name.
serviceCodestringNoOptional carrier service code.
estimatedDeliveryDaysintegerNoOptional delivery estimate in days.

Responses

200 Cart returned with selectedShipping populated.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.shipping.select(cartId, input)
  • client.shipping.clear(cartId)

Call clear when the buyer changes address and the previous method is no longer valid.

DELETE /api/v1/carts/{id}/shipping Server-side

Clear selected shipping from a cart.

X-API-Key Guide
Implementation details

Use when the buyer changes address, shipping is no longer required, or the selected method is no longer available.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Responses

200 Cart returned with selectedShipping cleared.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.shipping.clear(cartId)

Recalculate totals after clearing shipping if payment amount depends on shipping.

PUT /api/v1/carts/{id}/tax-lines Server-side

Replace tax lines on a cart.

X-API-Key Guide
Implementation details

Use this when you bring your own tax calculation and need to persist the final line-level tax breakdown on a native cart.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Request body

FieldTypeRequiredDescription
linesarrayYesComplete replacement list of tax lines.
lines[].lineItemIduuidYesLine item receiving the tax.
lines[].jurisdictionCodestringYesTax jurisdiction code.
lines[].jurisdictionNamestringNoHuman-readable jurisdiction name.
lines[].taxTypesales | vat | gst | pst | hst | service | excise | otherYesTax category.
lines[].ratenumberYesDecimal rate between 0 and 1.
lines[].amountintegerYesTax amount in minor units.
lines[].currencystringNoThree-letter currency code.

Responses

200 Cart returned with replacement taxLines.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.taxLines.set(cartId, lines)
  • client.taxLines.clear(cartId)

This is a full replacement operation, not a patch.

DELETE /api/v1/carts/{id}/tax-lines Server-side

Clear all tax lines from a cart.

X-API-Key Guide
Implementation details

Remove persisted tax lines when the cart address changes, the tax mode changes, or you need to recompute taxes from scratch.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Responses

200 Cart returned with taxLines cleared.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.taxLines.clear(cartId)

This removes every tax line on the cart.

POST /api/v1/carts/{id}/apply-discount Server-side

Apply a promotion code to a cart.

X-API-Key Guide
Implementation details

Validates a code and writes the active applied discount snapshot onto the cart. A cart can have one active code; applying a new valid code replaces the old one.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Request body

FieldTypeRequiredDescription
codestringYesPromotion code to apply.

Responses

200 Cart returned with appliedDiscount populated.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
422 discount_invalid The code is inactive, expired, over usage limits, or not valid for the cart/customer. Keep the existing cart state and show the buyer the returned message.

SDK coverage

@usethrottle/discounts or @usethrottle/cart · Server-side Node clients.

  • discounts.applyToCart(cartId, code)
  • cartClient.discounts.apply(cartId, code)

Use @usethrottle/discounts when discounts are your main workflow; use @usethrottle/cart inside cart orchestration.

DELETE /api/v1/carts/{id}/discount Server-side

Remove the active promotion code from a cart.

X-API-Key Guide
Implementation details

Clears the applied discount snapshot and returns the cart without an active promotion code.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Responses

200 Cart returned with appliedDiscount cleared.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle cart identifier used by all cart mutation endpoints.
statusopen | checkout | converted | abandonedYesCurrent cart lifecycle state. Only open carts should be mutated.
currencystringYesISO 4217 currency used for all cart totals.
subtotal, taxTotal, discountTotal, shippingTotal, totalintegerYesCart totals in minor units.
lineItemsarrayNoLine items included when reading a cart or after item mutations.
appliedDiscountobject | nullNoSnapshot of the active promotion code, if one is applied.
selectedShippingobject | nullNoSelected shipping method and rate, if one has been selected.
taxLinesarrayNoTax line breakdown persisted on the cart.
metadataobjectNoMerchant-owned JSON metadata returned unchanged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/discounts or @usethrottle/cart · Server-side Node clients.

  • discounts.removeFromCart(cartId)
  • cartClient.discounts.remove(cartId)

Recalculate totals after removal if the buyer remains in checkout.

POST /api/v1/carts/{id}/checkout Server-side

Convert a cart into an order.

X-API-Key Guide
Implementation details

Call after items, discount, shipping, and final tax calculation are ready. This creates the order that payment and fulfillment workflows use.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Request body

FieldTypeRequiredDescription
paymentMethodstringNoOptional selected payment method such as card or net30.
metadataobjectNoOptional checkout metadata.

Responses

201 Order created from cart.

Response fields

FieldTypeRequiredDescription
iduuidYesOrder id.
orderNumberstringNoMerchant-visible order number.
statusdraftNoInitial order status.
subtotal, totalintegerNoOrder totals in minor units.
cartIduuidNoSource cart id.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
400 cart_not_ready The cart is missing required checkout state or cannot be converted. Confirm items exist and final totals have been calculated before checkout.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.carts.checkout(cartId, input)

Run shippingTax.calculateCart with kind checkout_final before checkout when Throttle calculates totals.

GET /api/v1/carts/{id}/events Server-side

Read immutable cart events.

X-API-Key Guide
Implementation details

Use cart events for polling/debugging cart mutations. For real-time delivery, subscribe to outbound webhooks.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesCart id.

Query parameters

FieldTypeRequiredDescription
sinceSequenceintegerNoReturn events after this sequence.
limitintegerNoPage size, 1 to 200.

Responses

200 Ordered cart event list.

Response fields

FieldTypeRequiredDescription
iduuidYesEvent id.
eventTypestringYesEvent name such as cart.item_added.
sequenceintegerYesMonotonic per-cart sequence.
payloadobjectNoEvent payload.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.events.list(cartId, { sinceSequence, limit })

Store the last sequence you processed if you poll events.

GET /api/v1/abandoned-carts Server-side

List abandoned carts (most-recently abandoned first).

X-API-Key
Implementation details

Carts that the sweep flagged abandoned, newest first. Cursor-paginated. A cart becomes abandoned after the per-app idle threshold (see embed-config `cartAbandonmentThresholdMinutes`) or once it passes its expiry.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
limitintegerNoPage size, 1 to 100 (default 25).
cursorstringNoOpaque cursor from the previous page.

Responses

200 Cursor-paginated abandoned carts.

Response fields

FieldTypeRequiredDescription
iduuidYesCart id.
customerobject | nullNoBuyer identity ({ id, email, firstName }) or null for an anonymous cart.
totalintegerNoCart total in minor units (cents).
currencystringNoISO-4217 currency code.
itemCountintegerNoNumber of line items.
abandonedAtstring | nullNoISO-8601 timestamp the cart was marked abandoned.
recoveryStatusstringNoWhether a recovery email was sent, or recovery is webhook-only.
Values: emailed, webhook_only
GET /api/v1/abandoned-carts/summary Server-side

Abandoned-cart summary metrics for a trailing window.

X-API-Key
Implementation details

Headline counts for the abandoned-carts dashboard over a trailing window.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
sinceDaysintegerNoTrailing window in days, 1 to 365 (default 30).

Responses

200 Summary metrics.

Response fields

FieldTypeRequiredDescription
sinceDaysintegerNoWindow applied.
abandonedCountintegerNoCarts abandoned in the window.
abandonedValueintegerNoSum of abandoned-cart totals in minor units (cents).
recoveryEmailsSentintegerNoRecovery emails dispatched in the window.
POST /api/v1/shipping-tax/external-snapshots Server-side

Push provider-owned shipping/tax totals.

X-API-Key Guide
Implementation details

Use when your application is in bring-your-own shipping or tax mode and an upstream provider owns the final totals.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
applicationIduuidYesApplication receiving the snapshot.
cartIduuid | nullNoOptional Throttle cart to mirror totals onto.
checkoutSessionIdstring | nullNoOptional checkout session reference.
orderIduuid | nullNoOptional order reference.
currencystringNoThree-letter currency code.
totalsobjectYessubtotal, discountTotal, shippingTotal, taxTotal, and total in minor units.
selectedShippingobject | nullNoProvider-selected shipping snapshot.
taxLinesarrayNoProvider tax line breakdown.
sourcestringNoProvider/source label for audit.

Responses

200 External snapshot accepted and calculation response returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
422 external_snapshot_not_allowed Neither shipping nor tax mode is configured for bring-your-own totals. Switch at least one axis to byo mode before pushing external totals.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.shippingTax.pushExternalSnapshot(input)

This is for provider-owned totals; native Throttle carts usually use calculateCart instead.

Discounts

Manage percentage and fixed amount promotion codes, preview them without mutation, and apply them to native carts.

POST /api/v1/discounts Server-side

Create a discount.

X-API-Key Guide
Implementation details

Creates a percentage or fixed amount discount code for later preview and cart application.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
codestringNoPromotion code. Leave empty for automatic discounts.
namestringYesHuman-readable discount name.
typepercentage | fixed_amountYesDiscount type.
valueintegerYesWhole percent for percentage discounts, or minor units for fixed amount discounts.
conditionsobjectNoOptional conditions such as minOrder.
usageLimitintegerNoOptional global usage cap.
maxRedemptionsPerCustomerinteger | nullNoPer-customer redemption cap. Use null for unlimited.
Default: 1
startsAt, endsAtdate-timeNoOptional active window.
metadataobjectNoCampaign or attribution metadata.

Responses

201 Discount created.

Response fields

FieldTypeRequiredDescription
iduuidYesDiscount id.
codestringNoPromotion code.
type, valuestring, integerNoDiscount calculation fields.
isActivebooleanNoWhether the code can be used.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/discounts · Server-side Node client.

  • discounts.create(input)
  • discounts.list(filters)

Use the SDK from API routes, server actions, workers, or backend services only.

GET /api/v1/discounts Server-side

List discounts.

X-API-Key Guide
Implementation details

Use for promotion management screens, campaign reconciliation, or validating which codes exist before checkout.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
cursorstringNoCursor for pagination.
limitintegerNoPage size, 1 to 100.
Default: 10
isActivebooleanNoFilter by active state.
codestringNoFilter by promotion code.
typepercentage | fixed_amountNoFilter by type.
qstringNoSearch code, name, type, or metadata.
sortasc | descNoSort by creation time.

Responses

200 Paginated discount list returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/discounts · Server-side Node client.

  • discounts.list(filters)
  • discounts.get(id)

Use cursor pagination for management UIs.

PATCH /api/v1/discounts/{id} Server-side

Update a discount.

X-API-Key Guide
Implementation details

Patch campaign metadata, active windows, usage limits, or the display name for an existing discount.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesDiscount id.

Request body

FieldTypeRequiredDescription
codestringNoPromotion code.
namestringNoHuman-readable discount name.
valueintegerNoUpdated percent or fixed amount value.
conditionsobjectNoReplacement conditions object.
usageLimitintegerNoUpdated global usage cap.
maxRedemptionsPerCustomerinteger | nullNoUpdated per-customer cap.
startsAt, endsAtdate-timeNoUpdated active window.
metadataobjectNoReplacement metadata.

Responses

200 Updated discount returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/discounts · Server-side Node client.

  • discounts.update(id, input)

Existing cart snapshots keep the discount values captured when the code was applied.

DELETE /api/v1/discounts/{id} Server-side

Deactivate or delete a discount.

X-API-Key Guide
Implementation details

Removes a discount from future use. Existing orders keep their historical discount snapshot.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesDiscount id.

Responses

204 Discount removed. No JSON body is returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/discounts · Server-side Node client.

  • discounts.delete(id)

Prefer deactivation semantics in your UI copy if historical redemptions matter.

POST /api/v1/discounts/preview Server-side

Preview a code without mutating a cart.

X-API-Key Guide
Implementation details

Call while the buyer types a code in your storefront. Preview returns the computed discount and final total without changing cart or usage counts.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
codestringYesPromotion code to preview.
currencystringYesThree-letter currency code.
subtotalintegerYesCurrent subtotal in minor units.
customerIduuidNoOptional customer id for redemption-limit checks.
lineItemsarrayNoOptional line item context for future item-level conditions.

Responses

200 Preview result.

Response fields

FieldTypeRequiredDescription
validbooleanYesWhether the code can currently be applied.
codestringNoNormalized code.
discountTotalintegerNoDiscount amount in minor units.
totalintegerNoSubtotal minus discount.
messagestringNoBuyer-safe reason when invalid.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/discounts · Server-side Node client.

  • discounts.preview(input)

Preview is safe to call repeatedly because it does not mutate usage counts.

Shipping and Tax

Issue storefront quote tokens, estimate buyer totals, and calculate or persist cart totals before checkout.

GET /api/v1/shipping-tax/config Setup

Read draft and published shipping/tax config.

X-API-Key Guide
Implementation details

Use setup tooling or advanced dashboards to show the active shipping/tax modes and catalog for an application.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
applicationIduuidYesApplication id to read config for.

Responses

200 Draft and published configs returned.

Response fields

FieldTypeRequiredDescription
draftobject | nullNoEditable config draft.
publishedobject | nullNoPublished config used by calculations.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
400 missing_application_id applicationId query parameter is missing. Pass applicationId in the query string.
GET /api/v1/shipping-tax/quote-tokens Setup

List publishable quote tokens for an application.

X-API-Key Guide
Implementation details

Use during setup to audit active quote tokens. Raw token values are not returned after creation.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
applicationIduuidYesApplication id to list tokens for.

Responses

200 Quote token metadata list returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/shipping-tax/quote-tokens Setup

Create a publishable storefront quote token.

X-API-Key Guide
Implementation details

Quote tokens start with pk_ and let a storefront request read-only estimates without exposing a secret key.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
applicationIduuidYesApplication the token can quote for.
namestringYesInternal token label, 1 to 80 characters.
expiresAtdate-time | nullNoOptional expiration time.

Responses

200 Token created. rawToken is shown once.

Response fields

FieldTypeRequiredDescription
rawTokenstringYesPublishable pk_ token. Store it safely client-side.
tokenPrefixstringNoPrefix shown later for identification.
expiresAtdate-time | nullNoExpiration time.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 store_not_found The application id does not belong to the authenticated workspace. Use a valid application id for this workspace.
DELETE /api/v1/shipping-tax/quote-tokens/{tokenId} Setup

Revoke a storefront quote token.

X-API-Key Guide
Implementation details

Soft-deletes and deactivates a pk_ token so storefront quote requests using it stop working.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
tokenIduuidYesQuote token id.

Responses

200 Revocation confirmation.

Response fields

FieldTypeRequiredDescription
iduuidNoRevoked token id.
revokedbooleanNoAlways true on success.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/shipping-tax/quotes Browser-safe

Request a storefront shipping/tax estimate.

Publishable quote token Guide
Implementation details

Use from the browser or your backend for read-only estimates. It validates the pk_ quote token, application id, expiry, and allowed origin.

Headers

FieldTypeRequiredDescription
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
applicationIduuidYesApplication being quoted.
quoteTokenstringYesPublishable pk_ token for this application.
currencystringNoThree-letter currency code. Defaults to application currency or USD.
itemsarrayYesAt least one item to quote.
items[].idstringYesSKU or item id.
items[].subtotalAmountintegerYesLine subtotal in minor units.
items[].quantityintegerNoQuantity, minimum 1.
Default: 1
items[].requiresShippingbooleanNoWhether the item needs shipping rates.
items[].taxCategorystringNoTax category used by configured rules.
discountsTotalintegerNoDiscount total in minor units.
selectedShippingMethodIdstring | nullNoMethod id selected by the buyer.
addresses.shippingobject | nullNoShipping address fields such as countryCode, stateProvince, postalCode.
addresses.billingobject | nullNoBilling address for tax rules that use billing address.

Responses

200 Estimated shipping/tax calculation.

Response fields

FieldTypeRequiredDescription
kindquoteYesCalculation kind.
statusestimated | final | failedYesCalculation status.
shipping.methodsarrayNoAvailable shipping or pickup methods.
tax.taxTotalintegerNoTax total in minor units.
totals.totalintegerNoEstimated final total in minor units.
prompts, warnings, errorsarrayNoMissing info and calculation feedback.

Common errors

Status Code Cause Fix
401 invalid_quote_token Token is wrong, expired, for another application, or the request origin is not allowed. Create a new token and add your storefront origin to the merchant allowlist.
404 store_not_found The application id is unknown. Use the application id tied to the quote token.

SDK coverage

@usethrottle/cart · Browser-safe or backend quote helper.

  • new StorefrontQuoteClient(opts).quote(input)

StorefrontQuoteClient uses the pk_ token, not your secret API key.

POST /api/v1/shipping-tax/carts/{cartId}/calculate Server-side

Calculate shipping/tax for a native cart.

X-API-Key Guide
Implementation details

Use this from your backend when a Throttle cart exists. Persist checkout_final totals before cart checkout so payment receives locked totals. Pass shippingAddress/billingAddress inline to set the destination and calculate in one request — they are persisted to the cart before calculation, so a separate PATCH /carts/{id} is not required. Unknown fields are rejected with a 400 validation_error.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
cartIduuidYesCart id.

Request body

FieldTypeRequiredDescription
kindcart_estimate | checkout_finalNoEstimate during browsing or final lock before payment.
Default: cart_estimate
selectedShippingMethodIdstring | nullNoBuyer-selected method id to include in final totals.
persistbooleanNoPersist calculation snapshot and mirror selected shipping/tax lines onto the cart when supported.
shippingAddressobject | nullNoOptional inline shipping destination (countryCode, stateProvince, postalCode, city, addressLine1/2). Persisted to the cart before calculation, so you can set the address and get rates in one call instead of a separate PATCH /carts/{id}.
billingAddressobject | nullNoOptional inline billing address; persisted to the cart before calculation.
taxDatestring (YYYY-MM-DD)NoTax the sale at the rate in force on this date instead of today — a back-dated invoice, or a correction re-issued after a rate change. Omit for an ordinary sale. Set the same value on order metadata (metadata.taxDate) so the filed document is taxed as of the date the buyer was quoted. Secret-key only: the publishable-token quote endpoint does not accept it.

Responses

200 Cart calculation response.

Response fields

FieldTypeRequiredDescription
snapshotIduuidNoPersisted snapshot id when a snapshot is stored.
shipping.methodsarrayNoAvailable shipping methods.
shipping.selectedMethodobject | nullNoSelected method if supplied.
tax.linesarrayNoTax line breakdown.
totalsobjectNosubtotal, discountTotal, shippingTotal, taxTotal, and total.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cart · Server-side Node client.

  • client.shippingTax.calculateCart(cartId, input)

Use kind checkout_final after the buyer commits to shipping and payment.

Orders and Payments

Read orders and payments from your backend, issue refunds, retrieve Net 30 invoice PDFs, and resend invoice emails.

PATCH /api/v1/orders/{id}/line-items Server-side

Edit an order’s line items (add / update / remove).

X-API-Key
Implementation details

Add, update (quantity/unitPrice), or remove line items and recompute the order total. On a captured order the total delta is settled automatically: an increase charges the customer’s stored card for the difference; a decrease refunds it (capped at the captured amount). Draft/pending orders edit freely with no money movement. Terminal orders (cancelled/refunded/voided) reject.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Request body

FieldTypeRequiredDescription
addarrayNoNew line items: [{ name, unitPrice, quantity, referenceId? }].
updatearrayNoEdits: [{ lineItemId, quantity?, unitPrice? }].
removearrayNoLine item ids to remove.

Responses

200 The updated order with items + an adjustment { delta, previousTotal, newTotal, chargedPaymentId?, refundedPaymentId? }.
402 payment_failed — the delta charge on the stored card was declined.
409 order_not_editable — the order is in a terminal state.
GET /api/v1/orders Server-side

List orders.

X-API-Key
Implementation details

Use for order history, reconciliation, and merchant-side operations dashboards.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
cursorstringNoCursor for pagination.
limitintegerNoPage size, 1 to 100.
Default: 20
statusdraft | pending | processing | partially_fulfilled | fulfilled | cancelled | closedNoOptional status filter.
paymentStatuspending | authorized | captured | partially_paid | partially_refunded | refunded | failed | voidedNoOptional payment status filter.
qstringNoSearch order id, order number, status, source, discount code, or metadata.
customerIduuidNoOptional customer filter.
applicationIduuidNoOptional application filter.

Responses

200 Paginated order list.

Response fields

FieldTypeRequiredDescription
data[]arrayNoOrder records.
meta.pagination.cursorstring | nullNoCursor for the next page.
meta.pagination.hasMorebooleanNoWhether another page exists.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/api-client · Server-side generated REST client.

  • Generated client method for GET /api/v1/orders

For native cart checkout, most applications use webhooks for durable order updates and list APIs for reconciliation.

GET /api/v1/orders/{id} Server-side

Fetch an order and its line items.

X-API-Key
Implementation details

Use for order detail pages, reconciliation, fulfillment handoff, and support tooling.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Responses

200 Order detail returned.

Response fields

FieldTypeRequiredDescription
iduuidNoOrder id.
statusstringNoOrder lifecycle state.
lineItemsarrayNoOrder line items.
subtotal, totalintegerNoOrder totals in minor units.
metadataobjectNoOrder metadata.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 not_found The order id is unknown or belongs to another merchant. Verify the order id and merchant API key.

SDK coverage

@usethrottle/checkout-sdk/server · Server-side checkout SDK.

  • createCheckoutClient().getOrder(id)
  • createCheckoutClient().getOrderWithPayments(id)

Prefer webhooks for state changes; read the order when rendering a confirmation page or reconciling checkout success.

POST /api/v1/orders/{id}/status Server-side

Set an order lifecycle status.

X-API-Key
Implementation details

Moves an order to any status in the lifecycle vocabulary, in either direction. Unlike the automatic transitions the engine applies, this accepts any target — a merchant correcting a mis-shipped order needs to move it back. Side effects already applied (captured payments, sent emails, shipped fulfillments) are never rewound; the status label changes, the history records who changed it and why.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Request body

FieldTypeRequiredDescription
statusstringYesOne of draft, pending, processing, partially_fulfilled, fulfilled, cancelled, closed.
reasonstringNoFree-text note stored on the status-history row. Max 500 characters.

Responses

200 The updated order.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 not_found The order id is unknown or belongs to another merchant. Verify the order id and merchant API key.
GET /api/v1/orders/{id}/status-history Server-side

List every status change on an order.

X-API-Key
Implementation details

Append-only audit trail, oldest first. Each row carries fromStatus, toStatus, actorType (user | system | integration), actorId, reason, and source (manual | state_machine | fulfillment | payment | migration).

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Responses

200 Array of status-history rows, oldest first.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 not_found The order id is unknown or belongs to another merchant. Verify the order id and merchant API key.
POST /api/v1/orders/{id}/payments/record Server-side

Record money that arrived outside Throttle.

X-API-Key
Implementation details

Cash at the counter, a bank transfer to the merchant's own account, a cheque. The payment is created already captured, so the order advances exactly as a processor capture would — paymentStatus rolls up, fulfillment unblocks, receipts send. No processor is contacted and no card is charged. A draft order is placed by the recording, so cash against an order created through the API needs no separate checkout call. These payments are excluded from billable GMV. Requires the payment_records:write scope and the application:payments:record permission (admin or finance).

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder the money is for.

Request body

FieldTypeRequiredDescription
amountintegerYesMinor units, at least 1. Part-payments roll up to partially_paid; paying more than the balance settles it.
currencystringNoDefaults to the order's currency.
methodstringYescash | bank_transfer | cheque | external.
receivedAtstringNoISO 8601 date-time the money actually arrived. Defaults to now.
referencestringNoCheque number, till id, wire reference. Max 120 characters.
notestringNoFree-text note. Max 500 characters.

Responses

200 The created payment, already captured, with processor "manual".

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
422 invalid_order_state The order is cancelled or closed, so there is no lifecycle left to advance. Reopen the order first with POST /v1/orders/{id}/status, then record the payment.
Record a cheque
curl -X POST https://api.usethrottle.dev/api/v1/orders/ord_abc/payments/record \
  -H "X-API-Key: $THROTTLE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 20000, "method": "cheque", "reference": "0114", "note": "Collected at pickup" }'
POST /api/v1/orders/{id}/comp Server-side

Waive the order's remaining balance.

X-API-Key
Implementation details

A comp waives what the buyer still owes. Money already captured stays captured. Nothing is sent to a payment processor and the buyer is never charged. `compAmount` is set to the outstanding balance; `total` is NOT reduced, because the order is still a sale of that size — the comp is a credit recorded against it, and what the buyer owes is `total - compAmount`, so `paymentStatus` settles at `captured` and `displayStatus` reads "… · Comped". The amount is never accepted from the caller — only the reason is. Anything still claiming the waived balance is settled: open authorizations are voided, and unpaid Net-N invoices are voided and their buyers emailed. Requires the order_comps:write scope and the application:orders:comp permission (admin or finance).

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Request body

FieldTypeRequiredDescription
reasonstringYesWhy the balance is being waived. 3–500 characters. Stored on the status history.

Responses

200 The updated order, plus `paymentActions`: one row per void attempted, each { paymentId, action: "void", status: "succeeded" | "failed", error? }. A failed void never undoes the comp.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
422 validation_error The order owes nothing, or is already comped, or is cancelled/refunded. Comp only an order with an outstanding balance.
Comp an order
curl -X POST https://api.usethrottle.dev/api/v1/orders/ord_abc/comp \
  -H "X-API-Key: $THROTTLE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Warranty replacement" }'
POST /api/v1/orders/{id}/comp/reverse Server-side

Undo a comp.

X-API-Key
Implementation details

The order owes what it owed again: `compAmount` returns to 0, `total` is restored, and `paymentStatus` falls back out of `captured` on its own. Side effects of the comp are NOT rewound — an authorization voided at the processor cannot be un-voided, and a voided Net-N invoice is not reissued, so collecting the restored balance means taking a fresh payment. A tax return filed for the comp is reversed by retrying it: POST /v1/tax-documents/{id}/retry. Requires the order_comps:write scope and the application:orders:comp permission.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Responses

200 The updated order with compAmount 0 and its total restored.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
422 validation_error The order has no comp to reverse. Read the order and check compAmount is greater than 0 first.
Reverse a comp
curl -X POST https://api.usethrottle.dev/api/v1/orders/ord_abc/comp/reverse \
  -H "X-API-Key: $THROTTLE_SECRET_KEY"
GET /api/v1/payments Server-side

List payments for the calling merchant.

X-API-Key
Implementation details

Returns all payments scoped to the calling application, cursor-paginated by createdAt DESC. Filter by `method` (e.g. net30, card), `status` (repeat the param for multi-status OR logic), `order_id` (UUID — returns payments for a specific order), `due_from` / `due_to` (YYYY-MM-DD ISO dates that filter on `metadata.dueDate`), `amount_min` / `amount_max` (integer cents, inclusive bounds), `aging` (Net-N aging bucket: `0_30 | 31_60 | 61_90 | 90_plus`), `limit` (page size), and `cursor` (opaque continuation token from the previous response).

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
methodstringNoFilter by payment method (e.g. net30, card, manual, external).
statusstringNoFilter by payment status. Repeat the parameter for multi-status OR logic (e.g. status=authorized&status=captured).
order_iduuidNoReturn payments belonging to a specific order.
due_fromYYYY-MM-DDNoInclusive lower bound on metadata.dueDate (ISO date).
due_toYYYY-MM-DDNoInclusive upper bound on metadata.dueDate (ISO date).
amount_minintegerNoInclusive minimum payment amount in minor currency units (cents).
amount_maxintegerNoInclusive maximum payment amount in minor currency units (cents).
aging0_30 | 31_60 | 61_90 | 90_plusNoFilter to a Net-N aging bucket based on days since the invoice due date.
limitintegerNoPage size, 1 to 100.
Default: 20
cursorstringNoOpaque pagination cursor returned by the previous response.

Responses

200 Payments matching the filters, ordered by createdAt DESC.

Response fields

FieldTypeRequiredDescription
data[]arrayNoPayment records.
meta.pagination.cursorstring | nullNoCursor for the next page, or null when no further pages exist.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
GET /api/v1/orders/{id}/payments Server-side

List payments for an order.

X-API-Key
Implementation details

Use when you need to show payment state, processor references, refunds, or Net 30 state for a specific order.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Responses

200 Payments attached to the order.

Response fields

FieldTypeRequiredDescription
iduuidNoPayment id.
statusstringNoPayment status.
amount, currencyinteger, stringNoPayment amount and currency.
methodcard | net30 | manual | external | ...NoPayment method.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/checkout-sdk/server · Server-side checkout SDK.

  • createCheckoutClient().listOrderPayments(orderId)
  • createCheckoutClient().getOrderWithPayments(orderId)

Use getOrderWithPayments when your confirmation route needs order, payment, and transaction state in one helper.

GET /api/v1/payments/{id}/transactions Server-side

List processor transactions for a payment.

X-API-Key
Implementation details

Use when you need capture, authorization, refund, or failure transaction details for reconciliation and support tooling.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesPayment id.

Responses

200 Payment transactions returned.

Response fields

FieldTypeRequiredDescription
iduuidNoTransaction id.
paymentIduuidNoPayment this transaction belongs to.
typeauthorization | capture | refund | void | ...NoProcessor transaction type.
statusstringNoTransaction status.
amount, currencyinteger, stringNoTransaction amount and currency.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/checkout-sdk/server · Server-side checkout SDK.

  • createCheckoutClient().listPaymentTransactions(paymentId)

getOrderWithPayments calls this for every payment and returns transactions nested under each payment.

POST /api/v1/payments/{id}/refund Server-side

Refund a captured payment.

X-API-Key
Implementation details

Refund a payment fully or partially. Use webhooks to update downstream order state after the refund result is recorded.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesPayment id.

Request body

FieldTypeRequiredDescription
amountintegerNoPartial refund amount in minor units. Omit for a full refund.

Responses

200 Refund recorded or processor refund initiated.

Response fields

FieldTypeRequiredDescription
iduuidNoPayment id.
statusstringNoUpdated payment/refund status.
refundedAmountintegerNoTotal refunded amount in minor units when returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
422 refund_not_allowed Payment is not captured, already fully refunded, or amount exceeds refundable balance. Read the payment first and only refund captured, refundable amounts.

SDK coverage

@usethrottle/api-client · Server-side generated REST client.

  • Generated client method for POST /api/v1/payments/{id}/refund

Refunds are operations code, not browser checkout code.

GET /api/v1/payments/{id}/invoice-pdf Server-side

Get a signed Net 30 invoice PDF URL.

X-API-Key
Implementation details

Use for buyer portals or operations tools that need to show or download a Net 30 invoice PDF.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesNet 30 payment id.

Responses

200 Signed download information.

Response fields

FieldTypeRequiredDescription
urlurlYesTemporary signed invoice PDF URL.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 not_found No payment with this id belongs to the merchant. Confirm the payment id and that it belongs to your workspace and application.
409 not_invoice The payment is not a Net 30 invoice (e.g. a card or manual payment), so it has no invoice PDF. Only request an invoice PDF for payments whose method is net30.
409 pdf_not_ready The Net 30 invoice exists but its PDF has not been generated yet. Retry after invoice generation completes.
503 storage_unavailable Object storage could not produce a signed URL for the PDF. Retry shortly; if it persists, contact support.
POST /api/v1/payments/{id}/invoice/resend Server-side

Resend the Net 30 invoice email.

X-API-Key
Implementation details

Queues the customer.net30_invoice_issued email again. The email includes a fresh buyer-facing invoice download link.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesNet 30 payment id.

Responses

200 Invoice email queued.

Response fields

FieldTypeRequiredDescription
messageIduuid | stringYesQueued email message id.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
409 not_invoice The payment is not a Net 30 invoice payment. Only call this endpoint for payments where method is net30.
409 no_recipient No customer or Net 30 billing email is available for the invoice. Confirm the order customer or Net 30 acceptance billing email was captured.
409 email_not_configured Transactional email is not enabled for the API service. Configure RESEND_API_KEY, REDIS_URL, and email settings before resending.
GET /api/v1/payments/{id}/invoice/download?token={token} Browser-safe

Download a Net 30 invoice from an email link.

Signed invoice token
Implementation details

Public buyer route used by invoice emails. Throttle validates the signed token, reloads the payment, and redirects to a short-lived S3 signed URL. Tokens are valid for the snapshotted Net-N term, clamped to 1-365 days.

Path parameters

FieldTypeRequiredDescription
iduuidYesNet 30 payment id.

Query parameters

FieldTypeRequiredDescription
tokenjwtYesSigned invoice download token from the email.

Responses

302 Redirects to a short-lived signed PDF URL.

Response fields

FieldTypeRequiredDescription
LocationurlYesTemporary S3 signed URL for the invoice PDF.

Common errors

Status Code Cause Fix
400 missing_token The token query parameter was omitted. Use the full URL generated by the invoice email.
401 invalid_token The token is expired, malformed, or signed with the wrong secret. Resend the invoice email to issue a fresh buyer link.
409 pdf_not_ready The invoice PDF has not been rendered to object storage yet. Retry after the PDF render/backfill job finishes.

Webhooks

Configure signed HTTPS endpoints, test delivery, inspect attempts, and replay delivery payloads.

GET /api/v1/webhook-endpoints Webhook operations

List configured webhook endpoints.

X-API-Key Guide
Implementation details

Returns active and paused outbound webhook endpoints. Deleted endpoints are excluded.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Responses

200 Webhook endpoint list.

Response fields

FieldTypeRequiredDescription
iduuidNoEndpoint id.
urlurlNoDelivery URL.
enabledEventsarrayNoSubscribed event types.
isActivebooleanNoWhether dispatch is active.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/webhook-endpoints Webhook operations

Create a signed outbound webhook endpoint.

X-API-Key Guide
Implementation details

Register the HTTPS URL that receives durable order, payment, cart, subscription, discount, customer, and fulfillment events.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
urlhttps URLYesYour webhook receiver URL. Must use https.
enabledEventsstring[]YesEvent types to deliver. Must be non-empty and unique.

Responses

201 Webhook endpoint created. signingSecret is returned once.

Response fields

FieldTypeRequiredDescription
iduuidYesWebhook endpoint id.
urlurlYesDelivery URL.
enabledEventsarrayYesSubscribed event list.
isActivebooleanYesWhether delivery is active.
signingSecretstringYesHMAC secret. Store it now; it is shown once.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
Create endpoint
curl -X POST https://api.usethrottle.dev/api/v1/webhook-endpoints \
  -H "x-api-key: $THROTTLE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "url": "https://shop.example.com/api/throttle/webhook",
    "enabledEvents": ["order.created", "payment.captured", "payment.failed"]
  }'
PATCH /api/v1/webhook-endpoints/{id} Webhook operations

Update URL, event list, or active state.

X-API-Key Guide
Implementation details

Use this to rotate receivers, pause delivery, resume delivery, or change subscribed events.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesWebhook endpoint id.

Request body

FieldTypeRequiredDescription
urlhttps URLNoNew delivery URL.
enabledEventsstring[]NoReplacement event list.
isActivebooleanNofalse pauses dispatch; true resumes it.

Responses

200 Updated endpoint returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
DELETE /api/v1/webhook-endpoints/{id} Webhook operations

Soft-delete a webhook endpoint.

X-API-Key Guide
Implementation details

Stops future dispatch and removes the endpoint from list responses. Create a new endpoint to subscribe again.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesWebhook endpoint id.

Responses

200 Deleted endpoint confirmation returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
GET /api/v1/webhook-deliveries Webhook operations

Inspect recent webhook delivery attempts.

X-API-Key Guide
Implementation details

Use for debugging and operational audit views. This endpoint returns attempts, not the endpoint configuration itself.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
endpointIduuidNoFilter by webhook endpoint.
orderIduuidNoFilter by related order.
limitintegerNoPage size, 1 to 200.
Default: 50
offsetintegerNoOffset pagination start.
Default: 0

Responses

200 Delivery page.

Response fields

FieldTypeRequiredDescription
itemsarrayNoDelivery attempts.
totalintegerNoTotal matching attempts.
hasMorebooleanNoWhether another page exists.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/webhook-endpoints/{id}/test Webhook operations

Send a synthetic signed test event.

X-API-Key Guide
Implementation details

Use during setup to verify URL reachability, signature validation, and handler routing without waiting for a real checkout event.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesWebhook endpoint id.

Request body

FieldTypeRequiredDescription
eventTypedocumented outbound webhook event typeNoSynthetic event type. Defaults to payment.captured.

Responses

200 Synthetic delivery enqueued or sent.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/webhook-endpoints/{id}/rotate-secret Webhook operations

Rotate the endpoint signing secret (reveal-once).

X-API-Key Guide
Implementation details

Generates a new signing secret and returns it once in the response. The previous secret stops verifying immediately, so update your receiver before (or right after) rotating. Use this to recover from a leaked secret.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesWebhook endpoint id.

Responses

200 New signing secret returned (shown once).

Response fields

FieldTypeRequiredDescription
iduuidNoWebhook endpoint id.
signingSecretstringNoThe new whsec_… secret. Store it now; it is not retrievable later.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/webhook-deliveries/{id}/replay Webhook operations

Replay a prior webhook delivery.

X-API-Key Guide
Implementation details

Re-fires the same event payload with a fresh signature. Use after fixing a receiver bug or recovering from downtime.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesDelivery id.

Responses

200 Replay enqueued or dispatched.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

Production notes

  • Your receiver must still be idempotent because replay intentionally delivers an event more than once.

Embed Config

Allow storefront origins and set merchant branding used by hosted and embedded checkout.

GET /api/v1/embed-config Setup

Read allowed origins and checkout branding.

X-API-Key Guide
Implementation details

Use this in setup tooling or dashboards to show which parent origins and brand values are currently configured.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Responses

200 Current embed config.

Response fields

FieldTypeRequiredDescription
allowedOriginsstring[]NoOrigins allowed to embed checkout.
primaryColorstring | nullNoDefault checkout brand color.
logoUrlurl | nullNoDefault checkout logo.
merchantNamestring | nullNoBuyer-facing merchant name.

SDK coverage

@usethrottle/cli · Developer setup CLI.

  • throttle embed-config get

The CLI is the easiest way to configure origins during setup.

PUT /api/v1/embed-config Setup

Set allowed origins and checkout branding.

X-API-Key Guide
Implementation details

Required before embedding checkout in production. The parentOrigin passed to the SDK must match an allowed origin.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
allowedOriginsstring[]NoAllowed parent origins. Max 20, unique.
primaryColorstringNoBrand color forwarded to hosted checkout (hex `#rrggbb`).
logoUrlurlNoLogo URL used by hosted checkout.
merchantNamestringNoBuyer-facing merchant name, 1 to 100 characters.
cartRecoveryUrlTemplatestring | nullNoAbsolute https URL template for abandoned-cart recovery emails. Must contain a `{cartId}` placeholder (e.g. `https://store.com/cart?c={cartId}`). When set, idle carts with a known customer trigger the recovery email; when unset, recovery is webhook-only. Pass null to clear.
cartAbandonmentThresholdMinutesinteger | nullNoMinutes of inactivity before an open/checkout cart is treated as abandoned (fires `cart.abandoned` + any recovery email). Range 15 to 129600 (90 days). Pass null to clear; when unset, the platform default of 1440 (24h) applies.

Responses

200 Updated embed config returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/cli · Developer setup CLI.

  • throttle embed-config set --origins ...

Use exact origins, including scheme and host. Do not include paths.

Customer Accounts Settings

Enable buyer authentication (registration, sessions, storefront accounts) for an application, per environment. Allowed origins for buyer-auth requests come from the same allowedOrigins list configured via Embed Config above, not a separate setting. Token lifetimes are fixed platform-wide and are not merchant-configurable — the same reasoning as password policy: a merchant cannot weaken the accepted read-revocation lag, and Throttle can raise the floor for everyone at once.

GET /api/v1/applications/{applicationId}/auth-settings Setup

Read buyer-auth settings for an application.

X-API-Key or Clerk session Guide
Implementation details

Requires the applications:read scope (API key) or the application:settings dashboard permission (Clerk). Resolves the environment from the caller (X-Throttle-Environment-Id for Clerk, the key’s own environment for an API key).

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
applicationIduuidYesMust match the caller’s own application; a mismatch returns 403 forbidden.

Responses

200 Current buyer-auth settings for this application + environment.

Response fields

FieldTypeRequiredDescription
enabledbooleanNoWhether /v1/storefront/* is reachable for this application/environment. Defaults to false.
PATCH /api/v1/applications/{applicationId}/auth-settings Setup

Update buyer-auth settings for an application.

X-API-Key or Clerk session Guide
Implementation details

Requires the applications:write scope (API key) or the application:settings dashboard permission (Clerk). Merges into the existing settings JSON — send only the fields you want to change.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
applicationIduuidYesMust match the caller’s own application; a mismatch returns 403 forbidden.

Request body

FieldTypeRequiredDescription
enabledbooleanNoTurn buyer authentication on or off for this application + environment.

Responses

200 Updated buyer-auth settings returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

Production notes

  • Allowed origins for /v1/storefront/* are not set here — they come from the application’s existing allowedOrigins (PUT /api/v1/embed-config). An empty list denies every request in a production environment and allows any origin in a non-production environment.
  • Token lifetimes (access token TTL, refresh token TTL, refresh token absolute TTL) are fixed platform-wide and are not settable here; an unrecognized field is rejected with 400.

Subscriptions

Use recurring checkout plus subscription APIs for buyer portals and merchant-side management.

POST /api/v1/subscriptions Server-side

Create a subscription manually.

X-API-Key Guide
Implementation details

Use for manual creation flows after a vaulted payment method exists. Embed-driven create:auto remains the fastest checkout path.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
customerIduuidYesThrottle customer id.
applicationIduuidNoOptional application id.
planReferencestringYesYour plan id.
planNamestringNoBuyer-facing plan name.
intervalweekly | monthly | quarterly | yearlyYesBilling interval.
amountintegerYesRecurring amount in minor units.
currencystringNoThree-letter currency code.
Default: USD
currentPeriodStartdate-timeYesCurrent period start (ISO 8601).
currentPeriodEnddate-timeYesCurrent period end (ISO 8601).
trialEnddate-timeNoOptional trial end.
metadataobjectNoMerchant-owned metadata.

Responses

201 Subscription created.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side subscription SDK.

  • createSubscriptionsClient().create(input)
  • useCreateSubscription()

The server SDK accepts camelCase fields and can resolve externalCustomerId to the Throttle customer row before create.

GET /api/v1/subscriptions Server-side

List subscriptions for a buyer portal or backend job.

X-API-Key Guide
Implementation details

Filter by Throttle customer id, your external customer id, or status. Proxy this through your backend for buyer-facing portals.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
cursorstringNoCursor for pagination.
limitintegerNoPage size, 1 to 100.
Default: 20
customerIduuidNoThrottle customer id filter.
externalCustomerIdstringNoYour customer id. Mutually exclusive with customerId.
statusactive | paused | cancelled | past_due | trialingNoOptional status filter.
intervalweekly | monthly | quarterly | yearlyNoOptional billing interval filter.
qstringNoSearch subscription id, customer id, plan, status, interval, or metadata.

Responses

200 Paginated subscription list.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hooks through your backend proxy.

  • createSubscriptionsClient().list(filters)
  • useSubscriptions(filters)

Buyer-facing portals should route hooks through createSubscriptionProxyHandler so reads are pinned to the authenticated externalCustomerId.

GET /api/v1/subscriptions/{id} Server-side

Fetch a subscription.

X-API-Key Guide
Implementation details

Use for buyer portal detail pages, support tooling, and access-gating checks.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Responses

200 Subscription detail returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hooks through your backend proxy.

  • createSubscriptionsClient().get(id)
  • useSubscription(id)

The proxy helper verifies the subscription belongs to the authenticated buyer before forwarding mutations.

PATCH /api/v1/subscriptions/{id} Server-side

Change subscription plan or metadata.

X-API-Key Guide
Implementation details

Updates plan reference, display name, interval, amount, or metadata. Changes apply according to the subscription lifecycle rules documented in the guide.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Request body

FieldTypeRequiredDescription
planReferencestringNoUpdated plan id.
planNamestringNoUpdated plan name.
intervalweekly | monthly | quarterly | yearlyNoUpdated interval.
amountintegerNoUpdated amount in minor units.
metadataobjectNoReplacement metadata.

Responses

200 Updated subscription returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hooks through your backend proxy.

  • createSubscriptionsClient().update(id, input)
  • createSubscriptionsClient().changePlan(input)
  • useUpdateSubscription()
  • useChangePlan()

No mid-period proration is applied in v1. Use your own plan catalog as the source of truth for planReference and amount.

POST /api/v1/subscriptions/{id}/pause Server-side

Pause a subscription.

X-API-Key Guide
Implementation details

Moves an active subscription into paused state from your backend proxy.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Responses

200 Paused subscription returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hooks through your backend proxy.

  • createSubscriptionsClient().pause(id)
  • usePauseSubscription()

The proxy helper verifies buyer ownership before forwarding pause requests.

POST /api/v1/subscriptions/{id}/resume Server-side

Resume a paused subscription.

X-API-Key Guide
Implementation details

Moves a paused subscription back into an active billing state.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Responses

200 Resumed subscription returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hooks through your backend proxy.

  • createSubscriptionsClient().resume(id)
  • useResumeSubscription()

The proxy helper verifies buyer ownership before forwarding resume requests.

POST /api/v1/subscriptions/{id}/retry-charge Server-side

Retry the failed charge on a past-due subscription.

X-API-Key Guide
Implementation details

Runs the renewal engine now instead of waiting for the next scheduled dunning attempt. A success advances the period and mints the invoice, the order and the buyer email exactly as the cron would; a failure walks the dunning ladder one rung. Only a past-due subscription has a failed charge to retry.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Responses

200 The subscription as it stands after the attempt — active when the card cleared, still past_due when it did not.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
409 conflict
422 invalid_state

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK.

  • createSubscriptionsClient().retryCharge(id)

Each attempt is charged separately at the payment provider, so a card the buyer has since fixed goes through.

POST /api/v1/subscriptions/{id}/waive-period Server-side

Forgive the current period on a past-due subscription.

X-API-Key Guide
Implementation details

Writes the period off rather than collecting it: the period advances and the dunning counters clear, leaving the same artifacts as any zero-amount renewal — an order and a captured $0 payment, both marked waived with your reason. No invoice is billed. Past-due only: an active subscription already paid, and giving that money back is a refund, not this endpoint.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Request body

FieldTypeRequiredDescription
reasonstringYesWhy the money was not collected, 1–500 characters. Recorded on the waived order.

Responses

200 The subscription, active again.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
422 invalid_state

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK.

  • createSubscriptionsClient().waivePeriod(id, { reason: 'goodwill' })

The waived order reads back as waived, never as a free plan.

POST /api/v1/subscriptions/{id}/cancel Server-side

Cancel a subscription immediately or at period end.

X-API-Key Guide
Implementation details

Use from buyer portals and support tooling. For buyer-facing use, authorize ownership in your backend before calling Throttle.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Request body

FieldTypeRequiredDescription
atPeriodEndbooleanNoIf true, cancels at the end of the current billing period.
Default: false

Responses

200 Updated subscription returned.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hooks through your backend proxy.

  • createSubscriptionsClient().cancel(id, { atPeriodEnd })
  • useCancelSubscription()

Pause and resume follow the same backend-proxy pattern.

POST /api/v1/subscriptions/eligibility-check Server-side

Check trial eligibility for a vaulted card.

X-API-Key Guide
Implementation details

Pre-flight trial fraud protection by checking whether a payment method fingerprint has already used a trial for this merchant.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
paymentMethodIduuidYesCustomer payment method id owned by the authenticated merchant.

Responses

200 Eligibility result.

Response fields

FieldTypeRequiredDescription
eligiblebooleanNoWhether the payment method can receive a trial.
reasonstringNoReason when blocked.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hook through your backend proxy.

  • createSubscriptionsClient().checkTrialEligibility({ paymentMethodId })
  • useTrialEligibility()

Use after a card is vaulted when your UI needs to decide whether to offer a trial.

GET /api/v1/customers/by-external/{externalId} Server-side

Resolve a customer by your own customer id.

X-API-Key Guide
Implementation details

Use when your app stores only its own user id. Throttle resolves the canonical customer row for subscription lists, direct subscription creates, and payment-method reads.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
externalIdstringYesYour customer or user id previously passed as externalCustomerId.

Responses

200 Customer returned.

Response fields

FieldTypeRequiredDescription
iduuidYesThrottle customer id.
externalIdstring | nullNoYour customer id when one is attached.
emailstring | nullNoCustomer email.
metadataobjectNoCustomer metadata.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 not_found No Throttle customer is associated with that external id. Create a checkout session or customer with customer.externalCustomerId first.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hooks through your backend proxy.

  • createSubscriptionsClient().getCustomerByExternalId(externalId)
  • useCustomerByExternalId(externalId)

createSubscriptionProxyHandler pins this path to the authenticated buyer and ignores ids supplied by the browser.

GET /api/v1/customers/{id}/payment-methods Server-side

List saved payment methods for a customer.

X-API-Key Guide
Implementation details

Use on subscription confirmation pages and buyer portals when you need to show the vaulted card summary used for renewals.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesCustomer id.

Responses

200 Saved payment-method summaries returned.

Response fields

FieldTypeRequiredDescription
iduuidYesPayment method id.
methodTypecard | stringNoPayment method type.
cardBrandstring | nullNoCard brand.
cardLastFourstring | nullNoLast four digits for card methods.
isDefaultbooleanNoWhether this method is the default renewal method.
isActivebooleanNoWhether this method can be used for future renewals. Paused methods remain visible but are not charged.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.

SDK coverage

@usethrottle/subscriptions/server · Server-side SDK plus browser hook through your backend proxy.

  • createSubscriptionsClient().listCustomerPaymentMethods(customerId)
  • useCustomerPaymentMethods(customerId)

When routed through createSubscriptionProxyHandler, payment-method reads are resolved from the authenticated externalCustomerId instead of trusting the browser-supplied customer id.

POST /api/v1/customers/{customerId}/payment-methods/{id}/pause Server-side

Pause a saved payment method.

Clerk JWT or X-API-Key
Implementation details

Keeps the vaulted payment method on file but prevents renewals from charging it until it is resumed.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
customerIduuidYesCustomer id.
iduuidYesPayment method id.

Responses

200 Updated payment method returned with isActive=false.

Response fields

FieldTypeRequiredDescription
iduuidYesPayment method id.
isActivebooleanNoFalse after pause.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/customers/{customerId}/payment-methods/{id}/resume Server-side

Resume a saved payment method.

Clerk JWT or X-API-Key
Implementation details

Allows a previously paused vaulted payment method to be used for future renewals again.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
customerIduuidYesCustomer id.
iduuidYesPayment method id.

Responses

200 Updated payment method returned with isActive=true.

Response fields

FieldTypeRequiredDescription
iduuidYesPayment method id.
isActivebooleanNoTrue after resume.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/subscriptions/{id}/change-plan Server-side

Change a subscription plan immediately or at period end.

X-API-Key Guide
Implementation details

Use effective: "now" for upgrades (charges the stored card immediately, resets the billing period). Use effective: "period_end" for downgrades (sets pending_* fields, applies on the next renewal). Returns the updated subscription.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Request body

FieldTypeRequiredDescription
planReferencestringYesYour plan id from your plan catalog.
planNamestringNoBuyer-facing plan name.
intervalweekly | monthly | quarterly | yearlyYesBilling interval for the new plan.
amountintegerYesRecurring amount in minor units for the new plan.
effective"now" | "period_end"Yes"now" charges the card and applies immediately (upgrade path). "period_end" defers the change to next renewal (downgrade path).

Responses

200 Updated subscription returned.

Response fields

FieldTypeRequiredDescription
iduuidYesSubscription id.
statusstringYesCurrent status.
pendingPlanReferencestring | nullNoSet when effective: "period_end". Contains the deferred plan id. Null for effective: "now".
pendingPlanNamestring | nullNoDeferred plan display name. Null when no change is pending.
pendingIntervalstring | nullNoDeferred billing interval. Null when no change is pending.
pendingAmountinteger | nullNoDeferred amount in minor units. Null when no change is pending.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
400 invalid_subscription_state planReference is already equal to the current plan reference. Only call change-plan when the plan is actually changing.
402 payment_failed effective: "now" was used but the stored card charge was declined by the processor. Surface the failure to the buyer and let them update their payment method.
404 not_found No subscription found for the given id. Confirm the subscription id and API key belong to the same application.
Immediate upgrade
curl -X POST https://api.usethrottle.dev/api/v1/subscriptions/sub_abc/change-plan \
  -H "x-api-key: $THROTTLE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "planReference": "pro_yearly",
    "planName": "Pro Yearly",
    "interval": "yearly",
    "amount": 29900,
    "effective": "now"
  }'
Scheduled downgrade
curl -X POST https://api.usethrottle.dev/api/v1/subscriptions/sub_abc/change-plan \
  -H "x-api-key: $THROTTLE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "planReference": "starter_monthly",
    "planName": "Starter Monthly",
    "interval": "monthly",
    "amount": 999,
    "effective": "period_end"
  }'

Production notes

  • effective: "now" is the upgrade path. It charges the stored card for the full new plan amount, resets the billing period from now, emits subscription.plan_changed, and clears any pending_* fields.
  • effective: "period_end" is the downgrade path. No charge is made. The pending_* fields are written, subscription.plan_change_scheduled fires, and the renewal cron applies the change on the next period end.
  • A pending change can be cancelled with DELETE /api/v1/subscriptions/:id/pending-change.
  • A new change-plan call overwrites any existing pending_* fields.
  • cancelAtPeriodEnd takes precedence: if the subscription is already scheduled to cancel at period end, the pending change will never apply unless you first unset the cancel flag.
POST /api/v1/subscriptions/{id}/change-quantity Server-side

Change the seat quantity (per-seat pricing).

X-API-Key Guide
Implementation details

The subscription amount is the per-seat price; the period charge is amount × quantity. effective: "now" prorates immediately (credits unused time on the old total, charges the net of the new total, resets the period) and returns a proration object; effective: "period_end" defers via pending_quantity, applied by the renewal cron. Emits subscription.updated.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Request body

FieldTypeRequiredDescription
quantityintegerYesNew seat count (≥ 1).
effectivestringYes"now" (prorated, immediate) or "period_end" (deferred).
Values: now, period_end

Responses

200 Updated subscription. Immediate changes include a proration object { creditCents, chargedCents, fullAmount }.
400 quantity_unchanged — the new quantity equals the current one.
402 payment_failed — the prorated seat-increase charge was declined.
Add seats now (prorated)
curl -X POST https://api.usethrottle.dev/api/v1/subscriptions/sub_abc/change-quantity \
  -H "X-API-Key: $THROTTLE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "quantity": 5, "effective": "now" }'
DELETE /api/v1/subscriptions/{id}/pending-change Server-side

Cancel a scheduled plan change.

X-API-Key Guide
Implementation details

Clears the pending_* fields set by a prior change-plan call with effective: "period_end". The subscription continues on its current plan. Emits subscription.updated.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesSubscription id.

Responses

200 Updated subscription returned with all pending_* fields null.

Response fields

FieldTypeRequiredDescription
iduuidYesSubscription id.
pendingPlanReferencenullNoAlways null after clear.
pendingPlanNamenullNoAlways null after clear.
pendingIntervalnullNoAlways null after clear.
pendingAmountnullNoAlways null after clear.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
404 not_found No subscription found for the given id. Confirm the subscription id and API key belong to the same application.
Cancel pending change
curl -X DELETE https://api.usethrottle.dev/api/v1/subscriptions/sub_abc/pending-change \
  -H "x-api-key: $THROTTLE_API_KEY"

Production notes

  • Safe to call even when no pending change exists — the call is a no-op and returns the current subscription.
  • Does not affect cancelAtPeriodEnd. Use PATCH /api/v1/subscriptions/:id with cancelAtPeriodEnd: false to cancel a scheduled cancellation.

Workspace Environments

Manage the workspace-wide environment catalog. Each workspace has one immutable production environment; every custom environment is non-production and routes to sandbox-provider credentials. These routes are selected by workspace id and do not require X-Throttle-Environment-Id.

GET /api/v1/workspaces/{workspaceId}/environments Setup

List workspace environments.

Clerk JWT Guide
Implementation details

Returns active workspace environments by default. Add includeArchived=true for settings, audit, or recovery screens.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.

Query parameters

FieldTypeRequiredDescription
includeArchivedtrue | falseNoWhen true, includes archived custom environments.
Default: false

Responses

200 Workspace environments returned.

Response fields

FieldTypeRequiredDescription
iduuidYesEnvironment id.
slugstringYesEnvironment slug used in API key prefixes.
namestringYesHuman-readable environment name.
kindproduction | non_productionYesProduction is the only production kind.
providerEnvironmentproduction | sandboxYesProvider routing target.
statusactive | archivedYesArchived environments are hidden from normal selectors.
isSystembooleanYesSystem environments cannot be archived.

Common errors

Status Code Cause Fix
403 application_key_workspace_route An API key was used for a workspace-level route. Call this route from the dashboard or another Clerk-authenticated setup flow.
POST /api/v1/workspaces/{workspaceId}/environments Setup

Create a custom non-production environment.

Clerk JWT Guide
Implementation details

Creates a new sandbox-provider environment such as UAT, staging, or QA. Production is created by the system and cannot be created through this endpoint. Existing applications in the workspace receive fresh per-environment settings containers immediately.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.

Request body

FieldTypeRequiredDescription
slugstringYesUnique workspace slug. It is normalized to lowercase kebab-case. It cannot start with a production or live component — production, live, production-1, and live-2 are all rejected, because their key segments would read as live credentials. Slugs that merely begin with those letters, such as productionish or livemode, are fine.
namestringYesDisplay name shown in the dashboard selector and settings.

Responses

201 Custom environment created.

Common errors

Status Code Cause Fix
400 reserved_environment_slug Slug starts with a production or live component — production, live, production-1, live-2. Use a non-production slug such as uat, staging, qa, or preview.
409 environment_slug_taken Another environment in the workspace already uses that slug. Pick a unique slug.
DELETE /api/v1/workspaces/{workspaceId}/environments/{environmentId} Setup

Archive a custom environment.

Clerk JWT Guide
Implementation details

Archives a non-system workspace environment. Historical rows keep their environment id; the environment is removed from normal selectors and new work should use another active environment. Production cannot be archived or deleted.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.
environmentIduuidYesEnvironment id to archive.

Responses

200 Environment archived.

Common errors

Status Code Cause Fix
400 system_environment_locked The requested environment is production or another system environment. Only archive custom non-production environments.
404 environment_not_found Environment id is unknown for this workspace. Refresh the environment list and retry.

Auth and API Keys

API keys are workspace credentials minted from the dashboard. Two types exist: secret keys (sk_) for server-side use — they may hold any granted scope, including the wildcard — and publishable keys (pk_) that are safe to embed in browser/frontend code and may hold ONLY the stateless compute scopes shipping_quotes:write and tax_calculations:write. Both carry the workspace environment segment — live for production, the environment slug otherwise (for example sk_uat_ or sk_live_) — that pins the key to one environment. Never expose a secret key in browser code.

GET /api/v1/whoami Setup

Identify the calling credential.

Clerk JWT or X-API-Key
Implementation details

Returns the credential type, its granted scopes, and the workspace, application and environment it is pinned to. Requires authentication but no particular scope, so a minimal key can always read its own grants — useful for tools that adapt their behaviour to what the key may do (the Throttle MCP server registers only the tools the key can execute). Never returns a secret: apiKey.keyPrefix is the same non-sensitive prefix the dashboard shows.

Headers

FieldTypeRequiredDescription
authorization or x-api-keystringYesClerk JWT for dashboard flows or an API key for programmatic callers.

Responses

200 Caller identity.

Response fields

FieldTypeRequiredDescription
typestringNoCredential type: api_key, clerk_jwt, extension_session or pm_client_token.
scopesstring[]NoGranted scopes. Clerk sessions carry ["*"].
workspaceobjectNoid, name and slug of the workspace the credential belongs to.
applicationobject | nullNoid, name and slug of the pinned application; null for workspace-scoped callers.
environmentobjectNoid, slug, kind (production | non_production) and providerEnvironment (production | sandbox) of the pinned environment.
apiKeyobject | nullNoid, name and keyPrefix for API-key callers; null otherwise. Never the raw key.
GET /api/v1/api-keys Setup

List active API keys for the current merchant.

Clerk JWT or X-API-Key
Implementation details

Use in dashboard or setup tooling. Runtime storefront code should not list keys.

Headers

FieldTypeRequiredDescription
authorization or x-api-keystringYesClerk JWT for dashboard flows or secret key for backend setup tooling.

Responses

200 Active key metadata. Raw secret values are never returned.
POST /api/v1/api-keys Setup

Create a secret (sk_) or publishable (pk_) API key.

Clerk JWT Guide
Implementation details

Mint a new key for the selected workspace environment. To mint a browser-safe publishable (pk_) key, include the sentinel string "publishable" as the first entry of the scopes array; otherwise a server-side secret (sk_) key is created. The minted key inherits the request environment selected by X-Throttle-Environment-Id, so the raw value includes the environment segment — live for production, the environment slug otherwise, for example sk_uat_/pk_uat_ or sk_live_/pk_live_. Requested scopes are validated against the @core/scopes registry: unknown scopes, staff-only scopes (the admin:* family), and — for publishable keys — any scope outside shipping_quotes:write / tax_calculations:write are rejected with 400 invalid_scope. The raw key is returned once; store it securely and never ship a secret key to the browser. Only Clerk-authenticated dashboard callers may create keys (an sk_ key cannot mint another key — 403 forbidden).

Headers

FieldTypeRequiredDescription
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
namestringYesKey label.
scopesstring[]YesScopes assigned to the key. Secret keys accept any granted scope or the wildcard "*". To mint a publishable (pk_) key, prepend the sentinel "publishable" to the array; a pk_ key then accepts only shipping_quotes:write and tax_calculations:write (never the wildcard).

Responses

201 Key created.

Response fields

FieldTypeRequiredDescription
rawKeystringYesRaw key, prefixed by type + environment segment — live for production, the environment slug otherwise (for example sk_uat_ or pk_live_). Returned once.
id, name, scopesstring, string, arrayNoKey metadata.

Common errors

Status Code Cause Fix
400 invalid_scope A requested scope is unknown, is staff-only (admin:*), or — for a publishable key — is not one of shipping_quotes:write / tax_calculations:write (or includes the wildcard). Pick scopes from the scopes reference. For a pk_ key request only shipping_quotes:write and/or tax_calculations:write.
DELETE /api/v1/api-keys/{id} Setup

Revoke an API key.

Clerk JWT
Implementation details

Use when rotating credentials or removing access for an integration. Revoked keys can no longer call secret-key endpoints.

Path parameters

FieldTypeRequiredDescription
iduuidYesAPI key id.

Responses

204 Key revoked. No JSON body is returned.

Common errors

Status Code Cause Fix
404 not_found The key id is unknown or belongs to another merchant. Refresh the key list and retry with a valid key id.

Workspace Invitations

Create, list, resend, revoke, and accept workspace membership invitations. Invitations are signed 7-day JWTs sent by email; the accept endpoint binds the Clerk user to the workspace.

POST /api/v1/workspaces/{workspaceId}/invites Setup

Create a workspace invitation.

Clerk JWT Guide
Implementation details

Sends an invitation email to the target address. The invitee must accept with a Clerk account whose email matches exactly. Requires workspace:invite permission (or workspace:invite-admin when granting workspace_admin role). Owners and workspace admins can set environmentGrants; application admins default to all_non_production for app-scoped invites.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.

Request body

FieldTypeRequiredDescription
emailstringYesInvitee email address.
workspaceRolestringNoWorkspace-level role to grant on accept. One of workspace_admin. Omit for application-only access.
applicationRolesarrayNoPer-application role assignments. Each entry is { applicationId, role } where role is admin | developer | finance | viewer.
environmentGrantsobjectNoWorkspace-wide environment access. Shape: { grantType: all | all_non_production | production_only | selected, environmentIds?: uuid[] }. selected requires at least one active environment id.

Responses

201 Invitation created and email sent.

Response fields

FieldTypeRequiredDescription
iduuidNoInvitation id.
emailstringNoInvitee email.
statusstringNoAlways pending on creation.
expiresAtISO 8601NoToken expiry, 7 days out.

Common errors

Status Code Cause Fix
403 permission_denied Caller lacks workspace:invite or workspace:invite-admin. Use an owner or workspace_admin token.
403 environment_grants_forbidden A non-owner/non-workspace-admin tried to set explicit environment grants. Ask an owner or workspace admin to set environment access.
400 invalid_environment_grants selected was sent without environmentIds, or ids were sent for a non-selected grant type. Send a valid grantType and include environmentIds only for selected grants.
409 already_member The email address already belongs to an active workspace member. Use the member management endpoints to update roles instead.
GET /api/v1/workspaces/{workspaceId}/invites Setup

List workspace invitations.

Clerk JWT
Implementation details

Returns all invitations for the workspace, including pending, accepted, revoked, and expired. Filterable by status.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.

Query parameters

FieldTypeRequiredDescription
statusstringNoFilter by invitation status. One of pending | accepted | revoked | expired.

Responses

200 Invitation list.

Response fields

FieldTypeRequiredDescription
itemsarrayNoArray of invitation objects.
totalintegerNoTotal matching invitations.
POST /api/v1/workspaces/{workspaceId}/invites/{id}/resend Setup

Resend a pending invitation.

Clerk JWT
Implementation details

Rotates the invitation token (old token is immediately invalidated) and sends a new email with a fresh 7-day expiry.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.
iduuidYesInvitation id.

Responses

200 Token rotated, email resent.

Response fields

FieldTypeRequiredDescription
expiresAtISO 8601NoNew token expiry.

Common errors

Status Code Cause Fix
409 invite_not_pending Invitation is already accepted, revoked, or expired. Create a new invitation.
POST /api/v1/workspaces/{workspaceId}/invites/{id}/revoke Setup

Revoke a pending invitation.

Clerk JWT
Implementation details

Kills the invitation token immediately. The invitee can no longer use the email link to join.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.
iduuidYesInvitation id.

Responses

204 Invitation revoked. No JSON body.
POST /api/v1/invites/accept Setup

Accept a workspace invitation.

Clerk JWT
Implementation details

Validates the signed token, verifies the Clerk user email matches the invited address, creates the workspace member record, and applies role assignments. The token is consumed on success.

Request body

FieldTypeRequiredDescription
tokenstringYesSigned JWT from the invite email link.

Responses

200 Member joined.

Response fields

FieldTypeRequiredDescription
workspaceIduuidNoThe joined workspace.
memberIduuidNoNew workspace member record id.

Common errors

Status Code Cause Fix
400 invite_expired Token TTL has elapsed. Ask an admin to resend the invitation.
400 invite_email_mismatch Clerk account email does not match the invited address. Sign in with the exact email address the invitation was sent to.
409 already_member Caller is already a member of this workspace. No action needed; access is already granted.

Workspace Members

List, inspect, update, and remove workspace members. Member records hold workspace-level role assignments, per-application role assignments, and workspace-wide environment grants.

GET /api/v1/workspaces/{workspaceId}/members Setup

List workspace members.

Clerk JWT Guide
Implementation details

Returns all active members with their workspace role, per-application role assignments, and environment grants. Requires workspace:edit-member or workspace:remove-member permission.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.

Responses

200 Member list.

Response fields

FieldTypeRequiredDescription
itemsarrayNoArray of member objects.
items[].environmentGrantsobjectNoEnvironment grant summary: { grantType, environmentIds }. Owners resolve to all.
totalintegerNoTotal member count.
GET /api/v1/workspaces/{workspaceId}/members/me Setup

Get the calling user's membership.

Clerk JWT
Implementation details

Returns the workspace role, application role assignments, and environment grants for the authenticated caller. No elevated permissions required.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.

Responses

200 Caller's membership record.

Response fields

FieldTypeRequiredDescription
memberIduuidNoMembership record id.
workspaceRolestringNoowner | workspace_admin | null.
applicationRolesarrayNoPer-application role assignments.
environmentGrantsobjectNoEnvironment grant summary for the calling member.
PATCH /api/v1/workspaces/{workspaceId}/members/{memberId} Setup

Update a member role.

Clerk JWT
Implementation details

Change the workspace-level role, update per-application role assignments, or replace environment grants. Send only the fields you want to change. Requires workspace:edit-member; only owner/workspace_admin callers may set environmentGrants.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.
memberIduuidYesMember id.

Request body

FieldTypeRequiredDescription
workspaceRolestringNoNew workspace role. One of workspace_admin or null to remove.
applicationRolesarrayNoPer-application role assignments to upsert. Each entry is { applicationId, role }.
environmentGrantsobjectNoReplace environment access. Shape: { grantType: all | all_non_production | production_only | selected, environmentIds?: uuid[] }.

Responses

200 Updated member record.

Common errors

Status Code Cause Fix
403 permission_denied Caller cannot grant a role higher than their own. Use an owner or workspace_admin token.
403 environment_grants_forbidden Caller cannot manage environment grants. Use an owner or workspace_admin token.
400 invalid_environment_grants Environment grants were malformed. For selected grants, include at least one environment id; omit ids for other grant types.
DELETE /api/v1/workspaces/{workspaceId}/members/{memberId} Setup

Remove a member from the workspace.

Clerk JWT
Implementation details

Revokes all application roles and removes the workspace membership record in one call. Requires workspace:remove-member.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.
memberIduuidYesMember id.

Responses

204 Member removed. No JSON body.

Common errors

Status Code Cause Fix
403 cannot_remove_owner Attempt to remove the workspace owner. Transfer ownership first, then remove the former owner.
DELETE /api/v1/workspaces/{workspaceId}/members/{memberId}/applications/{applicationId} Setup

Revoke a member's access to one application.

Clerk JWT
Implementation details

Removes the per-application role for the specified application. Workspace membership and roles on other applications are unchanged. Requires application:edit-app-member on the target application.

Path parameters

FieldTypeRequiredDescription
workspaceIduuidYesWorkspace id.
memberIduuidYesMember id.
applicationIduuidYesApplication to revoke access on.

Responses

204 Application role revoked. No JSON body.
GET /api/v1/auth/permissions Setup

Resolve permissions for the authenticated caller.

Clerk JWT Guide
Implementation details

Returns every permission key and whether it resolves to true for the caller. Pass x-application-id to include application-level role flags. Useful for building UI conditionals.

Responses

200 Permissions map.

Response fields

FieldTypeRequiredDescription
workspaceRolestringNoCaller workspace role or null.
appRolestringNoCaller application role on x-application-id or null.
permissionsobjectNoMap of permission key → boolean.

Connectors

Manage payment-provider connections and configure card-transaction routing rules. Routing lets you define which providers are tried, in which order, and for which buyer regions. These are dashboard/merchant-facing routes; all require a Clerk JWT and the connectors:read or connectors:write scope.

GET /api/v1/payment-routing Setup

Get the card-transaction routing config.

Clerk JWT
Implementation details

Returns the current routing configuration for the application: a set of condition-based rules and a default cascade. Rules are evaluated in order; the first rule whose conditions all match wins and its cascade is used. Conditions within a rule are AND-ed. The default cascade applies to any transaction not matched by a rule. Within each cascade, providers are tried in order — if the first provider fails, the next is attempted automatically. Routing is now supported in production environments.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Responses

200 Current routing config.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesOrdered list of condition-based routing rules. Each rule is evaluated in order; the first rule whose conditions all match is applied.
data.rules[].conditionsarrayYesArray of conditions that must all be satisfied (AND-ed) for this rule to match. Each condition matches against a specific transaction attribute.
data.rules[].conditions[].typestringYesCondition type: "country" (buyer country), "cardScheme" (card brand), "cardSource" (payment source), "cardType" (credit/debit/prepaid), "cardCountry" (card issuer country), "paymentSource" (payment initiation source), "amount" (transaction amount), "currency" (transaction currency), or "metadata" (transaction metadata key/value matching).
data.rules[].conditions[].opstringYesOperator: for set conditions (country/cardScheme/cardSource/cardType/cardCountry/paymentSource/currency): "is_one_of" or "is_not_one_of". For amount conditions: "gt" (greater than), "lt" (less than), or "between". For metadata conditions: "includes" or "excludes".
data.rules[].conditions[].valuesstring[]NoArray of values for set conditions. For country: ISO 3166-1 alpha-2 codes. For cardScheme: visa, mastercard, amex, etc. For cardSource: raw, token, applepay, googlepay, network-token. For cardType: credit, debit, prepaid. For cardCountry: ISO 3166-1 alpha-2 codes representing the card issuer country (e.g. "US", "GB"). For paymentSource: ecommerce, moto, recurring, installment, card_on_file. For currency: ISO 4217 codes. For metadata conditions: string values to match against the metadata key.
data.rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions. Throttle automatically stamps "throttle_order_type" on every transaction ("one_off" for one-off checkouts, "recurring" for subscription renewals). Any metadata the merchant sends at checkout is also routable by its key.
data.rules[].conditions[].currencystringNoCurrency for amount conditions (e.g., "USD"). Required for amount conditions.
data.rules[].conditions[].minnumberNoMinimum amount in major units (e.g., dollars, not cents) for "gt" or "between" operators.
data.rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators.
data.rules[].cascadestring[]YesOrdered list of connector IDs to use when this rule matches. First entry is attempted first; subsequent entries are automatic fail-over.
data.defaultCascadestring[]YesOrdered list of connector IDs tried for any transaction not matched by any rule. First entry is attempted first; subsequent entries are automatic fail-over.

Common errors

Status Code Cause Fix
403 permission_denied Caller does not have the application:settings permission. Use a Clerk session with admin or owner role on the target application.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. Check provider status if the error persists.
Get routing config
curl https://api.usethrottle.dev/api/v1/payment-routing \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>"
Example response
{
  "data": {
    "rules": [
      {
        "conditions": [
          { "type": "country", "op": "is_one_of", "values": ["CA", "MX"] }
        ],
        "cascade": ["connector-id-north-america", "connector-id-backup"]
      }
    ],
    "defaultCascade": ["connector-id-stripe", "connector-id-backup"]
  }
}

Production notes

  • Routing is supported in both production and non-production environments.
  • Rules are evaluated in order; the first rule whose conditions all match is applied.
  • Conditions within a rule are AND-ed together.
  • Use GET /api/v1/routing-connectors to list connector IDs eligible for a cascade.
PUT /api/v1/payment-routing Setup

Replace the card-transaction routing config.

Clerk JWT
Implementation details

Atomically replaces the full routing configuration using condition-based rules. Supply the complete desired state; the previous config is discarded and rebuilt from the supplied body. All connector IDs must be active connectors for the application. Condition values must conform to the allowed vocabulary for each condition type. Routing is now supported in production environments.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
rulesarrayYesArray of condition-based routing rules. May be empty to use only the default cascade globally. Rules are evaluated in order; the first rule whose conditions all match is applied.
rules[].conditionsarrayYesArray of conditions for this rule. All conditions must be satisfied (AND-ed) for the rule to match. May be empty.
rules[].conditions[].typestringYesCondition type: "country", "cardScheme", "cardSource", "cardType", "cardCountry", "paymentSource", "amount", or "metadata".
rules[].conditions[].opstringYesOperator. For set types (country/cardScheme/cardSource/cardType/cardCountry/paymentSource): "is_one_of" or "is_not_one_of". For amount: "gt" (greater than), "lt" (less than), or "between". For metadata: "includes" or "excludes".
rules[].conditions[].valuesstring[]NoFor set conditions: array of allowed values. For country: ISO 3166-1 alpha-2 codes (US, CA, GB, etc.). For cardScheme: visa, mastercard, amex, discover, diners-club, jcb, maestro, unionpay, etc. For cardSource: raw, token, applepay, googlepay, network-token. For cardType: credit, debit, prepaid. For cardCountry: ISO 3166-1 alpha-2 codes representing the card issuer country (e.g. "US", "GB"). For paymentSource: ecommerce, moto, recurring, installment, card_on_file. For currency: ISO 4217 codes. For metadata conditions: string values to match against the metadata key.
rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions. Throttle automatically stamps "throttle_order_type" on every transaction ("one_off" for one-off checkouts, "recurring" for subscription renewals). Any metadata the merchant sends at checkout is also routable by its key.
rules[].conditions[].currencystringNoCurrency code for amount conditions (e.g., "USD"). Required for amount type.
rules[].conditions[].minnumberNoMinimum amount in major units for "gt" or "between" operators. Required for those operators.
rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators. Required for those operators.
rules[].cascadestring[]YesOrdered list of connector IDs for this rule. Must contain at least one entry and must not have duplicates.
defaultCascadestring[]YesOrdered connector IDs tried for any transaction not matched by any rule. Must contain at least one entry and must not have duplicates.

Responses

200 Updated routing config returned.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesThe persisted rules after the update.
data.defaultCascadestring[]YesThe persisted default cascade after the update.

Common errors

Status Code Cause Fix
422 routing_default_required defaultCascade is empty. Include at least one active connector ID in defaultCascade.
422 routing_unknown_connector A connector ID in a cascade does not exist or is not active for this application. List available connectors with GET /api/v1/routing-connectors and use only those IDs.
422 routing_duplicate_connector A connector ID appears more than once within the same cascade. Each connector may appear at most once per cascade.
422 routing_empty_cascade A rule cascade is empty. Each rule must include at least one connector ID.
422 routing_rule_no_conditions A routing rule has no conditions. Each rule must include at least one condition.
422 routing_empty_condition_values A set-type condition (country, cardScheme, cardSource, cardType) has an empty values array. Include at least one value in the condition values array.
422 routing_invalid_country A country condition value is not a valid ISO 3166-1 alpha-2 code. Use two-letter uppercase country codes, e.g. "US", "CA".
422 routing_invalid_currency An amount condition currency is not a valid ISO-4217 code. Use three-letter uppercase currency codes, e.g. "USD", "EUR".
422 routing_invalid_amount An amount condition is missing a required field (min for gt, max for lt, both for between) or a value is not a positive number. Provide the required numeric fields for the amount operator and ensure all values are positive.
422 routing_amount_range_invalid An amount between condition has min >= max. Ensure min is strictly less than max.
422 routing_invalid_scheme A cardScheme condition value is not in the allowed card scheme vocabulary. Use one of the documented card scheme values (e.g. "visa", "mastercard", "amex").
422 routing_invalid_card_source A cardSource condition value is not in the allowed card source vocabulary. Use one of: applepay, googlepay, network-token, raw, token.
422 routing_invalid_card_type A cardType condition value is not in the allowed card type vocabulary. Use one of: credit, debit, prepaid.
422 routing_invalid_condition An unsupported condition type was supplied. Use one of: country, cardScheme, cardSource, cardType, cardCountry, paymentSource, amount.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. The routing config was not partially applied.
Set routing config
curl -X PUT https://api.usethrottle.dev/api/v1/payment-routing \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>" \
  -H "content-type: application/json" \
  -d '{
    "rules": [
      {
        "conditions": [
          { "type": "country", "op": "is_one_of", "values": ["CA", "MX"] }
        ],
        "cascade": ["connector-id-north-america", "connector-id-backup"]
      }
    ],
    "defaultCascade": ["connector-id-stripe", "connector-id-backup"]
  }'

Production notes

  • This is a full replacement, not a patch. Omitting a rule removes it.
  • Rules are evaluated in order; the first rule whose conditions all match is applied.
  • Conditions within a rule are AND-ed together.
  • The fail-over order within each cascade is deterministic: the first connector in the array is attempted first, and subsequent entries are tried only if earlier ones fail.
  • Routing is supported in both production and non-production environments.
GET /api/v1/routing-connectors Setup

List connectors eligible for a routing cascade.

Clerk JWT
Implementation details

Returns the active connectors that may be referenced in the defaultCascade or any rule cascade arrays. Only connectors with an active status are included. Use the returned id values when constructing or validating a routing config.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Responses

200 List of available connectors.

Response fields

FieldTypeRequiredDescription
data[].idstringYesConnector ID to use in cascade arrays.
data[].displayNamestringYesHuman-readable connector label.
data[].methodstringNoPayment method type such as card.

Common errors

Status Code Cause Fix
403 permission_denied Caller does not have the application:settings permission. Use a Clerk session with admin or owner role on the target application.
List available connectors
curl https://api.usethrottle.dev/api/v1/routing-connectors \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>"
Example response
{
  "data": [
    { "id": "connector-id-stripe", "displayName": "Stripe (live)", "method": "card" },
    { "id": "connector-id-backup", "displayName": "Backup processor", "method": "card" }
  ]
}

Production notes

  • This endpoint always reflects the current active connectors. Re-fetch before building a new routing config to avoid referencing deleted or inactive connectors.
GET /api/v1/routing-payment-methods Setup

List payment methods available to routing and decline rules.

Clerk JWT
Implementation details

Returns the payment methods supported for this environment. Use a returned id as the value of a paymentMethod condition (Other-transaction decline rules) or as the method of an Other-transaction routing rule. Card methods (card, network-token) are excluded — card routing and decline use card-specific conditions instead.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Responses

200 List of available payment methods.

Response fields

FieldTypeRequiredDescription
data[].idstringYesPayment method id to use as a paymentMethod condition value or an Other-routing rule method (e.g. "paypal", "ideal", "sepa").
data[].labelstringYesHuman-readable payment method label.

Common errors

Status Code Cause Fix
403 permission_denied Caller does not have the application:settings permission. Use a Clerk session with admin or owner role on the target application.
502 payment_provider_error The upstream payment provider method-definitions API returned an unexpected error. Retry after a short delay. Check provider status if the error persists.
List available payment methods
curl https://api.usethrottle.dev/api/v1/routing-payment-methods \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>"
Example response
{
  "data": [
    { "id": "paypal", "label": "PayPal" },
    { "id": "ideal", "label": "iDEAL" },
    { "id": "sepa", "label": "SEPA" }
  ]
}

Production notes

  • Card and network-token methods are excluded; card routing and decline use card-specific conditions (cardScheme, cardType, cardCountry, etc.).
GET /api/v1/card-decline Setup

Get the card-transaction decline rules.

Clerk JWT
Implementation details

Returns the current set of decline rules for card transactions. Rules are evaluated in order before routing occurs; the first rule whose conditions all match rejects the transaction outright and, when an errorCode is configured, returns that code to the integration. Conditions within a rule are AND-ed. A transaction that matches no decline rule proceeds to the routing step.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Responses

200 Current card-decline rules.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesOrdered list of decline rules. Each rule is evaluated in order; the first rule whose conditions all match causes the transaction to be declined.
data.rules[].conditionsarrayYesArray of conditions that must all be satisfied (AND-ed) for this rule to match. Allowed condition types: country, cardScheme, cardSource, cardType, cardCountry, amount, currency, metadata.
data.rules[].conditions[].typestringYesCondition type: "country" (buyer country), "cardScheme" (card brand), "cardSource" (payment source), "cardType" (credit/debit/prepaid), "cardCountry" (card issuer country), "amount" (transaction amount), "currency" (transaction currency), or "metadata" (transaction metadata key/value matching).
data.rules[].conditions[].opstringYesOperator: for set conditions (country/cardScheme/cardSource/cardType/cardCountry/currency): "is_one_of" or "is_not_one_of". For amount: "gt", "lt", or "between". For metadata: "includes" or "excludes".
data.rules[].conditions[].valuesstring[]NoArray of values for set conditions. For country: ISO 3166-1 alpha-2 codes. For cardScheme: visa, mastercard, amex, etc. For cardSource: raw, token, applepay, googlepay, network-token. For cardType: credit, debit, prepaid. For cardCountry: ISO 3166-1 alpha-2 codes representing the card issuer country (e.g. "US", "GB"). For currency: ISO 4217 codes. For metadata conditions: string values to match against the metadata key.
data.rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions.
data.rules[].conditions[].currencystringNoCurrency for amount conditions (e.g., "USD"). Required for amount conditions.
data.rules[].conditions[].minnumberNoMinimum amount in major units for "gt" or "between" operators.
data.rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators.
data.rules[].errorCodestringNoOptional error code returned to the integration when this rule declines the transaction. Must match ^flow_[a-z_]+$ (e.g. "flow_high_risk_country"). If omitted, a generic decline code is returned.

Common errors

Status Code Cause Fix
403 permission_denied Caller does not have the application:settings permission. Use a Clerk session with admin or owner role on the target application.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. Check provider status if the error persists.
Get card-decline rules
curl https://api.usethrottle.dev/api/v1/card-decline \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>"
Example response
{
  "data": {
    "rules": [
      {
        "conditions": [
          { "type": "country", "op": "is_one_of", "values": ["RU", "KP"] }
        ],
        "errorCode": "flow_high_risk_country"
      }
    ]
  }
}

Production notes

  • Decline rules are evaluated before routing. A matched rule rejects the transaction immediately.
  • Rules are evaluated in order; the first matching rule wins.
  • Conditions within a rule are AND-ed together.
  • errorCode is optional. When set it must match ^flow_[a-z_]+$.
PUT /api/v1/card-decline Setup

Replace the card-transaction decline rules.

Clerk JWT
Implementation details

Atomically replaces the full set of card-transaction decline rules. Supply the complete desired state; previous rules are discarded. A matched rule rejects the transaction before routing; the optional errorCode is returned to the integration. Each rule requires at least one condition.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
rulesarrayYesArray of decline rules. May be empty to disable all decline rules. Rules are evaluated in order.
rules[].conditionsarrayYesArray of conditions for this rule. All conditions must be satisfied (AND-ed) for the rule to match. Must contain at least one condition.
rules[].conditions[].typestringYesCondition type: "country", "cardScheme", "cardSource", "cardType", "cardCountry", "amount", or "metadata".
rules[].conditions[].opstringYesOperator. For set types (country/cardScheme/cardSource/cardType/cardCountry): "is_one_of" or "is_not_one_of". For amount: "gt", "lt", or "between". For metadata: "includes" or "excludes".
rules[].conditions[].valuesstring[]NoFor set conditions: array of allowed values. For country: ISO 3166-1 alpha-2 codes. For cardScheme: visa, mastercard, amex, discover, diners-club, jcb, maestro, unionpay, etc. For cardSource: raw, token, applepay, googlepay, network-token. For cardType: credit, debit, prepaid. For cardCountry: ISO 3166-1 alpha-2 codes representing the card issuer country (e.g. "US", "GB"). For metadata: string values to match against the metadata key.
rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions.
rules[].conditions[].currencystringNoCurrency code for amount conditions (e.g., "USD"). Required for amount type.
rules[].conditions[].minnumberNoMinimum amount in major units for "gt" or "between" operators. Required for those operators.
rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators. Required for those operators.
rules[].errorCodestringNoOptional error code returned to the integration when this rule fires. Must match ^flow_[a-z_]+$ (e.g. "flow_high_risk_country"). No free-text message field — errorCode only.

Responses

200 Updated card-decline rules returned.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesThe persisted decline rules after the update.

Common errors

Status Code Cause Fix
422 decline_rule_no_conditions A decline rule has no conditions. Each rule must include at least one condition.
422 routing_invalid_country A country condition value is not a valid ISO 3166-1 alpha-2 code. Use two-letter uppercase country codes, e.g. "US", "CA".
422 routing_invalid_currency An amount condition currency is not a valid ISO-4217 code. Use three-letter uppercase currency codes, e.g. "USD", "EUR".
422 routing_invalid_amount An amount condition is missing a required field or a value is not a positive number. Provide the required numeric fields for the amount operator and ensure all values are positive.
422 routing_amount_range_invalid An amount between condition has min >= max. Ensure min is strictly less than max.
422 routing_invalid_scheme A cardScheme condition value is not in the allowed card scheme vocabulary. Use one of the documented card scheme values (e.g. "visa", "mastercard", "amex").
422 routing_invalid_card_source A cardSource condition value is not in the allowed card source vocabulary. Use one of: applepay, googlepay, network-token, raw, token.
422 routing_invalid_card_type A cardType condition value is not in the allowed card type vocabulary. Use one of: credit, debit, prepaid.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. The decline rules were not partially applied.
Set card-decline rules
curl -X PUT https://api.usethrottle.dev/api/v1/card-decline \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>" \
  -H "content-type: application/json" \
  -d '{
    "rules": [
      {
        "conditions": [
          { "type": "country", "op": "is_one_of", "values": ["RU", "KP"] }
        ],
        "errorCode": "flow_high_risk_country"
      },
      {
        "conditions": [
          { "type": "cardType", "op": "is_one_of", "values": ["prepaid"] },
          { "type": "amount", "op": "gt", "currency": "USD", "min": 500 }
        ]
      }
    ]
  }'

Production notes

  • This is a full replacement, not a patch. Omitting a rule removes it.
  • Rules are evaluated in order before routing; the first matching rule declines the transaction.
  • Conditions within a rule are AND-ed together.
  • errorCode must match ^flow_[a-z_]+$ when provided. There is no free-text message field.
  • Send an empty rules array to remove all decline rules.
GET /api/v1/other-routing Setup

Get the non-card ("Other transactions") routing config.

Clerk JWT
Implementation details

Returns the current routing configuration for non-card payment methods (e.g. PayPal, iDEAL, SEPA). Rules are evaluated in order; the first rule whose method and conditions all match determines the connector cascade used. Unmatched non-card transactions fall through to the default (first active connection for the payment method and currency).

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Responses

200 Current non-card routing config.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesOrdered list of non-card routing rules. Each rule is evaluated in order; the first rule whose method and conditions all match is applied.
data.rules[].methodstringYesPayment method this rule applies to (e.g. "paypal", "ideal", "sepa"). Only transactions of this method are tested against this rule's conditions.
data.rules[].conditionsarrayYesArray of conditions that must all be satisfied (AND-ed) for this rule to match. Allowed condition types: country, currency, amount, metadata. Card conditions (cardScheme, cardSource, cardType) are not permitted here.
data.rules[].conditions[].typestringYesCondition type: "country" (buyer country), "currency" (transaction currency), "amount" (transaction amount), or "metadata" (transaction metadata key/value matching). Card-specific condition types are not permitted for non-card routing rules.
data.rules[].conditions[].opstringYesOperator: for set conditions (country/currency): "is_one_of" or "is_not_one_of". For amount: "gt", "lt", or "between". For metadata: "includes" or "excludes".
data.rules[].conditions[].valuesstring[]NoArray of values for set conditions. For country: ISO 3166-1 alpha-2 codes. For currency: ISO 4217 codes (e.g. "USD", "EUR"). For metadata: string values to match against the metadata key.
data.rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions.
data.rules[].conditions[].currencystringNoCurrency for amount conditions (e.g., "USD"). Required for amount conditions.
data.rules[].conditions[].minnumberNoMinimum amount in major units for "gt" or "between" operators.
data.rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators.
data.rules[].connectionsstring[]YesOrdered list of connector IDs of the same method as the rule. First entry is attempted first; subsequent entries are automatic fail-over. All connectors must use the same payment method as rules[].method.

Common errors

Status Code Cause Fix
403 permission_denied Caller does not have the application:settings permission. Use a Clerk session with admin or owner role on the target application.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. Check provider status if the error persists.
Get non-card routing config
curl https://api.usethrottle.dev/api/v1/other-routing \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>"
Example response
{
  "data": {
    "rules": [
      {
        "method": "paypal",
        "conditions": [
          { "type": "country", "op": "is_one_of", "values": ["US", "CA"] }
        ],
        "connections": ["connector-id-paypal-primary", "connector-id-paypal-backup"]
      }
    ]
  }
}

Production notes

  • Rules are evaluated in order; the first rule whose method and conditions all match is applied.
  • Conditions within a rule are AND-ed together.
  • Card-specific condition types (cardScheme, cardSource, cardType) are not permitted. Use method to identify the payment method.
  • Unmatched non-card transactions use the default (first active connection for that method and currency). There is no pinned default cascade for this config.
  • Use GET /api/v1/routing-connectors to discover connector IDs and their associated payment methods.
PUT /api/v1/other-routing Setup

Replace the non-card ("Other transactions") routing config.

Clerk JWT
Implementation details

Atomically replaces the full routing configuration for non-card payment methods. Supply the complete desired state; previous rules are discarded. Each rule must declare a payment method and at least one connector of that method. Card conditions (cardScheme, cardSource, cardType) are not permitted — use the method field instead.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
rulesarrayYesArray of non-card routing rules. May be empty to disable custom non-card routing. Rules are evaluated in order.
rules[].methodstringYesPayment method this rule targets (e.g. "paypal", "ideal", "sepa"). Must be a non-card method. All connections in this rule must be of the same method.
rules[].conditionsarrayYesArray of conditions for this rule. All conditions must be satisfied (AND-ed) for the rule to match. May be empty (matches all transactions of the given method).
rules[].conditions[].typestringYesCondition type: "country", "currency", "amount", or "metadata". Card-specific types (cardScheme, cardSource, cardType) are not permitted.
rules[].conditions[].opstringYesOperator. For set types (country/currency): "is_one_of" or "is_not_one_of". For amount: "gt", "lt", or "between". For metadata: "includes" or "excludes".
rules[].conditions[].valuesstring[]NoFor set conditions: array of allowed values. For country: ISO 3166-1 alpha-2 codes. For currency: ISO 4217 codes (e.g. "USD", "EUR"). For metadata: string values to match against the metadata key.
rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions.
rules[].conditions[].currencystringNoCurrency code for amount conditions (e.g., "USD"). Required for amount type.
rules[].conditions[].minnumberNoMinimum amount in major units for "gt" or "between" operators. Required for those operators.
rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators. Required for those operators.
rules[].connectionsstring[]YesOrdered list of connector IDs for this rule. All connectors must use the same payment method as rules[].method. Must contain at least one entry.

Responses

200 Updated non-card routing config returned.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesThe persisted non-card routing rules after the update.

Common errors

Status Code Cause Fix
422 other_routing_method_required A rule is missing the method field. Provide a non-card payment method string (e.g. "paypal", "ideal") for each rule.
422 other_routing_empty_connections A rule has an empty connections array. Each rule must include at least one connector ID in connections.
422 other_routing_method_mismatch A connection's payment method does not match the rule's method field. Ensure every connector ID in a rule's connections uses the same payment method as the rule's method field.
422 other_routing_unknown_connector A connector ID in connections does not exist or is not active for this application. List available connectors with GET /api/v1/routing-connectors and use only active connector IDs.
422 routing_invalid_country A country condition value is not a valid ISO 3166-1 alpha-2 code. Use two-letter uppercase country codes, e.g. "US", "CA".
422 routing_invalid_currency A currency condition or amount condition currency is not a valid ISO-4217 code. Use three-letter uppercase currency codes, e.g. "USD", "EUR".
422 routing_invalid_amount An amount condition is missing a required field or a value is not a positive number. Provide the required numeric fields for the amount operator and ensure all values are positive.
422 routing_amount_range_invalid An amount between condition has min >= max. Ensure min is strictly less than max.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. The routing config was not partially applied.
Set non-card routing config
curl -X PUT https://api.usethrottle.dev/api/v1/other-routing \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>" \
  -H "content-type: application/json" \
  -d '{
    "rules": [
      {
        "method": "paypal",
        "conditions": [
          { "type": "country", "op": "is_one_of", "values": ["US", "CA"] }
        ],
        "connections": ["connector-id-paypal-primary", "connector-id-paypal-backup"]
      },
      {
        "method": "ideal",
        "conditions": [],
        "connections": ["connector-id-ideal-primary"]
      }
    ]
  }'

Production notes

  • This is a full replacement, not a patch. Omitting a rule removes it.
  • Rules are evaluated in order; the first rule whose method and conditions all match is applied.
  • Conditions within a rule are AND-ed together.
  • Card-specific condition types (cardScheme, cardSource, cardType) are not permitted. The method field identifies the payment method.
  • Unmatched non-card transactions use the default. There is no pinned default cascade.
  • Send an empty rules array to remove all custom non-card routing rules.
GET /api/v1/other-decline Setup

Get the non-card transaction decline rules.

Clerk JWT
Implementation details

Returns the current set of decline rules for non-card payment method transactions. Rules are evaluated in order before routing occurs; the first rule whose conditions all match rejects the transaction. Allowed condition types are paymentMethod, country, currency, amount, and metadata.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.

Responses

200 Current non-card decline rules.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesOrdered list of non-card decline rules. The first rule whose conditions all match causes the transaction to be declined.
data.rules[].conditionsarrayYesArray of conditions that must all be satisfied (AND-ed) for this rule to match. Allowed condition types: paymentMethod, country, currency, amount, metadata.
data.rules[].conditions[].typestringYesCondition type: "paymentMethod" (specific non-card method), "country" (buyer country), "currency" (transaction currency), "amount" (transaction amount), or "metadata" (transaction metadata key/value matching).
data.rules[].conditions[].opstringYesOperator: for paymentMethod/country/currency conditions: "is_one_of" or "is_not_one_of". For amount: "gt", "lt", or "between". For metadata: "includes" or "excludes".
data.rules[].conditions[].valuesstring[]NoArray of values for set conditions. For paymentMethod: non-card method names (e.g. "paypal", "ideal", "sepa"). For country: ISO 3166-1 alpha-2 codes. For currency: ISO 4217 codes. For metadata: string values to match against the metadata key.
data.rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions.
data.rules[].conditions[].currencystringNoCurrency for amount conditions (e.g., "USD"). Required for amount conditions.
data.rules[].conditions[].minnumberNoMinimum amount in major units for "gt" or "between" operators.
data.rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators.
data.rules[].errorCodestringNoOptional error code returned to the integration when this rule declines the transaction. Must match ^flow_[a-z_]+$. If omitted, a generic decline code is returned.

Common errors

Status Code Cause Fix
403 permission_denied Caller does not have the application:settings permission. Use a Clerk session with admin or owner role on the target application.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. Check provider status if the error persists.
Get non-card decline rules
curl https://api.usethrottle.dev/api/v1/other-decline \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>"
Example response
{
  "data": {
    "rules": [
      {
        "conditions": [
          { "type": "paymentMethod", "op": "is_one_of", "values": ["paypal"] },
          { "type": "country", "op": "is_one_of", "values": ["RU"] }
        ],
        "errorCode": "flow_high_risk_country"
      }
    ]
  }
}

Production notes

  • Decline rules are evaluated before routing. A matched rule rejects the transaction immediately.
  • Rules are evaluated in order; the first matching rule wins.
  • Conditions within a rule are AND-ed together.
  • The paymentMethod condition type uses "is_one_of" or "is_not_one_of" operators.
  • errorCode is optional. When set it must match ^flow_[a-z_]+$.
PUT /api/v1/other-decline Setup

Replace the non-card transaction decline rules.

Clerk JWT
Implementation details

Atomically replaces the full set of decline rules for non-card payment method transactions. Supply the complete desired state; previous rules are discarded. Each rule requires at least one condition. Allowed condition types are paymentMethod, country, currency, amount, and metadata.

Headers

FieldTypeRequiredDescription
authorizationBearer <dashboard-session>YesClerk dashboard session token. API keys cannot call workspace-level routes.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
rulesarrayYesArray of non-card decline rules. May be empty to disable all non-card decline rules. Rules are evaluated in order.
rules[].conditionsarrayYesArray of conditions for this rule. All conditions must be satisfied (AND-ed) for the rule to match. Must contain at least one condition.
rules[].conditions[].typestringYesCondition type: "paymentMethod", "country", "currency", "amount", or "metadata".
rules[].conditions[].opstringYesOperator. For paymentMethod/country/currency: "is_one_of" or "is_not_one_of". For amount: "gt", "lt", or "between". For metadata: "includes" or "excludes".
rules[].conditions[].valuesstring[]NoFor set conditions: array of allowed values. For paymentMethod: non-card method names (e.g. "paypal", "ideal", "sepa"). For country: ISO 3166-1 alpha-2 codes. For currency: ISO 4217 codes. For metadata: string values to match against the metadata key.
rules[].conditions[].keystringNoMetadata key to match against. Required for metadata conditions.
rules[].conditions[].currencystringNoCurrency code for amount conditions (e.g., "USD"). Required for amount type.
rules[].conditions[].minnumberNoMinimum amount in major units for "gt" or "between" operators. Required for those operators.
rules[].conditions[].maxnumberNoMaximum amount in major units for "lt" or "between" operators. Required for those operators.
rules[].errorCodestringNoOptional error code returned to the integration when this rule fires. Must match ^flow_[a-z_]+$. No free-text message field — errorCode only.

Responses

200 Updated non-card decline rules returned.

Response fields

FieldTypeRequiredDescription
data.rulesarrayYesThe persisted non-card decline rules after the update.

Common errors

Status Code Cause Fix
422 decline_rule_no_conditions A decline rule has no conditions. Each rule must include at least one condition.
422 routing_invalid_country A country condition value is not a valid ISO 3166-1 alpha-2 code. Use two-letter uppercase country codes, e.g. "US", "CA".
422 routing_invalid_currency A currency condition or amount condition currency is not a valid ISO-4217 code. Use three-letter uppercase currency codes, e.g. "USD", "EUR".
422 routing_invalid_amount An amount condition is missing a required field or a value is not a positive number. Provide the required numeric fields for the amount operator and ensure all values are positive.
422 routing_amount_range_invalid An amount between condition has min >= max. Ensure min is strictly less than max.
502 payment_provider_error The upstream payment provider returned an unexpected error. Retry after a short delay. The decline rules were not partially applied.
Set non-card decline rules
curl -X PUT https://api.usethrottle.dev/api/v1/other-decline \
  -H "authorization: Bearer <clerk-session-token>" \
  -H "x-application-id: <application-uuid>" \
  -H "x-throttle-environment-id: <environment-uuid>" \
  -H "content-type: application/json" \
  -d '{
    "rules": [
      {
        "conditions": [
          { "type": "paymentMethod", "op": "is_one_of", "values": ["paypal"] },
          { "type": "country", "op": "is_one_of", "values": ["RU", "KP"] }
        ],
        "errorCode": "flow_high_risk_country"
      }
    ]
  }'

Production notes

  • This is a full replacement, not a patch. Omitting a rule removes it.
  • Rules are evaluated in order before routing; the first matching rule declines the transaction.
  • Conditions within a rule are AND-ed together.
  • The paymentMethod condition type uses "is_one_of" or "is_not_one_of" to target specific non-card methods.
  • errorCode must match ^flow_[a-z_]+$ when provided. There is no free-text message field.
  • Send an empty rules array to remove all non-card decline rules.

Analytics and Export

Read-only merchant reporting: an orders + gross-revenue time series and a CSV export of orders. Both require the orders:read scope (secret API key or dashboard session) and are scoped to the caller’s workspace, application, and environment.

GET /api/v1/analytics/orders-timeseries Server-side

Orders + captured gross revenue bucketed by day, week, or month over a date range.

Secret API key or dashboard session
Implementation details

Returns a zero-filled series of order count and captured gross revenue, bucketed by day/week/month in the requested timezone. "Gross" counts orders whose payment status is authorized, captured, partially_paid, partially_refunded, or refunded. `days` remains supported as shorthand for `from = to - days`.

Query parameters

FieldTypeRequiredDescription
fromstringNoISO 8601 start of range, exclusive. Defaults to 30 days before "to" (or "to" minus `days`, if given).
tostringNoISO 8601 end of range, exclusive.
Default: now
daysintegerNoLegacy shorthand for from = to - days. Ignored when from is set.
Default: 30
groupBystringNoBucket size: day, week, or month.
Default: day
timezonestringNoIANA timezone name or UTC offset for bucket boundaries, e.g. America/New_York.
Default: UTC
compareTostringNoAdd a comparison total: previous_period, previous_year, or none.
Default: none

Responses

200 Envelope { data: { days, range, currency, totalOrders, totalGrossCents, series, comparison?, note } } where `range` is { from, to, timezone, groupBy }, each series entry is { date: "YYYY-MM-DD", orders, grossCents }, and `comparison` (present only when compareTo is set) is { range: { from, to }, totalOrders, totalGrossCents }.
GET /api/v1/orders/export.csv Server-side

Export orders as a CSV attachment.

Secret API key or dashboard session
Implementation details

Streams orders as text/csv (Content-Disposition: attachment), honoring the same filters as GET /api/v1/orders. Capped at 10,000 rows. Columns: order_number, id, status, display_status, payment_status, total, comp_amount, currency, customer_id, created_at.

Query parameters

FieldTypeRequiredDescription
statusstringNoFilter by order status.
paymentStatusstringNoFilter by payment status.
qstringNoSearch across id, order number, status, and payment status.

Responses

200 A text/csv attachment named orders-export.csv (not the JSON envelope).

Returns and RMA

Open and process returns (RMAs) against an order. A return covers a subset of the order’s line items; on completion a refund is issued for the returned value (capped at the captured amount) and the restock flag signals your WMS. A return can instead be completed as an exchange (create a replacement order + settle the price difference). Requires order_returns:read / order_returns:write.

POST /api/v1/orders/{id}/returns Server-side

Open a return (RMA) against an order.

X-API-Key
Implementation details

Creates a return in status "requested" for a subset of the order’s line items. Validates each line item belongs to the order and the quantity does not exceed the returnable balance (ordered minus already-returned). refundAmount is computed from the line items’ unit prices.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Request body

FieldTypeRequiredDescription
itemsarrayYesLine items to return: [{ lineItemId, quantity }].
reasonstringNoOptional return reason.
restockbooleanNoSignal your WMS to restock on completion. Default false.

Responses

200 The created return with its items.
Open a return
curl -X POST https://api.usethrottle.dev/api/v1/orders/ord_abc/returns \
  -H "X-API-Key: $THROTTLE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "items": [{ "lineItemId": "li_1", "quantity": 1 }], "reason": "defective", "restock": true }'
GET /api/v1/orders/{id}/returns Server-side

List an order's returns.

X-API-Key
Implementation details

Returns all RMAs opened against the order, each with its line items.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesOrder id.

Responses

200 Array of returns.
GET /api/v1/returns/{id} Server-side

Get a return and its items.

X-API-Key
Implementation details

Fetches a single return by id, including its line items and current status.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesReturn id.

Responses

200 The return with its items.
POST /api/v1/returns/{id}/transition Server-side

Transition a return through its lifecycle.

X-API-Key
Implementation details

Moves the return: approve (requested→approved), reject (requested→rejected), receive (approved→received), complete (received→completed), cancel (requested|approved→cancelled). On complete a refund is issued for refundAmount against the order’s captured payment and refundPaymentId is stamped. Emits return.updated.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesReturn id.

Request body

FieldTypeRequiredDescription
actionstringYesThe transition to apply.
Values: approve, reject, receive, complete, cancel

Responses

200 The updated return.
409 invalid_return_state — the action is not allowed from the current status.
POST /api/v1/returns/{id}/exchange Server-side

Complete a return as an exchange.

X-API-Key
Implementation details

Creates a replacement order for the swapped items and settles the price difference vs the return’s refund value: if the replacement costs more the difference is charged to the customer’s stored card; if less, it is refunded to the original payment. The return is marked completed and linked to the replacement order (exchange_order_id). The return must be in approved or received status.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesReturn id.

Request body

FieldTypeRequiredDescription
itemsarrayYesReplacement line items: [{ name, unitPrice, quantity, referenceId? }].

Responses

200 The completed return with an exchange { replacementOrderId, replacementTotal, delta, chargedPaymentId?, refundedPaymentId? }.
402 payment_failed — the exchange-difference charge was declined.
409 invalid_return_state — the return is not approved/received.

Bulk Imports

Import a merchant’s historical customers or orders from a CSV or TSV export. The file never passes through the API: POST /api/v1/imports returns a presigned PUT and the browser uploads straight to storage.

POST /api/v1/imports Server-side

Create an import and get a presigned upload URL.

X-API-Key
Implementation details

Creates the import record at status `created` and returns a one-hour presigned PUT for the file. Upload the file with exactly the returned `contentType` — the signature covers that header, so a different one fails with SignatureDoesNotMatch. The 500 MB size ceiling is checked here, before the URL is issued, because a presigned PUT cannot enforce one on its own. Spreadsheets (.xlsx / .xls) are not supported: export the sheet as CSV.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Request body

FieldTypeRequiredDescription
entityTypestringYesWhat the file contains.
Values: customer, order
fileNamestringYesThe merchant’s own file name. Its extension selects the parser: .csv or .tsv. Spreadsheets are rejected.
fileBytesintegerYesSize of the file about to be uploaded, in bytes.
providerstring | nullNoSource platform hint (e.g. `bigcommerce`), used to disambiguate template matching. Omit for a generic export.

Responses

201 Import created; upload the file next.

Response fields

FieldTypeRequiredDescription
importIduuidNoUse this for every later import call.
uploadUrlurlNoPresigned PUT. Send the file body here.
fileKeystringNoStorage key the file will live at.
contentTypestringNoThe Content-Type the PUT must send, verbatim.
expiresInintegerNoSeconds the upload URL stays valid.

Common errors

Status Code Cause Fix
400 unsupported_file_type fileName has an extension the importer cannot read, including .xlsx and .xls. Export the file as CSV (or TSV) and upload that. There is no spreadsheet reader.
413 file_too_large fileBytes exceeds the 500 MB ceiling. Split the export into smaller files. The message names both the limit and the size you sent.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
Create then upload
curl -X POST https://api.usethrottle.dev/api/v1/imports \
  -H "x-api-key: $THROTTLE_API_KEY" \
  -H "content-type: application/json" \
  -d '{"entityType":"order","fileName":"orders.csv","fileBytes":204800,"provider":"bigcommerce"}'

# then PUT the file to data.uploadUrl with the returned content type
curl -X PUT "$UPLOAD_URL" -H "content-type: text/csv" --data-binary @orders.csv
POST /api/v1/imports/{id}/inspect Server-side

Sniff the uploaded file and suggest a mapping.

X-API-Key
Implementation details

Reads at most the first 1 MB of the uploaded file, however large it is, so it answers immediately. Returns the sniffed dialect, the resolved headers, a 20-row sample, the matched platform template and a suggested target field per header. Persists the dialect and the object’s REAL size, and moves the import to status `mapping`. **This retracts any dry run** (`dryRunAt` is cleared): the dialect decides how every row is parsed, so a dry run that ran under a different one described a different file. An import that has already written rows — a finished commit, or one that died partway — cannot be inspected at all, because resetting its status would leave those rows with no way to remove them. A zero-byte object is refused: that is a PUT that did not carry the file.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesImport id.

Responses

200 What the mapping screen needs.

Response fields

FieldTypeRequiredDescription
dialectobjectNo{ delimiter, enclosure, hasHeader } — sniffed, not assumed.
headersstring[]NoColumn names, in file order.
sampleobject[]NoUp to 20 rows: { rowNumber, cells, raw }.
templateobject | nullNoThe matched platform template, or null for a generic export.
suggestionsobjectNoSource header to suggested target field, with a confidence score.

Common errors

Status Code Cause Fix
409 file_not_uploaded The import exists but nothing has been PUT to its upload URL yet — or the object is there and zero bytes, which is a PUT that did not carry the file. Upload the file to the presigned URL from POST /api/v1/imports, then inspect again.
409 import_running A worker is currently validating, committing or undoing this import. Wait for the run to finish. Re-inspecting mid-run would move the status out from under the worker.
409 already_committed The import has already committed, or has been undone. Create a new import. Re-inspecting a settled one would reset it to `mapping` and take its undo path with it.
409 rows_already_written A COMMIT of this import has written rows to this environment — typically one that died partway, which sits at `failed` rather than at a terminal status. A passing dry run does NOT count: it reports what it would create in the same counters, and `lastPassMode` is what tells the two apart. POST /api/v1/imports/{id}/undo to remove them first, or create a new import. Re-inspecting would reset the counters and status those rows are tracked by, leaving them unreachable.
413 file_too_large The uploaded object is over the 500 MB ceiling. Checked here against its REAL size, because a presigned PUT signs only the key and the content type — never the body length — so the size checked at create time was the one the client declared. Split the export and import it in parts.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
PATCH /api/v1/imports/{id}/mapping Server-side

Save the confirmed column mapping.

X-API-Key
Implementation details

Persists the mapping the merchant confirmed. Every target field is checked against the vocabulary for this import’s entityType, and an unknown one is rejected by name; two columns mapped to one field are rejected with both headers named. A source column the merchant chose to ignore is simply left out of `columns`. **This retracts any dry run**: the import returns to `status: "mapping"` and `dryRunAt` is cleared, because a dry run attests to a file AND a mapping — so a validate has to be re-run before this import can be committed. An import that has already written rows cannot be re-mapped at all (409 `rows_already_written`): resetting its status would leave those rows with no way to remove them.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.
content-typeapplication/jsonYesRequired when the request includes a JSON body.

Path parameters

FieldTypeRequiredDescription
iduuidYesImport id.

Request body

FieldTypeRequiredDescription
columnsobjectYesSource header to target field id, e.g. { "Order ID": "order.externalId" }. Omit a header to ignore that column.
dateOrderstringYesHow to read ambiguous dates. Required, never guessed — 03/04/2026 is two different days under dmy and mdy.
Values: iso, dmy, mdy
emptyPaymentPolicystringYesWhat a blank payment-status cell means.
Values: paid, unpaid, unknown
guestSentinelsstring[]NoCustomer-id values that mean “guest checkout” rather than a real buyer. Defaults to ["0", ""].
Default: ["0", ""]
createMissingCustomersbooleanNoOrder imports only: whether an unmatched buyer email may create a customer. Defaults to true.
Default: true

Responses

200 The import, with the saved mapping.

Common errors

Status Code Cause Fix
400 unknown_target_field A value in `columns` is not a target field for this import’s entityType. The message names the offending field ids. Fields are entity-specific: `customer.email` is not valid on an order import.
400 duplicate_target_field Two source columns are mapped to the same target field. The message names the field and both headers. Keep one and leave the other out of `columns` to ignore it — the importer would otherwise take the first and silently discard the second.
409 import_running A worker is currently validating or committing this import. Wait for the run to finish before changing the rules it is running under.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
GET /api/v1/imports/{id} Server-side

Read one import, with progress.

X-API-Key
Implementation details

Progress is polled from the counters on the import row rather than streamed. `progress.percent` is null until the row total is known.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesImport id.

Responses

200 The import.

Response fields

FieldTypeRequiredDescription
statusstringNoLifecycle state.
Values: created, mapping, validating, validated, committing, completed, failed, undone
progressobjectNo{ rowsTotal, rowsProcessed, percent }. rowsTotal is established at the end of the validate pass — nothing can count a file’s rows without parsing it — so percent is null during validate and real for the commit that follows.
errorSummaryobjectNoFailure counts grouped by error code, with one sample message each.
lastPassModestring | nullNoWhich pass wrote the counters above — `validate` or `commit`, null before any run. **Read it before reading `rowsCreated`:** a dry run reports what it WOULD create in the same field, so `rowsCreated: 6` means six rows exist only when this is `commit`.
Values: validate, commit
undoResultobject | nullNoWhat the last undo removed and kept: { ordersDeleted, customersDeleted, ordersKept, customersKept, keptReasons }. Null until an undo has run.

Common errors

Status Code Cause Fix
403 environment_mismatch The import belongs to a different workspace environment than the credential used. Use a key (or dashboard environment) for the environment the import was created in.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/imports/{id}/validate Server-side

Queue a dry run.

X-API-Key
Implementation details

Reads the whole file under the saved mapping and writes nothing: the response reports what a commit would create, update, skip and reject. Requires a saved mapping. Answers 202 with the import row at its PRE-run status — the worker owns the transition to `validating`, so poll GET /api/v1/imports/{id} for the outcome. The dry run is also what establishes `rowsTotal`, so the commit that follows can report real progress.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesImport id.

Responses

202 The import row; the run is queued.

Common errors

Status Code Cause Fix
400 mapping_required The import has no saved mapping. PATCH /api/v1/imports/{id}/mapping with the confirmed column mapping first.
409 import_running A worker is already validating or committing this import. Wait for the run in flight to reach a terminal status.
409 already_committed The import has already completed a commit, or has been undone. Create a new import to load the file again.
409 rows_already_written A commit of this import has written rows. A dry run over them would replace the counters and status those rows are tracked by, leaving no way to remove them. POST /api/v1/imports/{id}/undo first, or create a new import.
503 queue_unavailable The deployment has no import worker queue configured. Nothing was started. Retry once the worker is available; an import never runs inside the API process.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/imports/{id}/commit Server-side

Queue the real import.

X-API-Key
Implementation details

Requires a passed dry run: `status: "validated"`, or `status: "failed"` when the failure came from a commit that had already been validated (`dryRunAt` set), in which case the run resumes from its checkpoint rather than restarting. A commit rewrites order and customer history from the file, so an import that has never passed a dry run — including one whose VALIDATE failed — is refused rather than run. Answers 202 with the import row at its pre-run status; poll GET /api/v1/imports/{id}.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesImport id.

Responses

202 The import row; the write pass is queued.

Common errors

Status Code Cause Fix
409 validation_required The import has never passed a dry run — any status other than `validated`, or a `failed` one with no `dryRunAt` (its validate is what failed). POST /api/v1/imports/{id}/validate and wait for status `validated`.
409 import_running A worker is already validating or committing this import. Wait for the run in flight to reach a terminal status.
409 already_committed This import has already committed, or has been undone. There is never a second write pass. Create a new import to load the file again.
503 queue_unavailable The deployment has no import worker queue configured. Nothing was started. Retry once the worker is available.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
POST /api/v1/imports/{id}/undo Server-side

Queue the deletion of the rows this import created.

X-API-Key
Implementation details

Only from a commit that actually ran: `status: "completed"` with a recorded `committedAt`, or `status: "failed"` **with `dryRunAt` set**, which is a commit that died partway and left rows behind. A dry run writes nothing, so there is nothing to undo (a `failed` import with no `dryRunAt` is a failed VALIDATE), and a run still in flight must finish first. Deletes only rows this import CREATED, never a row it merely matched and updated. A created row that something else now depends on (a payment, a fulfillment, a return, a cart, an invoice, a subscription or a quote) is KEPT, and `keptReasons` names the relation that blocked each one rather than reporting a generic "in use". **Runs on the queue**: answers 202, moves the import to `undoing`, and writes the outcome to `undoResult` on the import row — poll GET /api/v1/imports/{id} the same way you poll a validate or a commit. The import is marked `undone` only when nothing was kept, so one whose rows were blocked stays undoable once the blocker clears.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesImport id.

Responses

202 The import row, unchanged — the delete is queued, and the worker moves the import to `undoing` a moment later. Poll GET /api/v1/imports/{id} and read `undoResult`, which is null until the job has run. A commit that COMPLETES after an undo was requested cancels it: the queued undo finds its precondition gone and does nothing, rather than reverting an import the merchant has just been told succeeded.

Response fields

FieldTypeRequiredDescription
undoResultobject | nullNoNull at 202. Once the job has run: { ordersDeleted, customersDeleted, ordersKept, customersKept, keptReasons }. `keptReasons` is keyed by the relation that blocked the delete, e.g. { "payments": 2, "quotes": 1 }; each kept row is counted once, under the first relation that claimed it, so the totals reconcile with ordersKept + customersKept.
statusstringNo`undone` only when nothing was kept. If rows were blocked it returns to `completed`/`failed` and stays undoable, so the merchant can retry once the blocker clears.

Common errors

Status Code Cause Fix
409 undo_not_available This import has written nothing to remove — it was only validated (a dry run writes nothing, whatever its counters say), its VALIDATE is what failed (`failed` with no `dryRunAt`), its commit failed before writing a row (`rowsCreated: 0`, no `committedAt`), a run is still in flight, or it has already been fully undone. Only an import whose commit actually wrote rows — completed, or failed partway after a passing dry run — has anything to remove. An import that wrote nothing needs no undo: re-map it and run it again.
503 queue_unavailable The deployment has no import worker queue configured. Nothing was deleted. Retry once the worker is available; an undo never runs inside the API process.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
GET /api/v1/imports/{id}/errors Server-side

The row-level error report.

X-API-Key
Implementation details

Generated on request from the stored row errors. `csv` is re-importable: the original columns of each failed row, plus `_row_number` (the line number in YOUR file, so a corrected re-upload still points at the right row), `_error_code` and `_error_message`. Column order is not the file’s. **Read `rowsIncluded` against `rowsFailed` before treating the report as complete** — at most 10,000 row errors are retained per pass, so a run with 40,000 failures returns 10,000 of them and `truncated: true`. Fix those, re-import, and repeat.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Path parameters

FieldTypeRequiredDescription
iduuidYesImport id.

Responses

200 The report.

Response fields

FieldTypeRequiredDescription
rowsFailedintegerNoRows the run rejected in total, uncapped.
rowsIncludedintegerNoRows this report actually contains. Lower than rowsFailed when the retention cap was reached.
truncatedbooleanNorowsIncluded < rowsFailed.
csvstringNoThe re-importable CSV, as text.
filenamestringNoSuggested download name.
errorsarrayNoThe same rows structured for display: { rowNumber, columnName, code, message }.

Common errors

Status Code Cause Fix
404 no_errors The import recorded no failed rows (including one that has not run yet). Nothing to fix — the run rejected nothing.
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.
GET /api/v1/imports Server-side

List imports, newest first.

X-API-Key
Implementation details

Scoped to the application and workspace environment the credential resolves to. Cursor-paginated: pass the previous page’s `meta.pagination.cursor` back as `cursor`; a null cursor means there are no more pages.

Headers

FieldTypeRequiredDescription
x-api-keystringYesYour Throttle secret API key. Keep this on your backend only.

Query parameters

FieldTypeRequiredDescription
limitintegerNoPage size, 1 to 100.
Default: 25
cursoruuidNoThe id of the last import on the previous page.

Responses

200 A page of imports, newest first.

Common errors

Status Code Cause Fix
401 unauthorized Missing, malformed, or revoked API key. Send a valid secret key from your backend and rotate the key if it may have leaked.
422 validation_error A required field is missing or a field does not match the expected type, enum, or format. Compare the body against the field table. Amounts are integer minor units and UUID fields must be valid UUIDs.