When to use this
Use CKO-04 when:- Your customers buy on your own website — your funnel, your cart, your payment provider
- You are an incumbent or existing ISP bringing your own subscribers to the kurnl network
- You handle your own billing entirely — no Stripe or kurnl invoices needed
- You want to provision subscribers programmatically from your own back-office system without a marketplace flow
How it works
Three calls from your storefront, then one to provision:- Creates the subscriber record in kurnl (or reuses an existing account by email)
- Creates the subscription
- Either provisions the switch port via SSH (VLAN, bandwidth, optional MAC binding),
or raises an install job for a technician — decided by the building’s line type,
not by you. The response’s
routesays which.
A back-office migration where you already hold port mappings skips the first
three calls and sends a
location_hash directly — see Naming the premise below.Making the call
job_id is null, route is "install", and the
subscription is PENDING_INSTALL until a technician calls
POST /provisioning/confirm-install.
The port is provisioned asynchronously. Poll the job or wait for the provisioning.completed webhook.
Retries are safe (idempotent). A repeat call for the same (subscriber email, plan version, location) triple returns 200 with the existing subscription instead of creating a duplicate — message is "Provisioning already in progress" (a job is still running) or "Subscription already exists (idempotent replay)", and job_id may be an empty string on a replay, so treat it as optional. The same subscriber + plan at a different location provisions a second line normally. A SUSPENDED subscription counts as existing.
Rate limit: 120 requests/minute per API key.
Errors
Naming the premise
Every order has to say where. There are two ways, and which one you can use depends on what you know about the customer.A unit — for a storefront (delivery_mode: "home_drop")
A shopper typing their address into your site has no way to know their switch port,
and neither do you. Ask them for their address and suite instead:
POST /serviceability/checkwith the address → abuilding_id.GET /serviceability/units?building_id=…→ the suites, each withavailable.POST /provisioning/provider-initiatedwithdelivery_mode: "home_drop"and the chosenunit_id.
available
rather than anything else you may have cached about a unit.
A port — for a migration (delivery_mode: "direct", the default)
A location_hash identifies a physical switch port. You get one of two ways:
- From your provisioning records — if you mapped your subscriber addresses to kurnl location hashes during onboarding
- From the kurnl dashboard — look up the port in Dashboard → Network and copy the location hash
Provision or install — the building decides
delivery_mode states what you have. The building’s line type decides what
happens, and a request that does not fit it is refused with 422 rather than
half-completed:
Read
route in the response (provision or install) and branch your confirmation
screen on it — never on the presence of job_id, which is also empty on an
idempotent replay.
No Stripe / no kurnl invoices
CKO-04 does not create any Stripe payment records or Invoice Ninja invoices. Billing is entirely your responsibility. kurnl tracks the subscription for network management purposes (deprovisioning on cancellation, reporting), but does not bill the subscriber on your behalf.If you want kurnl to handle subscriber billing (invoices, Stripe payment links, self-service portal), use CKO-01 (the kurnl marketplace checkout) or CKO-03 instead.
Cancellation
When a subscriber’s service ends, call the subscription cancel endpoint so kurnl can deprovision the port:
This marks the subscription
CANCELLED and sets canceled_at and ended_at (the response echoes both). ended_at is exclusive — service is off on that day. There is no minimum term: any date from today on is accepted. The port itself is not reset at call time: the deprovisioner resets it to the captive-portal VLAN once ended_at is reached. Service stays up until then.
GET /api/v1/subscription/{subscription_id}/cancel/preview?end_date=YYYY-MM-DD (same JWT) is a read-only quote of what a cancellation on that date would record — the effective date, the calendar month it lands in, and, for kurnl-billed subscriptions, whether the month has already been invoiced (a credit note for the unused days plus every open credit swept into the refund) or has not (a final invoice for the days served, minus open credits). CKO-04 subscriptions are not billed by kurnl, so the money lines are always empty for them.
The cancellation endpoint is on the internal API surface (
/api/v1) and requires dashboard JWT authentication, not an API key. If you need programmatic cancellation from your back-office system, use a service account JWT obtained from the dashboard login flow. Alternatively, cancellations can be initiated from Dashboard → Subscriptions.