---
title: "Provision (or resume provisioning) the hosted phone system for a business: carrier account, owner seat, Kai as extension 700, team ring group with the owner mobile, and the ring-team-then-Kai dial plan. Idempotent — a re-run resumes from stored ids. Pass business_address to save the street address first when the last attempt returned 409 missing_address. Owner role (session) or numbers:write. The admin key may also pass action=register_platform_webhook to register the per-environment events endpoint once (returns the signing secret exactly once)."
method: POST
path: "/v1/phone-system"
---

# Provision (or resume provisioning) the hosted phone system for a business: carrier account, owner seat, Kai as extension 700, team ring group with the owner mobile, and the ring-team-then-Kai dial plan. Idempotent — a re-run resumes from stored ids. Pass business_address to save the street address first when the last attempt returned 409 missing_address. Owner role (session) or numbers:write. The admin key may also pass action=register_platform_webhook to register the per-environment events endpoint once (returns the signing secret exactly once).

`POST /v1/phone-system`

## Request

- Base URL: `https://www.kaicalls.com/api`
- URL: `https://www.kaicalls.com/api/v1/phone-system`
- Auth: HTTP bearer

## Request body

- object
  - `business_id` string
  - `action` 'provision' | 'register_platform_webhook' | 'add_ring_group_member' | 'get_flow' | 'save_flow' | 'propose_flow': get_flow reads the reconciled phone flow (who rings, for how long, business-hours mode) from the phone system; save_flow validates and applies a flow idempotently (loop guard on every member, schedule derived from business hours); propose_flow turns free text into a validated flow plus a one-sentence readback without applying it.
  - `flow` object: save_flow: the phone flow — { version: 1, hours: { mode: always | business_hours, afterHours: kai }, ring: { members: [{ kind: cell, phone, label, requirePressOne } | { kind: desk_phone | user, userId, label }], timeoutSeconds }, overflow: kai }.
  - `text` string: propose_flow: how the phones should ring, in the owner's words (e.g. "me and Maria ring for 20 seconds, after hours straight to Kai").
  - `owner_mobile` string: E.164 override for the ring-group member (defaults to the owner mobile on file).
  - `business_address` object: provision: the business street address to save before provisioning — { street, city, state, zip } (US). Required only when no complete address is on file (409 missing_address).
    - `street` string
    - `city` string
    - `state` string
    - `zip` string
  - `phone_number` string: add_ring_group_member: the teammate cell (E.164) to add to the team ring group. Owners/admins are also registered on the admin roster so calling the business line from that cell reaches the secretary. The forwarded-from office line is refused (loop guard).
  - `name` string: add_ring_group_member: display name.
  - `role` 'owner' | 'admin' | 'member': add_ring_group_member: member only rings; owner/admin can call Kai.

## Response `200`

Provisioning result (ids, created/reused, warnings)

## Other responses

- `409`: Provisioning blocked (missing address / owner mobile)

---

[API](https://skmtc.dev/kaicalls/apis/kaicalls-public-api.md) · [All operations](https://skmtc.dev/kaicalls/apis/kaicalls-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/kaicalls/apis/kaicalls-public-api/revisions/e607fc6cf36e?raw)
