Upgrading api-client from 2.x to 4.x
Two major versions shipped a day apart in August 2026: 3.0.0 (one order status instead of
two) and 4.0.0 (payments that are still in flight). This page lists every breaking change
between 2.18.0 and 4.3.0,
taken from a diff of the two published packages.
The API moved, whichever client you run
Throttle serves one API version. Staying on 2.x does not keep the old behaviour — it keeps
types that describe it. Three things are already true for a 2.x client today:
postApiV1OrdersComplete returns 404, an order is never completed (it is fulfilled),
and order responses carry no fulfillmentStatus. Everything
else in 2.x keeps working.
Breaking changes that stop compiling
-
OrdersService.postApiV1OrdersCompleteis gone. The endpoint (POST /orders/{id}/complete) was removed with the status it set. UsepostApiV1OrdersStatus, which moves an order to any lifecycle status. - Order
status:completedbecamefulfilled. The full set is nowdraft,pending,processing,partially_fulfilled,fulfilled,cancelled,closed. Stored orders were migrated; you will not receivecompletedfrom any client version. -
fulfillmentStatuswas removed from order responses and filters. Delivery progress is instatusitself, with per-item counts infulfillmentSummary. See Order states. - Status unions grew. Order
paymentStatusgainedprocessing,disputedandexpired; paymentstatusgainedprocessingandexpired. An exhaustiveswitchover either stops type-checking until it handles them. - The delivery-log
eventTypefilter no longer acceptsorder.completed. See the event rename below.
Completing an order
// 2.x
await OrdersService.postApiV1OrdersComplete(orderId);
// 4.x
await OrdersService.postApiV1OrdersStatus(orderId, { status: 'fulfilled' }); The new payment statuses
switch (order.paymentStatus) {
case 'captured':
case 'partially_paid':
// ...
break;
case 'processing': // new — neither approved nor declined yet. Do NOT treat as failed.
break;
case 'disputed': // new — captured, then charged back
break;
case 'expired': // new — the authorization lapsed before capture
break;
// ...
} processing is not failed
Before 4.0.0 a payment the processor had not yet decided — a 3DS challenge in progress, a
redirect the buyer had not returned from, a bank debit still settling — was reported as
failed. If your code retries or re-charges on failed, make sure it does nothing on processing.
Breaking changes that still compile
The generated client takes positional arguments. Two list methods gained filters in the
middle of their argument lists, so an existing positional call shifts by one or
two places. TypeScript catches the shift where the types differ and misses it where both
sides are string.
-
OrdersService.getApiV1Orders—deliverywas inserted beforesource, andsubscriptionIdbeforecreatedAfter. A call that filtered bycustomerIdnow passes that id as the free-text searchq, and itscreatedAfterascustomerId. Neither is a type error. -
WebhooksOutboundService.getApiV1WebhookDeliveries—statusandeventTypewere inserted beforelimitandoffset. TypeScript rejects a number wherestatusis expected; plain JavaScript does not.
Listing orders
// 2.x argument order
// (environmentId, cursor, limit, status, paymentStatus, type,
// source, q, customerId, createdAfter, createdBefore)
//
// 4.x argument order — delivery and subscriptionId are new, and sit in the middle
// (environmentId, cursor, limit, status, paymentStatus, type,
// delivery, source, q, customerId, subscriptionId, createdAfter, createdBefore)
// This 2.x call still compiles on 4.x and asks a different question:
await OrdersService.getApiV1Orders(
undefined, undefined, 50, undefined, undefined, undefined,
undefined, // 2.x: source 4.x: delivery
undefined, // 2.x: q 4.x: source
customerId, // 2.x: customerId 4.x: q <- free-text search
'2026-01-01', // 2.x: createdAfter 4.x: customerId
);
// 4.x, same intent
await OrdersService.getApiV1Orders(
undefined, undefined, 50, undefined, undefined, undefined,
undefined, undefined, undefined,
customerId,
undefined,
'2026-01-01',
); Listing webhook deliveries
// 2.x: (environmentId, endpointId, orderId, limit, offset)
// 4.x: (environmentId, endpointId, orderId, status, eventType, limit, offset)
// 2.x
await WebhooksOutboundService.getApiV1WebhookDeliveries(undefined, endpointId, undefined, 25, 0);
// 4.x
await WebhooksOutboundService.getApiV1WebhookDeliveries(
undefined, endpointId, undefined, undefined, undefined, 25, 0,
); Every other method kept its argument order. Re-check these two by hand; a green build does not prove them.
order.completed became order.fulfilled
-
order.completedwas renamed toorder.fulfilledon 2026-08-22 and is no longer delivered. Stored webhook and extension subscriptions were rewritten to the new name. -
order.completedis still accepted inenabledEventswhen you create or update an endpoint, in 4.x as in 2.x, and is dropped from the saved list. That is deliberate: it keeps a read-modify-write of an old subscription list from failing. It is not a sign the event still fires. -
order.fulfilledis not in the 2.xenabledEventstype, but the API accepts it from any client. On 2.x, cast the value; on 4.x it is in the union. -
order.fulfilledandfulfillment.completedare different events — the first is about the order, the second about one fulfillment. Subscribe to whichever your handler is really about.
What you gain
- Orders:
postApiV1OrdersStatus,postApiV1OrdersHold/postApiV1OrdersHoldRelease,postApiV1OrdersComp/postApiV1OrdersCompReverse,getApiV1OrdersTimeline,getApiV1OrdersStatusHistory; adeliveryfilter (in_transit,delivered,returned) and asubscriptionIdfilter; the same filters on the CSV export. - Payments:
postApiV1OrdersPaymentsRecord(record a payment taken outside Throttle, includingcheque) andpostApiV1PaymentsMarkFailed; payment responses declareerrorCodeanderrorMessage. - Fulfillments:
postApiV1FulfillmentsDelivered. Subscriptions:postApiV1SubscriptionsRetryChargeandpostApiV1SubscriptionsWaivePeriod. - Webhooks:
order.fulfilled,order.held,order.hold_released,order.comped,order.comp_reversed,payment.processing,payment.expired,payment.recorded; the delivery log filters bystatusandeventType. - Customers carry
company; embed config carriescheckoutLinkBaseUrl.
Upgrade checklist
-
Search for
postApiV1OrdersComplete,'completed'andfulfillmentStatus. These are already wrong on 2.x, so fix them first — before or without the upgrade. - Install 4.x and fix what the compiler reports: the removed method, the removed field, and any exhaustive switch over a payment status.
-
Find every call to
getApiV1OrdersandgetApiV1WebhookDeliveriesand re-count the arguments against the lists above. The compiler will not find all of these for you. -
Replace
order.completedwithorder.fulfilledin the event list you send, and in the handler that switches on the deliveredtype. -
Make sure nothing treats a
processingpayment as a failure.