Endpoint
Authentication
X-Webhook-Secret header.
Request body — session-based (recommended)
This is the flow the kurnl Marketplace uses. Withsession_id set, the session
supplies the plan, building, location/unit and MAC address — only
external_subscription_id is additionally required (and contact_email when the order
needs a visit, see below). Any of the explicit fields
below included alongside a session_id are ignored in favor of the session.
/external-checkout/complete: resolved as of
the session’s creation day, and if it was archived meanwhile it lapses without failing the
order. That silent lapse covers only the session’s own code. A discount_code you send in
the body is checked as of the hand-over against the session’s building: a kurnl operator
code from the session’s operator_offers or one of your own discount codes is honoured;
anything else is a 400 (Invalid or expired discount code) and nothing is created. The
session’s own code sent back counts as no code. Check it before you charge, and on a 400
retry without the code (the plan’s campaign price if a campaign is live, otherwise the list
price). A bulk plan takes no code (422 bulk_discount). If the code cannot be checked
right now, the call answers 503 (Could not check the discount code; try again.): retry.
The building decides the path, as on
/external-checkout/complete,
not the delivery_mode of the session or of your payload:- a first-line building is provisioned at once (ACTIVE) — a shared first-line suite is held as an install job until the operator confirms the connection;
- a second- or third-line suite whose router is already online (a suite of one) is provisioned at once too;
- every other suite — router not online, a shared suite, or any suite in an
unclassified building — gets
PENDING_INSTALLand an operator install job.
delivery_mode in the response reports the path taken: direct = provisioned,
home_drop = install job. A direct order (a port, no suite) on a building that is
not first line is refused with 422: outside first line kurnl needs the suite.Request body — explicit fields (no session)
external_subscription_id is your own per-subscription identifier and acts as the idempotency key.
contact_email (either path) is an e-mail for the household behind the line. It is stored on the
subscription only — no customer record is created. It is required when the order needs a technician visit
or a shipped router: a second- or third-line building, unless the suite’s router is already online, and an
unclassified building, even when the suite’s router is online. Without it such an order is refused with 422 contact_email_required and nothing is created. On a first-line building, and for a second- or third-line suite
whose router is already online, it is optional. On a third-line building it is the address the technician booking link is e-mailed to; the
customer picks and manages the visit window from that link. Later it also serves the provider’s own outage
notices. The provider can add or change it in the portal.
Response — 200 OK
No
subscriber_id is returned — no subscriber record is created.
An order for a shared suite takes the install path. It is re-anchored to the suite’s first free connection
and stays PENDING_INSTALL as usual; unit_confirmation_pending: true says the operator
still has to confirm which connection is the customer’s. If every connection of the suite is
taken the call is refused with 409 no_free_connection.
Replays (same external_subscription_id or already-completed session_id) report the
subscription’s real current status — e.g. PENDING_INSTALL for a home-drop order
still awaiting install.