When to use this
Use the anonymous variant when:- You manage the end-user relationship entirely in your own system
- You do not want kurnl to store subscriber PII
- You use your own invoicing and billing — kurnl should not issue invoices on your behalf
How it works
When a subscriber selects a plan on the kurnl Marketplace, kurnl creates a checkout session and redirects them to your checkout URL with asession_id query parameter. Your checkout page reads this session to get the plan details, collects payment in your own system, then notifies kurnl to provision the port.
Step-by-step
1. Configure your checkout URL
Identical to direct delivery — see CKO-03 Direct: Step 1.2. Read the session from the redirect URL
When the subscriber lands on your checkout page, the URL will contain?session_id=<uuid>. Call the sessions endpoint to retrieve the plan details:
plan_version_id to call GET /partner/marketplace/plans/{plan_version_id} if you want to display the plan name and price to the subscriber before they pay.
This read marks the session as reached, after which it no longer expires — so take it as your page renders. A session that is never read expires 2 hours after creation; an expired (or cancelled) session returns
410 Gone, and you redirect the subscriber back to the Marketplace to start a fresh checkout.3. Collect payment in your own system
Display the plan details and handle the full checkout and payment in your own system. kurnl receives no customer data.4. Call kurnl after successful payment
Once payment succeeds, notify kurnl to provision the port. You have two options:Option A — pass session_id (recommended)
The simplest path. kurnl reads the plan, location, and provider directly from the session — you only need to supply your own internal subscription identifier. Any plan_version_id, location_hash, location_identifier, unit_id, mac_address, or delivery_mode in your payload is ignored — the session values win.
This endpoint routes on the session’s
delivery_mode (direct → provision
immediately, home_drop → PENDING_INSTALL). This differs from
/external-checkout/complete, which
routes on the building’s line type.Option B — pass fields explicitly (legacy / non-Marketplace flows)
Use this when you are not going through a kurnl Marketplace session — for example, a direct link from your own website where you already know the plan and location.subscriber_id is returned — no subscriber record is created. Store the subscription_id to correlate with webhook events.
5. Handle webhook events
At
provisioning.completed, the subscriber’s internet is live.
See Webhooks for signature verification and retry behaviour.
6. Read a subscription back
GET /partner/external-checkout/subscriptions/{external_subscription_id}
returns a subscription’s current state addressed by your own identifier — status,
whether it is anonymous, and, for an order that needs a technician, where the visit stands
(workflow_state, appointment_at, on_hold, whether a booking link has gone out).
This is how you show a home-drop customer a truthful status on your own thank-you page: such
an order stays PENDING_INSTALL until the technician has been, and nothing about it changes
for days.
7. Suspend and restore from your own billing
When your billing system puts a subscription on hold, callPOST /partner/external-checkout/subscription-status
with action: "suspend"; call it with "restore" when the customer pays again.
Address the subscription by your own external_subscription_id plus
service_provider_document_id — the same key you sent at completion. You never have to
store a kurnl identifier.
A hold before the install is accepted, and holds the technician visit. A home-drop
order is
PENDING_INSTALL until the technician has been, so an on-hold in that window is
the ordinary case — not an error. kurnl answers 200, cancels any booked visit, releases
the slot and stops the booking link, while the subscription itself stays
PENDING_INSTALL (it has not been installed, so it cannot be “suspended”).restore lifts the hold and sends a fresh booking link. Read
subscription_status in the response rather than assuming SUSPENDED: before the
install it stays PENDING_INSTALL in both directions.Once the line is ACTIVE, the same calls suspend and restore it normally.restore is all-or-nothing: if kurnl cannot re-open the port it returns 409 and leaves
the subscription SUSPENDED, rather than reporting it active while the customer is still
offline. Check the status code, not port_changed.
Field reference
GET /partner/external-checkout/sessions/{session_id}
POST /partner/external-checkout/anonymous-complete
Error handling
On 5xx errors or network timeout: Safe to retry — the request is idempotent. The same
external_subscription_id (or session_id) returns the existing subscription_id rather than creating a duplicate. Replays carry idempotent_replay: true and report the subscription’s real current status (e.g. PENDING_INSTALL for a home-drop order still awaiting install), with job_id: null.