Curated referenceAPI 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-tokenServer-side
Create a payment-ready proxy checkout session.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
amount | integer | Yes | Amount to charge in minor units, for example 2599 for $25.99. |
currency | string | Yes | Three-letter ISO 4217 currency code. |
country | string | No | Two-letter ISO 3166-1 country code. Defaults to US. Default: US |
externalCartId | string | No | Your cart reference. Stored on session metadata for reconciliation. |
Responses
200Session created and embed URLs returned.
Response fields
| Field | Type | Required | Description |
|---|
checkoutSessionId | string | Yes | Durable Throttle session id. Use this as the React embed sessionId. |
embedToken | string | Yes | Short-lived provider embed JWT. The hosted iframe can re-mint it later. |
hostedUrl | url | Yes | Standalone hosted checkout URL. |
embedUrl | url | Yes | Chromeless 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 Gr4vy widget renders the methods configured on your connection and cannot be filtered here. | Remove allowedMethods. To restrict methods, configure the Gr4vy connection, or use the full hosted checkout where allowedMethods filters the selection. |
| 422 | no_gr4vy_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.
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/sessionsServer-side
Create a cart-backed hosted checkout session.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
applicationId | uuid | Yes | Application that owns the checkout session. |
cartId | uuid | No | Throttle native cart id. Required unless externalCartId is provided. |
externalCartId | string | No | Merchant/provider cart reference. Required unless cartId is provided. |
returnUrl | url | Yes | Buyer return URL after hosted checkout success. |
cancelUrl | url | Yes | Buyer return URL when checkout is cancelled. |
customerEmail | string | No | Buyer email used for checkout and recurring setup when customer is not supplied. |
customer | object | No | Optional prefill object with customerId, externalCustomerId, email, names, phone, shippingAddress, billingAddress, and metadata. |
allowedMethods | string[] | No | Optional card/net30 payment method allowlist for this session. |
paymentTerms.netN | integer | null | No | Optional cart-level Invoice Terms override, 0-365. Customer netN still wins; null clears the cart override. |
recurring | object | No | Subscription intent: plan, interval, amount, trialDays, planName, and create mode auto/manual. |
collect | object | No | Controls required checkout fields. shippingAddress defaults to true; billingAddress defaults to false. |
discountCode | string | No | Optional promotion code to validate and apply synchronously during session creation. |
metadata | object | No | Up to 50 keys and 10 KB of merchant-owned JSON metadata. |
Responses
201Checkout session created.
Response fields
| Field | Type | Required | Description |
|---|
id | string | Yes | Session id used by hosted checkout and React embed components. |
status | open | completed | expired | cancelled | Yes | Session lifecycle state. |
hostedUrl, embedUrl | url | No | Hosted 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.
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-tokenBrowser-safe
Refresh the iframe embed token for an existing session.
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
| Field | Type | Required | Description |
|---|
id | string | Yes | Open checkout session id. |
Responses
200Fresh embed token and payment processor context.
Response fields
| Field | Type | Required | Description |
|---|
embedToken | string | Yes | Fresh provider embed JWT. |
amount, currency | integer, string | No | Amount and currency resolved from session metadata, cart totals, or the latest calculation snapshot. |
gr4vyCheckoutSessionId | string | No | Processor-side checkout session id. |
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-methodsBrowser-safe
List eligible payment methods for a checkout session.
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
| Field | Type | Required | Description |
|---|
id | string | Yes | Open checkout session id. |
Responses
200Eligible payment method list.
Response fields
| Field | Type | Required | Description |
|---|
methods[].method | card | net30 | string | Yes | Payment method key used by the completion payload. |
methods[].displayName | string | Yes | Buyer-facing method label. |
methods[].connectorId | string | No | Connector that supplied the method. |
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}/completeBrowser-safe
Complete a buyer-facing checkout session.
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
| Field | Type | Required | Description |
|---|
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | string | Yes | Open checkout session id. |
Request body
| Field | Type | Required | Description |
|---|
paymentMethod | card | gr4vy | net30 | Yes | Completion path selected by the buyer. |
email | string | No | Buyer email. Required for card and net30 modes when not already collected. |
shippingAddress | object | No | Shipping address object when the session collect flags require it. |
billingAddress | object | No | Billing address object when the session collect flags require it. |
paymentToken | string | No | Card payment token for the unified card path. |
gr4vyTransactionId | string | No | Provider transaction id for proxy mode. |
net30Acceptance | object | No | termsHash, acceptedAt, companyName, and billingEmail for Net 30 checkout. |
Responses
200Checkout completed.
Response fields
| Field | Type | Required | Description |
|---|
orderId | uuid | Yes | Created or updated order id. |
paymentId | uuid | Yes | Payment record created for the completed checkout. |
subscriptionId | uuid | No | Returned 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. |
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/cartsServer-side
Create a native Throttle cart.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
applicationId | uuid | Yes | Application that owns the cart. |
customerId | uuid | No | Optional Throttle customer id to attach to the cart. |
customerEmail | string | No | Optional lightweight email capture (no full customer record). Makes an otherwise-anonymous abandoned cart recoverable. A linked customer’s email takes precedence. |
currency | string | No | Three-letter currency code. Default: USD |
metadata | object | No | Merchant-owned JSON metadata. |
Responses
201Cart created.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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.
Implementation details
Read the current cart, including totals, line items, selected shipping, tax lines, and applied discount state.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Responses
200Cart snapshot returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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.
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.
Implementation details
Patch the customer id, addresses, notes, or metadata on an open native cart.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Request body
| Field | Type | Required | Description |
|---|
customerId | uuid | No | Throttle customer id. |
customerEmail | string | No | Lightweight email capture; pass null to clear. |
shippingAddress | CartAddress | No | Canonical address (required addressLine1, city, countryCode). Non-canonical keys are rejected at write time. |
billingAddress | CartAddress | No | Canonical address (same shape as shippingAddress). |
notes | string | No | Internal cart notes. |
metadata | object | No | Merchant-owned JSON metadata. |
Responses
200Updated cart returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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}/itemsServer-side
Add a line item to a cart.
Implementation details
Use this for products, services, tickets, donations, custom items, and subscription line items before checkout.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Request body
| Field | Type | Required | Description |
|---|
type | product | subscription | service | ticket | donation | custom | No | Line item type. Default: product |
referenceId | string | No | Your SKU, plan id, ticket id, or other external item reference. |
name | string | Yes | Buyer-facing item name. |
description | string | No | Optional item description. |
unitPrice | integer | Yes | Unit price in minor units (cents). |
quantity | integer | No | Quantity, minimum 1. Default: 1 |
taxAmount | integer | No | Optional item tax amount in minor units. |
discountAmount | integer | No | Optional item discount amount in minor units. |
imageUrl | string | No | Optional 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. |
requiresShipping | boolean | No | Whether 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. |
metadata | object | No | Merchant-owned item metadata. |
Responses
201Line item added.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Line item id. |
name | string | Yes | Item name. |
unitPrice, quantity, total | integer | No | Pricing fields in minor units. |
metadata | object | No | Item 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.
Implementation details
Patch quantity, price, tax, discount, or metadata for an existing cart line item.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
cartId | uuid | Yes | Cart id. |
id | uuid | Yes | Line item id. |
Request body
| Field | Type | Required | Description |
|---|
quantity | integer | No | Quantity, minimum 1. |
unitPrice | integer | No | Unit price in minor units. |
taxAmount | integer | No | Tax amount in minor units. |
discountAmount | integer | No | Discount amount in minor units. |
metadata | object | No | Replacement item metadata. |
Responses
200Updated 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.
Implementation details
Deletes a line item from an open native cart.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
cartId | uuid | Yes | Cart id. |
id | uuid | Yes | Line item id. |
Responses
204Line 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}/shippingServer-side
Select a shipping method for a cart.
Implementation details
Persist the buyer-selected shipping option before final checkout. Use the id returned from shipping/tax calculation when possible.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Request body
| Field | Type | Required | Description |
|---|
methodId | string | Yes | Shipping method id. |
displayName | string | Yes | Buyer-facing shipping label. |
rateAmount | integer | Yes | Shipping rate in minor units. |
currency | string | No | Three-letter currency code. |
carrier | string | No | Optional carrier name. |
serviceCode | string | No | Optional carrier service code. |
estimatedDeliveryDays | integer | No | Optional delivery estimate in days. |
Responses
200Cart returned with selectedShipping populated.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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}/shippingServer-side
Clear selected shipping from a cart.
Implementation details
Use when the buyer changes address, shipping is no longer required, or the selected method is no longer available.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Responses
200Cart returned with selectedShipping cleared.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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-linesServer-side
Replace tax lines on a cart.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Request body
| Field | Type | Required | Description |
|---|
lines | array | Yes | Complete replacement list of tax lines. |
lines[].lineItemId | uuid | Yes | Line item receiving the tax. |
lines[].jurisdictionCode | string | Yes | Tax jurisdiction code. |
lines[].jurisdictionName | string | No | Human-readable jurisdiction name. |
lines[].taxType | sales | vat | gst | pst | hst | service | excise | other | Yes | Tax category. |
lines[].rate | number | Yes | Decimal rate between 0 and 1. |
lines[].amount | integer | Yes | Tax amount in minor units. |
lines[].currency | string | No | Three-letter currency code. |
Responses
200Cart returned with replacement taxLines.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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-linesServer-side
Clear all tax lines from a cart.
Implementation details
Remove persisted tax lines when the cart address changes, the tax mode changes, or you need to recompute taxes from scratch.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Responses
200Cart returned with taxLines cleared.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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-discountServer-side
Apply a promotion code to a cart.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Request body
| Field | Type | Required | Description |
|---|
code | string | Yes | Promotion code to apply. |
Responses
200Cart returned with appliedDiscount populated.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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}/discountServer-side
Remove the active promotion code from a cart.
Implementation details
Clears the applied discount snapshot and returns the cart without an active promotion code.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Responses
200Cart returned with appliedDiscount cleared.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle cart identifier used by all cart mutation endpoints. |
status | open | checkout | converted | abandoned | Yes | Current cart lifecycle state. Only open carts should be mutated. |
currency | string | Yes | ISO 4217 currency used for all cart totals. |
subtotal, taxTotal, discountTotal, shippingTotal, total | integer | Yes | Cart totals in minor units. |
lineItems | array | No | Line items included when reading a cart or after item mutations. |
appliedDiscount | object | null | No | Snapshot of the active promotion code, if one is applied. |
selectedShipping | object | null | No | Selected shipping method and rate, if one has been selected. |
taxLines | array | No | Tax line breakdown persisted on the cart. |
metadata | object | No | Merchant-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}/checkoutServer-side
Convert a cart into an order.
Implementation details
Call after items, discount, shipping, and final tax calculation are ready. This creates the order that payment and fulfillment workflows use.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Request body
| Field | Type | Required | Description |
|---|
paymentMethod | string | No | Optional selected payment method such as card or net30. |
metadata | object | No | Optional checkout metadata. |
Responses
201Order created from cart.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Order id. |
orderNumber | string | No | Merchant-visible order number. |
status | draft | No | Initial order status. |
subtotal, total | integer | No | Order totals in minor units. |
cartId | uuid | No | Source 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}/eventsServer-side
Read immutable cart events.
Implementation details
Use cart events for polling/debugging cart mutations. For real-time delivery, subscribe to outbound webhooks.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
Query parameters
| Field | Type | Required | Description |
|---|
sinceSequence | integer | No | Return events after this sequence. |
limit | integer | No | Page size, 1 to 200. |
Responses
200Ordered cart event list.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Event id. |
eventType | string | Yes | Event name such as cart.item_added. |
sequence | integer | Yes | Monotonic per-cart sequence. |
payload | object | No | Event 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-cartsServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
limit | integer | No | Page size, 1 to 100 (default 25). |
cursor | string | No | Opaque cursor from the previous page. |
Responses
200Cursor-paginated abandoned carts.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Cart id. |
customer | object | null | No | Buyer identity ({ id, email, firstName }) or null for an anonymous cart. |
total | integer | No | Cart total in minor units (cents). |
currency | string | No | ISO-4217 currency code. |
itemCount | integer | No | Number of line items. |
abandonedAt | string | null | No | ISO-8601 timestamp the cart was marked abandoned. |
recoveryStatus | string | No | Whether a recovery email was sent, or recovery is webhook-only. Values: emailed, webhook_only |
GET/api/v1/abandoned-carts/summaryServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
sinceDays | integer | No | Trailing window in days, 1 to 365 (default 30). |
Responses
200Summary metrics.
Response fields
| Field | Type | Required | Description |
|---|
sinceDays | integer | No | Window applied. |
abandonedCount | integer | No | Carts abandoned in the window. |
abandonedValue | integer | No | Sum of abandoned-cart totals in minor units (cents). |
recoveryEmailsSent | integer | No | Recovery emails dispatched in the window. |
POST/api/v1/shipping-tax/external-snapshotsServer-side
Push provider-owned shipping/tax totals.
Implementation details
Use when your application is in bring-your-own shipping or tax mode and an upstream provider owns the final totals.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
applicationId | uuid | Yes | Application receiving the snapshot. |
cartId | uuid | null | No | Optional Throttle cart to mirror totals onto. |
checkoutSessionId | string | null | No | Optional checkout session reference. |
orderId | uuid | null | No | Optional order reference. |
currency | string | No | Three-letter currency code. |
totals | object | Yes | subtotal, discountTotal, shippingTotal, taxTotal, and total in minor units. |
selectedShipping | object | null | No | Provider-selected shipping snapshot. |
taxLines | array | No | Provider tax line breakdown. |
source | string | No | Provider/source label for audit. |
Responses
200External 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/discountsServer-side
Create a discount.
Implementation details
Creates a percentage or fixed amount discount code for later preview and cart application.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
code | string | No | Promotion code. Leave empty for automatic discounts. |
name | string | Yes | Human-readable discount name. |
type | percentage | fixed_amount | Yes | Discount type. |
value | integer | Yes | Whole percent for percentage discounts, or minor units for fixed amount discounts. |
conditions | object | No | Optional conditions such as minOrder. |
usageLimit | integer | No | Optional global usage cap. |
maxRedemptionsPerCustomer | integer | null | No | Per-customer redemption cap. Use null for unlimited. Default: 1 |
startsAt, endsAt | date-time | No | Optional active window. |
metadata | object | No | Campaign or attribution metadata. |
Responses
201Discount created.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Discount id. |
code | string | No | Promotion code. |
type, value | string, integer | No | Discount calculation fields. |
isActive | boolean | No | Whether 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/discountsServer-side
List discounts.
Implementation details
Use for promotion management screens, campaign reconciliation, or validating which codes exist before checkout.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
cursor | string | No | Cursor for pagination. |
limit | integer | No | Page size, 1 to 100. Default: 10 |
isActive | boolean | No | Filter by active state. |
code | string | No | Filter by promotion code. |
type | percentage | fixed_amount | No | Filter by type. |
q | string | No | Search code, name, type, or metadata. |
sort | asc | desc | No | Sort by creation time. |
Responses
200Paginated 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.
Implementation details
Patch campaign metadata, active windows, usage limits, or the display name for an existing discount.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Discount id. |
Request body
| Field | Type | Required | Description |
|---|
code | string | No | Promotion code. |
name | string | No | Human-readable discount name. |
value | integer | No | Updated percent or fixed amount value. |
conditions | object | No | Replacement conditions object. |
usageLimit | integer | No | Updated global usage cap. |
maxRedemptionsPerCustomer | integer | null | No | Updated per-customer cap. |
startsAt, endsAt | date-time | No | Updated active window. |
metadata | object | No | Replacement metadata. |
Responses
200Updated 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.
Implementation details
Removes a discount from future use. Existing orders keep their historical discount snapshot.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Discount id. |
Responses
204Discount 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.
Prefer deactivation semantics in your UI copy if historical redemptions matter.
POST/api/v1/discounts/previewServer-side
Preview a code without mutating a cart.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
code | string | Yes | Promotion code to preview. |
currency | string | Yes | Three-letter currency code. |
subtotal | integer | Yes | Current subtotal in minor units. |
customerId | uuid | No | Optional customer id for redemption-limit checks. |
lineItems | array | No | Optional line item context for future item-level conditions. |
Responses
200Preview result.
Response fields
| Field | Type | Required | Description |
|---|
valid | boolean | Yes | Whether the code can currently be applied. |
code | string | No | Normalized code. |
discountTotal | integer | No | Discount amount in minor units. |
total | integer | No | Subtotal minus discount. |
message | string | No | Buyer-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.
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/configSetup
Read draft and published shipping/tax config.
Implementation details
Use setup tooling or advanced dashboards to show the active shipping/tax modes and catalog for an application.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
applicationId | uuid | Yes | Application id to read config for. |
Responses
200Draft and published configs returned.
Response fields
| Field | Type | Required | Description |
|---|
draft | object | null | No | Editable config draft. |
published | object | null | No | Published 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-tokensSetup
List publishable quote tokens for an application.
Implementation details
Use during setup to audit active quote tokens. Raw token values are not returned after creation.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
applicationId | uuid | Yes | Application id to list tokens for. |
Responses
200Quote 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-tokensSetup
Create a publishable storefront quote token.
Implementation details
Quote tokens start with pk_ and let a storefront request read-only estimates without exposing a secret key.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
applicationId | uuid | Yes | Application the token can quote for. |
name | string | Yes | Internal token label, 1 to 80 characters. |
expiresAt | date-time | null | No | Optional expiration time. |
Responses
200Token created. rawToken is shown once.
Response fields
| Field | Type | Required | Description |
|---|
rawToken | string | Yes | Publishable pk_ token. Store it safely client-side. |
tokenPrefix | string | No | Prefix shown later for identification. |
expiresAt | date-time | null | No | Expiration 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.
Implementation details
Soft-deletes and deactivates a pk_ token so storefront quote requests using it stop working.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
tokenId | uuid | Yes | Quote token id. |
Responses
200Revocation confirmation.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Revoked token id. |
revoked | boolean | No | Always 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/quotesBrowser-safe
Request a storefront shipping/tax estimate.
Publishable quote tokenGuide 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
| Field | Type | Required | Description |
|---|
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
applicationId | uuid | Yes | Application being quoted. |
quoteToken | string | Yes | Publishable pk_ token for this application. |
currency | string | No | Three-letter currency code. Defaults to application currency or USD. |
items | array | Yes | At least one item to quote. |
items[].id | string | Yes | SKU or item id. |
items[].subtotalAmount | integer | Yes | Line subtotal in minor units. |
items[].quantity | integer | No | Quantity, minimum 1. Default: 1 |
items[].requiresShipping | boolean | No | Whether the item needs shipping rates. |
items[].taxCategory | string | No | Tax category used by configured rules. |
discountsTotal | integer | No | Discount total in minor units. |
selectedShippingMethodId | string | null | No | Method id selected by the buyer. |
addresses.shipping | object | null | No | Shipping address fields such as countryCode, stateProvince, postalCode. |
addresses.billing | object | null | No | Billing address for tax rules that use billing address. |
Responses
200Estimated shipping/tax calculation.
Response fields
| Field | Type | Required | Description |
|---|
kind | quote | Yes | Calculation kind. |
status | estimated | final | failed | Yes | Calculation status. |
shipping.methods | array | No | Available shipping or pickup methods. |
tax.taxTotal | integer | No | Tax total in minor units. |
totals.total | integer | No | Estimated final total in minor units. |
prompts, warnings, errors | array | No | Missing 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}/calculateServer-side
Calculate shipping/tax for a native cart.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
cartId | uuid | Yes | Cart id. |
Request body
| Field | Type | Required | Description |
|---|
kind | cart_estimate | checkout_final | No | Estimate during browsing or final lock before payment. Default: cart_estimate |
selectedShippingMethodId | string | null | No | Buyer-selected method id to include in final totals. |
persist | boolean | No | Persist calculation snapshot and mirror selected shipping/tax lines onto the cart when supported. |
shippingAddress | object | null | No | Optional 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}. |
billingAddress | object | null | No | Optional inline billing address; persisted to the cart before calculation. |
Responses
200Cart calculation response.
Response fields
| Field | Type | Required | Description |
|---|
snapshotId | uuid | No | Persisted snapshot id when a snapshot is stored. |
shipping.methods | array | No | Available shipping methods. |
shipping.selectedMethod | object | null | No | Selected method if supplied. |
tax.lines | array | No | Tax line breakdown. |
totals | object | No | subtotal, 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.
GET/api/v1/ordersServer-side
List orders.
X-API-Key
Implementation details
Use for order history, reconciliation, and merchant-side operations dashboards.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
cursor | string | No | Cursor for pagination. |
limit | integer | No | Page size, 1 to 100. Default: 20 |
status | draft | pending | processing | partially_fulfilled | completed | cancelled | closed | No | Optional status filter. |
paymentStatus | pending | authorized | captured | partially_refunded | refunded | failed | voided | No | Optional payment status filter. |
q | string | No | Search order id, order number, status, source, discount code, or metadata. |
customerId | uuid | No | Optional customer filter. |
applicationId | uuid | No | Optional application filter. |
Responses
200Paginated order list.
Response fields
| Field | Type | Required | Description |
|---|
data[] | array | No | Order records. |
meta.pagination.cursor | string | null | No | Cursor for the next page. |
meta.pagination.hasMore | boolean | No | Whether 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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Order id. |
Responses
200Order detail returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Order id. |
status | string | No | Order lifecycle state. |
lineItems | array | No | Order line items. |
subtotal, total | integer | No | Order totals in minor units. |
metadata | object | No | Order 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.
GET/api/v1/paymentsServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
method | string | No | Filter by payment method (e.g. net30, card, manual, external). |
status | string | No | Filter by payment status. Repeat the parameter for multi-status OR logic (e.g. status=authorized&status=captured). |
order_id | uuid | No | Return payments belonging to a specific order. |
due_from | YYYY-MM-DD | No | Inclusive lower bound on metadata.dueDate (ISO date). |
due_to | YYYY-MM-DD | No | Inclusive upper bound on metadata.dueDate (ISO date). |
amount_min | integer | No | Inclusive minimum payment amount in minor currency units (cents). |
amount_max | integer | No | Inclusive maximum payment amount in minor currency units (cents). |
aging | 0_30 | 31_60 | 61_90 | 90_plus | No | Filter to a Net-N aging bucket based on days since the invoice due date. |
limit | integer | No | Page size, 1 to 100. Default: 20 |
cursor | string | No | Opaque pagination cursor returned by the previous response. |
Responses
200Payments matching the filters, ordered by createdAt DESC.
Response fields
| Field | Type | Required | Description |
|---|
data[] | array | No | Payment records. |
meta.pagination.cursor | string | null | No | Cursor 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}/paymentsServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Order id. |
Responses
200Payments attached to the order.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Payment id. |
status | string | No | Payment status. |
amount, currency | integer, string | No | Payment amount and currency. |
method | card | net30 | manual | external | ... | No | Payment 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}/transactionsServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Payment id. |
Responses
200Payment transactions returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Transaction id. |
paymentId | uuid | No | Payment this transaction belongs to. |
type | authorization | capture | refund | void | ... | No | Processor transaction type. |
status | string | No | Transaction status. |
amount, currency | integer, string | No | Transaction 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}/refundServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Payment id. |
Request body
| Field | Type | Required | Description |
|---|
amount | integer | No | Partial refund amount in minor units. Omit for a full refund. |
Responses
200Refund recorded or processor refund initiated.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Payment id. |
status | string | No | Updated payment/refund status. |
refundedAmount | integer | No | Total 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-pdfServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Net 30 payment id. |
Responses
200Signed download information.
Response fields
| Field | Type | Required | Description |
|---|
url | url | Yes | Temporary 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/resendServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Net 30 payment id. |
Responses
200Invoice email queued.
Response fields
| Field | Type | Required | Description |
|---|
messageId | uuid | string | Yes | Queued 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
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Net 30 payment id. |
Query parameters
| Field | Type | Required | Description |
|---|
token | jwt | Yes | Signed invoice download token from the email. |
Responses
302Redirects to a short-lived signed PDF URL.
Response fields
| Field | Type | Required | Description |
|---|
Location | url | Yes | Temporary 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-endpointsWebhook operations
List configured webhook endpoints.
Implementation details
Returns active and paused outbound webhook endpoints. Deleted endpoints are excluded.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Responses
200Webhook endpoint list.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Endpoint id. |
url | url | No | Delivery URL. |
enabledEvents | array | No | Subscribed event types. |
isActive | boolean | No | Whether 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-endpointsWebhook operations
Create a signed outbound webhook endpoint.
Implementation details
Register the HTTPS URL that receives durable order, payment, cart, subscription, discount, customer, and fulfillment events.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
url | https URL | Yes | Your webhook receiver URL. Must use https. |
enabledEvents | string[] | Yes | Event types to deliver. Must be non-empty and unique. |
Responses
201Webhook endpoint created. signingSecret is returned once.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Webhook endpoint id. |
url | url | Yes | Delivery URL. |
enabledEvents | array | Yes | Subscribed event list. |
isActive | boolean | Yes | Whether delivery is active. |
signingSecret | string | Yes | HMAC 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. |
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.
Implementation details
Use this to rotate receivers, pause delivery, resume delivery, or change subscribed events.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Webhook endpoint id. |
Request body
| Field | Type | Required | Description |
|---|
url | https URL | No | New delivery URL. |
enabledEvents | string[] | No | Replacement event list. |
isActive | boolean | No | false pauses dispatch; true resumes it. |
Responses
200Updated 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.
Implementation details
Stops future dispatch and removes the endpoint from list responses. Create a new endpoint to subscribe again.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Webhook endpoint id. |
Responses
200Deleted 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-deliveriesWebhook operations
Inspect recent webhook delivery attempts.
Implementation details
Use for debugging and operational audit views. This endpoint returns attempts, not the endpoint configuration itself.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
endpointId | uuid | No | Filter by webhook endpoint. |
orderId | uuid | No | Filter by related order. |
limit | integer | No | Page size, 1 to 200. Default: 50 |
offset | integer | No | Offset pagination start. Default: 0 |
Responses
200Delivery page.
Response fields
| Field | Type | Required | Description |
|---|
items | array | No | Delivery attempts. |
total | integer | No | Total matching attempts. |
hasMore | boolean | No | Whether 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}/testWebhook operations
Send a synthetic signed test event.
Implementation details
Use during setup to verify URL reachability, signature validation, and handler routing without waiting for a real checkout event.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Webhook endpoint id. |
Request body
| Field | Type | Required | Description |
|---|
eventType | documented outbound webhook event type | No | Synthetic event type. Defaults to payment.captured. |
Responses
200Synthetic 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-secretWebhook operations
Rotate the endpoint signing secret (reveal-once).
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Webhook endpoint id. |
Responses
200New signing secret returned (shown once).
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Webhook endpoint id. |
signingSecret | string | No | The 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}/replayWebhook operations
Replay a prior webhook delivery.
Implementation details
Re-fires the same event payload with a fresh signature. Use after fixing a receiver bug or recovering from downtime.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Delivery id. |
Responses
200Replay 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-configSetup
Read allowed origins and checkout branding.
Implementation details
Use this in setup tooling or dashboards to show which parent origins and brand values are currently configured.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Responses
200Current embed config.
Response fields
| Field | Type | Required | Description |
|---|
allowedOrigins | string[] | No | Origins allowed to embed checkout. |
primaryColor | string | null | No | Default checkout brand color. |
logoUrl | url | null | No | Default checkout logo. |
merchantName | string | null | No | Buyer-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-configSetup
Set allowed origins and checkout branding.
Implementation details
Required before embedding checkout in production. The parentOrigin passed to the SDK must match an allowed origin.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
allowedOrigins | string[] | No | Allowed parent origins. Max 20, unique. |
primaryColor | string | No | Brand color forwarded to hosted checkout (hex `#rrggbb`). |
logoUrl | url | No | Logo URL used by hosted checkout. |
merchantName | string | No | Buyer-facing merchant name, 1 to 100 characters. |
cartRecoveryUrlTemplate | string | null | No | Absolute 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. |
cartAbandonmentThresholdMinutes | integer | null | No | Minutes 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
200Updated 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.
Subscriptions
Use recurring checkout plus subscription APIs for buyer portals and merchant-side management.
POST/api/v1/subscriptionsServer-side
Create a subscription manually.
Implementation details
Use for manual creation flows after a vaulted payment method exists. Embed-driven create:auto remains the fastest checkout path.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
customerId | uuid | Yes | Throttle customer id. |
applicationId | uuid | No | Optional application id. |
planReference | string | Yes | Your plan id. |
planName | string | No | Buyer-facing plan name. |
interval | weekly | monthly | quarterly | yearly | Yes | Billing interval. |
amount | integer | Yes | Recurring amount in minor units. |
currency | string | No | Three-letter currency code. Default: USD |
currentPeriodStart | date-time | Yes | Current period start (ISO 8601). |
currentPeriodEnd | date-time | Yes | Current period end (ISO 8601). |
trialEnd | date-time | No | Optional trial end. |
metadata | object | No | Merchant-owned 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. |
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/subscriptionsServer-side
List subscriptions for a buyer portal or backend job.
Implementation details
Filter by Throttle customer id, your external customer id, or status. Proxy this through your backend for buyer-facing portals.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Query parameters
| Field | Type | Required | Description |
|---|
cursor | string | No | Cursor for pagination. |
limit | integer | No | Page size, 1 to 100. Default: 20 |
customerId | uuid | No | Throttle customer id filter. |
externalCustomerId | string | No | Your customer id. Mutually exclusive with customerId. |
status | active | paused | cancelled | past_due | trialing | No | Optional status filter. |
interval | weekly | monthly | quarterly | yearly | No | Optional billing interval filter. |
q | string | No | Search subscription id, customer id, plan, status, interval, or metadata. |
Responses
200Paginated 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.
Implementation details
Use for buyer portal detail pages, support tooling, and access-gating checks.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
Responses
200Subscription 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.
Implementation details
Updates plan reference, display name, interval, amount, or metadata. Changes apply according to the subscription lifecycle rules documented in the guide.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
Request body
| Field | Type | Required | Description |
|---|
planReference | string | No | Updated plan id. |
planName | string | No | Updated plan name. |
interval | weekly | monthly | quarterly | yearly | No | Updated interval. |
amount | integer | No | Updated amount in minor units. |
metadata | object | No | Replacement metadata. |
Responses
200Updated 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}/pauseServer-side
Pause a subscription.
Implementation details
Moves an active subscription into paused state from your backend proxy.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
Responses
200Paused 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}/resumeServer-side
Resume a paused subscription.
Implementation details
Moves a paused subscription back into an active billing state.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
Responses
200Resumed 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}/cancelServer-side
Cancel a subscription immediately or at period end.
Implementation details
Use from buyer portals and support tooling. For buyer-facing use, authorize ownership in your backend before calling Throttle.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
Request body
| Field | Type | Required | Description |
|---|
atPeriodEnd | boolean | No | If true, cancels at the end of the current billing period. Default: false |
Responses
200Updated 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-checkServer-side
Check trial eligibility for a vaulted card.
Implementation details
Pre-flight trial fraud protection by checking whether a payment method fingerprint has already used a trial for this merchant.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
paymentMethodId | uuid | Yes | Customer payment method id owned by the authenticated merchant. |
Responses
200Eligibility result.
Response fields
| Field | Type | Required | Description |
|---|
eligible | boolean | No | Whether the payment method can receive a trial. |
reason | string | No | Reason 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.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
externalId | string | Yes | Your customer or user id previously passed as externalCustomerId. |
Responses
200Customer returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Throttle customer id. |
externalId | string | null | No | Your customer id when one is attached. |
email | string | null | No | Customer email. |
metadata | object | No | Customer 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-methodsServer-side
List saved payment methods for a customer.
Implementation details
Use on subscription confirmation pages and buyer portals when you need to show the vaulted card summary used for renewals.
Headers
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Customer id. |
Responses
200Saved payment-method summaries returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Payment method id. |
methodType | card | string | No | Payment method type. |
cardBrand | string | null | No | Card brand. |
cardLastFour | string | null | No | Last four digits for card methods. |
isDefault | boolean | No | Whether this method is the default renewal method. |
isActive | boolean | No | Whether 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}/pauseServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
customerId | uuid | Yes | Customer id. |
id | uuid | Yes | Payment method id. |
Responses
200Updated payment method returned with isActive=false.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Payment method id. |
isActive | boolean | No | False 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}/resumeServer-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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
customerId | uuid | Yes | Customer id. |
id | uuid | Yes | Payment method id. |
Responses
200Updated payment method returned with isActive=true.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Payment method id. |
isActive | boolean | No | True 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-planServer-side
Change a subscription plan immediately or at period end.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
Request body
| Field | Type | Required | Description |
|---|
planReference | string | Yes | Your plan id from your plan catalog. |
planName | string | No | Buyer-facing plan name. |
interval | weekly | monthly | quarterly | yearly | Yes | Billing interval for the new plan. |
amount | integer | Yes | Recurring 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
200Updated subscription returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
status | string | Yes | Current status. |
pendingPlanReference | string | null | No | Set when effective: "period_end". Contains the deferred plan id. Null for effective: "now". |
pendingPlanName | string | null | No | Deferred plan display name. Null when no change is pending. |
pendingInterval | string | null | No | Deferred billing interval. Null when no change is pending. |
pendingAmount | integer | null | No | Deferred 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. |
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"
}'
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.
DELETE/api/v1/subscriptions/{id}/pending-changeServer-side
Cancel a scheduled plan change.
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
| Field | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Throttle secret API key. Keep this on your backend only. |
Path parameters
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
Responses
200Updated subscription returned with all pending_* fields null.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Subscription id. |
pendingPlanReference | null | No | Always null after clear. |
pendingPlanName | null | No | Always null after clear. |
pendingInterval | null | No | Always null after clear. |
pendingAmount | null | No | Always 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. |
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}/environmentsSetup
List workspace environments.
Implementation details
Returns active workspace environments by default. Add includeArchived=true for settings, audit, or recovery screens.
Headers
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Path parameters
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
Query parameters
| Field | Type | Required | Description |
|---|
includeArchived | true | false | No | When true, includes archived custom environments. Default: false |
Responses
200Workspace environments returned.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | Yes | Environment id. |
slug | string | Yes | Environment slug used in API key prefixes. |
name | string | Yes | Human-readable environment name. |
kind | production | non_production | Yes | Production is the only production kind. |
providerEnvironment | production | sandbox | Yes | Provider routing target. |
status | active | archived | Yes | Archived environments are hidden from normal selectors. |
isSystem | boolean | Yes | System 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}/environmentsSetup
Create a custom non-production environment.
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Path parameters
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
Request body
| Field | Type | Required | Description |
|---|
slug | string | Yes | Unique workspace slug. It is normalized to lowercase kebab-case and cannot be production. |
name | string | Yes | Display name shown in the dashboard selector and settings. |
Responses
201Custom environment created.
Common errors
| Status | Code | Cause | Fix |
|---|
| 400 | reserved_environment_slug | Slug is production. | 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.
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Path parameters
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
environmentId | uuid | Yes | Environment id to archive. |
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 slug (for example sk_uat_ or sk_production_) that pins the key to one environment. Never expose a secret key in browser code.
GET/api/v1/api-keysSetup
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
| Field | Type | Required | Description |
|---|
authorization or x-api-key | string | Yes | Clerk JWT for dashboard flows or secret key for backend setup tooling. |
Responses
200Active key metadata. Raw secret values are never returned.
POST/api/v1/api-keysSetup
Create a secret (sk_) or publishable (pk_) API key.
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 slug, for example sk_uat_/pk_uat_ or sk_production_/pk_production_. 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
| Field | Type | Required | Description |
|---|
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
name | string | Yes | Key label. |
scopes | string[] | Yes | Scopes 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
201Key created.
Response fields
| Field | Type | Required | Description |
|---|
rawKey | string | Yes | Raw key, prefixed by type + environment slug (for example sk_uat_ or pk_production_). Returned once. |
id, name, scopes | string, string, array | No | Key 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
| Field | Type | Required | Description |
|---|
id | uuid | Yes | API key id. |
Responses
204Key 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}/invitesSetup
Create a workspace invitation.
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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
Request body
| Field | Type | Required | Description |
|---|
email | string | Yes | Invitee email address. |
workspaceRole | string | No | Workspace-level role to grant on accept. One of workspace_admin. Omit for application-only access. |
applicationRoles | array | No | Per-application role assignments. Each entry is { applicationId, role } where role is admin | developer | finance | viewer. |
environmentGrants | object | No | Workspace-wide environment access. Shape: { grantType: all | all_non_production | production_only | selected, environmentIds?: uuid[] }. selected requires at least one active environment id. |
Responses
201Invitation created and email sent.
Response fields
| Field | Type | Required | Description |
|---|
id | uuid | No | Invitation id. |
email | string | No | Invitee email. |
status | string | No | Always pending on creation. |
expiresAt | ISO 8601 | No | Token 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}/invitesSetup
List workspace invitations.
Clerk JWT
Implementation details
Returns all invitations for the workspace, including pending, accepted, revoked, and expired. Filterable by status.
Path parameters
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
Query parameters
| Field | Type | Required | Description |
|---|
status | string | No | Filter by invitation status. One of pending | accepted | revoked | expired. |
Responses
200Invitation list.
Response fields
| Field | Type | Required | Description |
|---|
items | array | No | Array of invitation objects. |
total | integer | No | Total matching invitations. |
POST/api/v1/workspaces/{workspaceId}/invites/{id}/resendSetup
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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
id | uuid | Yes | Invitation id. |
Responses
200Token rotated, email resent.
Response fields
| Field | Type | Required | Description |
|---|
expiresAt | ISO 8601 | No | New 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}/revokeSetup
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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
id | uuid | Yes | Invitation id. |
Responses
204Invitation revoked. No JSON body.
POST/api/v1/invites/acceptSetup
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
| Field | Type | Required | Description |
|---|
token | string | Yes | Signed JWT from the invite email link. |
Responses
200Member joined.
Response fields
| Field | Type | Required | Description |
|---|
workspaceId | uuid | No | The joined workspace. |
memberId | uuid | No | New 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}/membersSetup
List workspace members.
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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
Responses
200Member list.
Response fields
| Field | Type | Required | Description |
|---|
items | array | No | Array of member objects. |
items[].environmentGrants | object | No | Environment grant summary: { grantType, environmentIds }. Owners resolve to all. |
total | integer | No | Total member count. |
GET/api/v1/workspaces/{workspaceId}/members/meSetup
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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
Responses
200Caller's membership record.
Response fields
| Field | Type | Required | Description |
|---|
memberId | uuid | No | Membership record id. |
workspaceRole | string | No | owner | workspace_admin | null. |
applicationRoles | array | No | Per-application role assignments. |
environmentGrants | object | No | Environment 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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
memberId | uuid | Yes | Member id. |
Request body
| Field | Type | Required | Description |
|---|
workspaceRole | string | No | New workspace role. One of workspace_admin or null to remove. |
applicationRoles | array | No | Per-application role assignments to upsert. Each entry is { applicationId, role }. |
environmentGrants | object | No | Replace environment access. Shape: { grantType: all | all_non_production | production_only | selected, environmentIds?: uuid[] }. |
Responses
200Updated 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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
memberId | uuid | Yes | Member id. |
Responses
204Member 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
| Field | Type | Required | Description |
|---|
workspaceId | uuid | Yes | Workspace id. |
memberId | uuid | Yes | Member id. |
applicationId | uuid | Yes | Application to revoke access on. |
Responses
204Application role revoked. No JSON body.
GET/api/v1/auth/permissionsSetup
Resolve permissions for the authenticated caller.
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
200Permissions map.
Response fields
| Field | Type | Required | Description |
|---|
workspaceRole | string | No | Caller workspace role or null. |
appRole | string | No | Caller application role on x-application-id or null. |
permissions | object | No | Map 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-routingSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Responses
200Current routing config.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | Ordered list of condition-based routing rules. Each rule is evaluated in order; the first rule whose conditions all match is applied. |
data.rules[].conditions | array | Yes | Array 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[].type | string | Yes | Condition 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[].op | string | Yes | Operator: 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[].values | string[] | No | Array 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[].key | string | No | Metadata 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[].currency | string | No | Currency for amount conditions (e.g., "USD"). Required for amount conditions. |
data.rules[].conditions[].min | number | No | Minimum amount in major units (e.g., dollars, not cents) for "gt" or "between" operators. |
data.rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. |
data.rules[].cascade | string[] | Yes | Ordered list of connector IDs to use when this rule matches. First entry is attempted first; subsequent entries are automatic fail-over. |
data.defaultCascade | string[] | Yes | Ordered 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. Check Gr4vy status if the error persists. |
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>"
{
"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-routingSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
rules | array | Yes | Array 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[].conditions | array | Yes | Array of conditions for this rule. All conditions must be satisfied (AND-ed) for the rule to match. May be empty. |
rules[].conditions[].type | string | Yes | Condition type: "country", "cardScheme", "cardSource", "cardType", "cardCountry", "paymentSource", "amount", or "metadata". |
rules[].conditions[].op | string | Yes | Operator. 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[].values | string[] | No | For 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[].key | string | No | Metadata 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[].currency | string | No | Currency code for amount conditions (e.g., "USD"). Required for amount type. |
rules[].conditions[].min | number | No | Minimum amount in major units for "gt" or "between" operators. Required for those operators. |
rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. Required for those operators. |
rules[].cascade | string[] | Yes | Ordered list of connector IDs for this rule. Must contain at least one entry and must not have duplicates. |
defaultCascade | string[] | Yes | Ordered connector IDs tried for any transaction not matched by any rule. Must contain at least one entry and must not have duplicates. |
Responses
200Updated routing config returned.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | The persisted rules after the update. |
data.defaultCascade | string[] | Yes | The 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. The routing config was not partially applied. |
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-connectorsSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Responses
200List of available connectors.
Response fields
| Field | Type | Required | Description |
|---|
data[].id | string | Yes | Connector ID to use in cascade arrays. |
data[].displayName | string | Yes | Human-readable connector label. |
data[].method | string | No | Payment 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. |
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>"
{
"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-methodsSetup
List Gr4vy payment methods available to routing and decline rules.
Clerk JWT
Implementation details
Returns the payment methods Gr4vy supports 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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Responses
200List of available Gr4vy payment methods.
Response fields
| Field | Type | Required | Description |
|---|
data[].id | string | Yes | Payment method id to use as a paymentMethod condition value or an Other-routing rule method (e.g. "paypal", "ideal", "sepa"). |
data[].label | string | Yes | Human-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 | gr4vy_upstream_error | The Gr4vy payment-method-definitions API returned an unexpected error. | Retry after a short delay. Check Gr4vy status if the error persists. |
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>"
{
"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-declineSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Responses
200Current card-decline rules.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | Ordered 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[].conditions | array | Yes | Array 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[].type | string | Yes | Condition 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[].op | string | Yes | Operator: 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[].values | string[] | No | Array 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[].key | string | No | Metadata key to match against. Required for metadata conditions. |
data.rules[].conditions[].currency | string | No | Currency for amount conditions (e.g., "USD"). Required for amount conditions. |
data.rules[].conditions[].min | number | No | Minimum amount in major units for "gt" or "between" operators. |
data.rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. |
data.rules[].errorCode | string | No | Optional 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. Check Gr4vy status if the error persists. |
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>"
{
"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-declineSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
rules | array | Yes | Array of decline rules. May be empty to disable all decline rules. Rules are evaluated in order. |
rules[].conditions | array | Yes | Array 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[].type | string | Yes | Condition type: "country", "cardScheme", "cardSource", "cardType", "cardCountry", "amount", or "metadata". |
rules[].conditions[].op | string | Yes | Operator. 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[].values | string[] | No | For 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[].key | string | No | Metadata key to match against. Required for metadata conditions. |
rules[].conditions[].currency | string | No | Currency code for amount conditions (e.g., "USD"). Required for amount type. |
rules[].conditions[].min | number | No | Minimum amount in major units for "gt" or "between" operators. Required for those operators. |
rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. Required for those operators. |
rules[].errorCode | string | No | Optional 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
200Updated card-decline rules returned.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | The 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. The decline rules were not partially applied. |
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-routingSetup
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 Gr4vy default (first active connection for the payment method and currency).
Headers
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Responses
200Current non-card routing config.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | Ordered 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[].method | string | Yes | Payment method this rule applies to (e.g. "paypal", "ideal", "sepa"). Only transactions of this method are tested against this rule's conditions. |
data.rules[].conditions | array | Yes | Array 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[].type | string | Yes | Condition 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[].op | string | Yes | Operator: 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[].values | string[] | No | Array 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[].key | string | No | Metadata key to match against. Required for metadata conditions. |
data.rules[].conditions[].currency | string | No | Currency for amount conditions (e.g., "USD"). Required for amount conditions. |
data.rules[].conditions[].min | number | No | Minimum amount in major units for "gt" or "between" operators. |
data.rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. |
data.rules[].connections | string[] | Yes | Ordered 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. Check Gr4vy status if the error persists. |
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>"
{
"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 Gr4vy 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-routingSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
rules | array | Yes | Array of non-card routing rules. May be empty to disable custom non-card routing. Rules are evaluated in order. |
rules[].method | string | Yes | Payment 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[].conditions | array | Yes | Array 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[].type | string | Yes | Condition type: "country", "currency", "amount", or "metadata". Card-specific types (cardScheme, cardSource, cardType) are not permitted. |
rules[].conditions[].op | string | Yes | Operator. 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[].values | string[] | No | For 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[].key | string | No | Metadata key to match against. Required for metadata conditions. |
rules[].conditions[].currency | string | No | Currency code for amount conditions (e.g., "USD"). Required for amount type. |
rules[].conditions[].min | number | No | Minimum amount in major units for "gt" or "between" operators. Required for those operators. |
rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. Required for those operators. |
rules[].connections | string[] | Yes | Ordered 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
200Updated non-card routing config returned.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | The 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. The routing config was not partially applied. |
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 Gr4vy default. There is no pinned default cascade.
- Send an empty rules array to remove all custom non-card routing rules.
GET/api/v1/other-declineSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
Responses
200Current non-card decline rules.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | Ordered list of non-card decline rules. The first rule whose conditions all match causes the transaction to be declined. |
data.rules[].conditions | array | Yes | Array 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[].type | string | Yes | Condition 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[].op | string | Yes | Operator: 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[].values | string[] | No | Array 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[].key | string | No | Metadata key to match against. Required for metadata conditions. |
data.rules[].conditions[].currency | string | No | Currency for amount conditions (e.g., "USD"). Required for amount conditions. |
data.rules[].conditions[].min | number | No | Minimum amount in major units for "gt" or "between" operators. |
data.rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. |
data.rules[].errorCode | string | No | Optional 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. Check Gr4vy status if the error persists. |
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>"
{
"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-declineSetup
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
| Field | Type | Required | Description |
|---|
authorization | Bearer <dashboard-session> | Yes | Clerk dashboard session token. API keys cannot call workspace-level routes. |
content-type | application/json | Yes | Required when the request includes a JSON body. |
Request body
| Field | Type | Required | Description |
|---|
rules | array | Yes | Array of non-card decline rules. May be empty to disable all non-card decline rules. Rules are evaluated in order. |
rules[].conditions | array | Yes | Array 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[].type | string | Yes | Condition type: "paymentMethod", "country", "currency", "amount", or "metadata". |
rules[].conditions[].op | string | Yes | Operator. 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[].values | string[] | No | For 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[].key | string | No | Metadata key to match against. Required for metadata conditions. |
rules[].conditions[].currency | string | No | Currency code for amount conditions (e.g., "USD"). Required for amount type. |
rules[].conditions[].min | number | No | Minimum amount in major units for "gt" or "between" operators. Required for those operators. |
rules[].conditions[].max | number | No | Maximum amount in major units for "lt" or "between" operators. Required for those operators. |
rules[].errorCode | string | No | Optional error code returned to the integration when this rule fires. Must match ^flow_[a-z_]+$. No free-text message field — errorCode only. |
Responses
200Updated non-card decline rules returned.
Response fields
| Field | Type | Required | Description |
|---|
data.rules | array | Yes | The 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 | gr4vy_upstream_error | The Gr4vy flows API returned an unexpected error. | Retry after a short delay. The decline rules were not partially applied. |
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.