Skip to content

operatingTypes

An operating type answers in what capacity is this entity participating in this enrollment: advisor, creator, agency, reseller — your words, defined per brand. Boomin never interprets them; it uses them to discriminate policy.

await boomin.operatingTypes.create({ key: "advisor", name: "Advisor" });
await boomin.enrollments.update("enr_...", { operatingType: "advisor" });
MethodRouteScope
create(params, options)POST /operating_typesoperating_types:write
list(params, options)GET /operating_typesoperating_types:read
retrieve(id, options)GET /operating_types/{id}operating_types:read
update(id, params, options)POST /operating_types/{id}operating_types:write
archive(id, options)DELETE /operating_types/{id}operating_types:write

retrieve and update accept the otype_... id or the key itself (boomin.operatingTypes.retrieve("advisor")) — tenant vocabulary is the ergonomic address.

{
"id": "otype_...",
"object": "operating_type",
"key": "advisor",
"name": "Advisor",
"status": "active",
"metadata": {},
"livemode": true,
"createdAt": "2026-08-01T00:00:00.000Z",
"updatedAt": "2026-08-01T00:00:00.000Z"
}

Types discriminate policy — they never run anything

Section titled “Types discriminate policy — they never run anything”

A requirement, reward rule, or payout rule may carry an operatingType. Typed policy applies only to enrollments operating in that capacity; untyped policy (operatingType null) applies to everyone. That is the entire mechanism — one filter, applied consistently by the standing evaluator and both money rails:

// Only advisors must hold the verification claim:
await boomin.programs.requirements.create("prog_...", {
scope: "program_maintenance",
metricKey: "assert:advisor_verified",
operator: "exists",
operatingType: "advisor",
});
// Only advisors earn this split:
await boomin.payouts.rules.create({
name: "Advisor split",
type: "revenue_split",
rateBps: 1000,
operatingType: "advisor",
scope: { type: "program", program: "prog_..." },
});

A typed payout rule never pays an untyped enrollment; a typed requirement never gates one. Clearing an enrollment’s capacity makes typed policy stop applying to it — and re-applying the capacity brings it back.

Three ways, all converging on the same column:

SurfaceCall
API / SDKboomin.enrollments.update("enr_...", { operatingType: "advisor" })null clears
CLInpx @boomin/cli enrollment set-type enr_... --type advisor (or --clear)
Signed HandoffpostHandoff({ ..., operatingType: "advisor" }) — the key rides the signed payload; your app is the authority on capacity, so each handoff sets/refreshes it

Setting or clearing a capacity re-evaluates standing immediately. The handoff path is deliberately lenient: an unknown or archived key is skipped, never a reason to fail a signup.

(brand, key) is fully unique — including archived rows. Archiving stops the type from being newly assigned (assigning one answers operating_type_archived, 409); requirements and rules that already reference it keep their history and simply stop matching new assignments. Creating with an archived key answers operating_type_key_archived (409) pointing at reactivation:

await boomin.operatingTypes.update("otype_...", { status: "active" });

Reactivation flips the same row back — the key’s meaning is permanent, and a second meaning is never minted. Display name changes freely; key never does.

boomin standing test --enrollment enr_... --operating-type advisor previews one member’s standing as if they operated in a capacity — including --operating-type null for “what if untyped” — without touching state. See programs.standingPreview.