Base URL: 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.
Disambiguation. When 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 for POST /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.
Without 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_summary and ai_diagnosis go into the customer-facing article; transcript is 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.