See Subscriber Management for the full guide.

Endpoint

Auth: X-API-Key
Rate limit: 120 requests / minute

When to use

PAY-03 is for ISP-initiated provisioning — you have the subscriber’s details (from your own storefront, a sales CRM, a signed contract, or a migration from another system) and want to create their account without redirecting them through a kurnl checkout flow. You can name the premise two ways:
delivery_mode states what you have; it does not choose the outcome. The building’s line type decides whether kurnl provisions a port immediately or raises an install job for a technician, and a request that does not fit the building is refused with 422 rather than half-completed. Read route in the response to find out which happened.

Request body

With delivery_mode: "direct" (the default) provide at least one of location_hash or location_identifier (both is legal; location_hash wins). With delivery_mode: "home_drop" provide unit_id instead; location fields are ignored. There are no top-level subscriber.firstname / lastname / phonenumber fields — names and phone numbers live in invoice_contact_detail / contract_contact_detail. subscriber.password is optional; when set it controls the subscriber’s self-service login.

Response — 200 OK

Your confirmation screen should differ between the two: provision means the customer is coming online now, install means someone will contact them to book a visit. Webhooks: subscription.activated fires immediately at subscription creation — before the port is live. provisioning.completed (or provisioning.failed) fires after the background job finishes.

Idempotency

Idempotency is scoped to the exact (subscriber, plan version, location) triple — the same email + plan at a different location provisions normally (a genuine second line). SUSPENDED subscriptions count as live for this check. A replayed request returns 200 with the existing subscription:
message is "Provisioning already in progress" when a provisioning job is still pending/running, or "Subscription already exists (idempotent replay)" otherwise. job_id may be the empty string when no job record exists. Safe to retry on network errors.

Error codes