https://middleware.bso-projects.com/partner. All calls send X-API-Key; the ones
marked verified also require X-Verified-Session (see Authentication).
Every response is a typed, documented schema — the same shapes are rendered in the
interactive Swagger. Internal fields
(Stripe IDs, operator notes, MAC, user_id) are never exposed.
Identify
Search customers
GET /agent/customers/search?q={term}&limit={n}
Matches contact name, email, phone, short account id, invoice address, building/unit and
service location. Returns masked matches only — enough to identify a caller, not enough to
leak PII before verification.
ambiguous is true (match_count > 1), ask the caller for their
service address or unit, append it to q, and search again — service_locations on each
candidate is the discriminator. Never auto-select a match; if it stays ambiguous, ask
another distinguishing detail or escalate.
Get a customer
GET /agent/customers/{customerId}
Full profile — contacts, invoice address, service locations, subscriptions. Requires a
verified session (verify the caller first). Returns 404 if the customer is not owned by your
provider (no cross-provider enumeration). Internal fields are never returned.
Verify
See Authentication forPOST /agent/verify/issue and
POST /agent/verify/check. verify/issue accepts channel: "email" (default) or "sms"
(SMS is delivered via Twilio and is inert until configured — returns 503
dependency_unconfigured otherwise).
Answer
Billing summary
GET /agent/customers/{customerId}/billing-summary
Payment history
GET /agent/customers/{customerId}/payments
The customer’s payments. (kurnl has no separate payments table — a paid invoice with its Stripe
payment-intent is the payment record — so this is derived from paid invoices.)
Network health
GET /agent/customers/{customerId}/network-health
Read-only per-subscription provisioning/activation status plus modem (CPE) status from the
ACS when available. No switch control, no live-switch queries.
Communication history
GET /agent/customers/{customerId}/tickets
The customer’s support tickets, read by their email on file.
Act
Preview a plan change
POST /agent/customers/{customerId}/plan-change/preview
Returns the exact billing impact — recurring change plus the one-time prorated
charge/credit — without applying anything. Use it to explain the cost before confirming.
Apply a plan change
POST /agent/customers/{customerId}/plan-change
Applies the change. Requires confirm: true — call it only after the customer has seen
the preview and agreed. Proration is handled automatically.
Plan-change and AutoPay are Phase 1.5: the endpoints exist and are reachable on the
sandbox, but before general availability they gain a signed
quote_token (preview→apply),
an Idempotency-Key, and the change-confirmation/rollback flow below. Validate the read +
verify + escalate loop first.confirm: true the call returns 400 confirmation_required.
Update contact fields
PATCH /agent/customers/{customerId}/contact
Update the customer’s approved contract or invoice contact fields. Benign write — no billing or
network impact. Triggers the change-confirmation email.
contact_type:contract(default) |invoice. Only the fields you send are changed.
Password reset / resend activation
POST /agent/customers/{customerId}/password-reset
Emails the customer a self-service portal link — a password-reset link (15-min token) or a
re-sent activation/invite link (72-h token). The customer completes it themselves.
action:password_reset(default) |resend_activation.
Resend an invoice
POST /agent/customers/{customerId}/invoices/{invoiceId}/resend
Emails a copy of the invoice to the customer.
Add a support note
POST /agent/customers/{customerId}/notes
Append an internal, operator-visible note to the customer’s record, attributed to the AI agent.
Never shown to the customer.
Escalation
Create a ticket
POST /agent/tickets
Opens an enriched support ticket routed to the provider’s support group. Not
verification-gated, so it works even when the caller can’t be verified — the primary escalation
path on repeated auth failure or any downstream error. Provide customer_id (must be your
provider’s) or a contact_email.
priority:low|normal|high.ai_summaryandai_diagnosisgo into the customer-facing article;transcriptis stored as an internal note.
Change confirmation & rollback
Any account- or personal-data change the agent makes is applied immediately and triggers an out-of-band confirmation email to the subscriber’s address on file: “We’re confirming change request #XYZ — click here to roll it back if this wasn’t you.” The link is valid for 3 days; clicking it reverses the change and opens a provider ticket. This guarantees the real account holder is always notified through a channel the caller doesn’t control — a guard against socially-engineered verification. Applies to contact/personal-data edits (Phase 1) and plan-change / AutoPay (Phase 1.5). Password resets already deliver to the inbox by nature.Rate limits
Exceeding a limit returns
429 (standard rate-limit response; not the error envelope below).
Back off and retry.
Errors
Every/agent error returns a normalized envelope with a stable, machine-readable code
and a request_id you can quote to support — so your agent branches on the code, not the message:
Recommended default on downstream (502/503) and server (500) errors: graceful handover —
create an escalation ticket and offer a human callback rather than retrying. Back off on
429, re-verify on session errors. These behaviours are configurable to your agent design.