POST /v1/admin/billing/org/{org_id}/suspend

Automated billing-driven suspension (master-key auth; payment-worker only).

What this is

Sets organizations.active = 0 for the target org. Called by payment-worker on Stripe webhook events: subscription unpaid after dunning exhaustion, paused, customer.subscription.deleted, full charge.refunded within the 14-day grace window, or charge.dispute.created. Idempotent — set-twice is a no-op.

Distinct from POST /v1/admin/org/{org_id}/suspend which is the manual admin-dashboard path (different audit reason code, different undo policy).

Authentication

X-API-Key: $MASTER_ADMIN_KEY_BILLING_SUSPEND — scope-specific secret. payment-worker holds; admin-worker does not. Defense-in-depth invariant per D15.

Idempotency

Idempotency-Key header required by convention (use Stripe event.id). Composite PK (endpoint, idempotency_key) prevents cross-endpoint replay.

Reactivation path

Reactivation does NOT use /v1/admin/billing/org/{org_id}/reactivate. The reactivation flow mints a NEW key via POST /v1/admin/billing/org/{org_id}/rotate — the old key was permanently revoked at suspension time and is unrecoverable.

Rate limiting

Request

curl -X POST https://api.cohesionauth.com/v1/admin/billing/org/org_acme_2026_example/suspend \
  -H "X-API-Key: $MASTER_ADMIN_KEY_BILLING_SUSPEND" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: example-billing-suspend-key" \
  -d '{}'

Response

{
  "suspended": true,
  "org_id": "org_acme_2026_example",
  "suspended_at": "2026-05-02T20:00:00.000Z",
  "note": "Organization is now inactive. Reactivate via /v1/admin/billing/org/:id/rotate (mints a new key).",
  "request_id": "req_01H...",
  "timestamp": "2026-05-02T20:00:00.000Z"
}

Errors

StatusMeaning
401Master-key missing or wrong scope
404Org not found
422Malformed org_id path parameter