Skip to content

operations

Every external mutation that does real work returns an operation. Launch, pause, resume, cancel: none of them are synchronous, and none of them pretend to be.

An operation is never “the response you were waiting for”. It is the handle you poll.

const accepted = await boomin.distributions.launch("dist_...");
const operation = await boomin.operations.wait(accepted.operation, {
timeout: 120000,
pollInterval: 2000,
});
console.log(operation.status);
MethodRouteScope
list(params, options)GET /operationsoperations:read
retrieve(id, options)GET /operations/{id}operations:read
wait(id, options)(polls retrieve)operations:read

operations:read is granted to every valid token implicitly, so any key can poll the operations it caused. You never have to widen a key just to find out whether its own launch worked.

{
"id": "op_...",
"object": "operation",
"subject": { "type": "distribution", "id": "" },
"kind": "distribution.launch",
"status": "succeeded",
"waitingReason": null,
"attempts": 1,
"maxAttempts": 5,
"error": null,
"result": { },
"progress": { },
"targetOperationId": null,
"livemode": true,
"createdAt": "2026-08-01T00:00:00.000Z",
"completedAt": "2026-08-01T00:00:12.000Z"
}

Raw HTTP responses use the snake_case spellings (waiting_reason, created_at); the SDK camelCases every response key.

targetOperationId is set on a cancel: it points at the operation being superseded.

StatusTerminalMeaning
pendingEnqueued, not claimed
runningA worker holds the lease
waitingBlocked on something nameable — see waitingReason
succeededEverything the operation set out to do happened
partialSome children succeeded, some did not
failedNothing usable came out of it
canceledSuperseded or explicitly canceled

partial is a real outcome, not a transient state. A launch that brought up nine of twelve deployments is partial, and the distribution is partially_active. Treat it as “look at the deployments”, not as a failure.

waiting always carries a reason — a null reason is structurally impossible.

ReasonMeaningClears when
funding_requiredA funded budget outran the brand walletThe wallet is topped up
provider_reviewAn external provider is reviewingThe provider decides
awaiting_target_settleA cancel is waiting for the running operation it targetsThe target settles
awaiting_children_settleWaiting on fan-out childrenThe last child settles
awaiting_cleanupWaiting on adapter teardownCleanup settles

A waiting operation is alive. It is woken by domain events when its blocker settles, with a cron poller as the universal backstop — so it will not sit stranded even if a wake is missed. Relaunching while a launch waits on funding reuses the waiting operation rather than enqueueing a second one.

const operation = await boomin.operations.wait(operationId, {
timeout: 120000, // ms, default 60000
pollInterval: 1000, // ms, default 1000
});

Two things to know:

  1. It resolves on any terminal status. succeeded, partial, failed, and canceled all resolve — inspect operation.status yourself. wait() does not throw on a failed operation.
  2. It throws only on timeout, as a BoominError with code operation_wait_timeout. The operation is still running; poll again with a longer budget.
const operation = await boomin.operations.wait(id, { timeout: 120000 });
switch (operation.status) {
case "succeeded": break;
case "partial": await inspectDeployments(); break;
case "failed": console.error(operation.error); break;
case "canceled": break;
}

wait also accepts the standard per-call RequestOptions (brand, timeout per HTTP request via the client, maxRetries) alongside its own two.

ParamValues
subjectTypee.g. distribution, deployment
subjectIdA prefixed id (dist_...) or a bare uuid
statusAny status above; anything else is invalid_status (400)
limit1–100, default 20
startingAfterAn op_... cursor
// what is currently in flight for this distribution?
const { data } = await boomin.operations.list({
subjectId: "dist_...",
status: "running",
});

A subject can hold one live mutation at a time. A second launch, resume, or apply while one is live raises operation_conflict (409) — poll the live one instead of enqueueing a rival.

Cancel runs on a separate control plane, so a cancel can coexist with the launch it is cancelling. That is the only cross-plane exception, and it is why cancel() works on a distribution that is mid-launch.