Overview

There are two distinct surfaces, and it’s important not to confuse them:
  • Partner API (X-API-Key) — how you create subscribers programmatically, as part of checkout or a migration. This is the server-to-server integration surface.
  • Operator dashboard (JWT-authenticated) — where subscribers and subscriptions are managed after creation (edit details, change plan, cancel). These endpoints live under /api/v1/dashboard/* and are not reachable with a partner API key; they back your dashboard UI.
The partner API does not expose subscriber CRUD, or subscription activate or cancel — those still require a dashboard session. Earlier versions of this page documented X-API-Key calls to /provider/subscribers and /subscription/{id}/…; those paths do not exist on the partner surface. What the partner surface does have: the checkout session lifecycle endpoints (session create / read / PATCH / status), the suspend/restore lever below, and — as of 2026-09-17 — plan change (POST / GET .../preview at /partner/subscriptions/{id}/change-plan, see below).

Creating subscribers (partner API)

Programmatic subscriber creation happens through the checkout/provisioning flows, which create the subscriber, the subscription, and (optionally) provision the port in one call:
  • CKO-03 external checkoutPOST /partner/external-checkout/complete (and the anonymous variant) create a subscriber + subscription from your own checkout. Provisioning is idempotent across paths: the same subscriber email + plan version + location returns the existing subscription instead of duplicating it, and a replayed session_id returns the session’s existing subscription.
  • CKO-04 provider-initiated provisioningPOST /partner/provisioning/provider-initiated (and /bulk) create + activate a subscriber’s port without a marketplace redirect. Use this to migrate an existing subscriber base.

Managing subscribers & subscriptions (dashboard)

After creation, management is done in the operator dashboard (dashboard JWT + the subscribers:read / subscribers:write permissions), not via the partner API key:
  • Subscribers — create/list/get/update live under /api/v1/dashboard/subscribers (update is PUT). See the operator guide Add a subscriber & subscription.
  • Subscription lifecycle — activate and cancel are /api/v1/subscription/{id}/… and remain dashboard-only (see Subscriptions reference). Cancelling deprovisions the port and resets it to the captive-portal VLAN.
  • Plan change — unlike activate/cancel, this one is also available on the partner API: POST /partner/subscriptions/{id}/change-plan (plus a GET .../preview to check eligibility first) changes the plan on your own ACTIVE subscriptions immediately, once per calendar day (UTC). See the plan change reference for the full guard table, billing behaviour, and what bandwidth_updated: false means.
  • Suspend / restore — when kurnl bills, suspension is automatic (non-payment with a CRTC grace window, restored on payment by the billing schedulers). When you own billing, the partner lever is POST /partner/external-checkout/subscription-status (X-Webhook-Secret, action: "suspend" | "restore"): suspend resets the port to the captive portal and marks the subscription SUSPENDED (no kurnl billing effects); restore reverses a suspend: from SUSPENDED it re-queues port provisioning and marks ACTIVE; from ACTIVE it is an idempotent 200 (“Already ACTIVE”); any other state (e.g. CANCELLED, PENDING_INSTALL) returns 409. The response includes port_changed and a nullable port_error (set on suspend only, when a switch action was attempted and failed — restore reports missing switch data via its message instead) (set when a switch action was attempted and failed). See the suspend / restore reference.

Subscription statuses

Migrating an existing subscriber base

  1. For each subscriber, call provider-initiated provisioning (CKO-04) with their plan_version_id and location_hash — this creates + activates them.
  2. Store kurnl’s returned subscriber_id / subscription_id in your own system.
  3. Manage them thereafter from the dashboard (or your own dashboard-authenticated integration).