API reference
import { Tabs, TabItem } from “@astrojs/starlight/components”;
All endpoints live on your customer Function App at https://pocai-fa-{stack-hash}.azurewebsites.net/api/. Authentication varies by endpoint — see each entry.
Anonymous endpoints
GET /api/health
Liveness probe + minimal deployment metadata.
{ "ok": true, "deploymentId": "pocai-...", "marketplaceSubscriptionId": "...", "version": "phase24-synctrigger", "startedAt": "2026-...", "bootstrap": { "attempted": true, "result": "succeeded" }, "seat": { "activeSessionCount": 0, "lastReportedQuantity": 0 }, "tokens": { ... }}GET /api/plan
Current plan + seat quota + grace state. Used by the dashboard JS.
{ "planId": "growth", "planDisplayName": "Growth", "seatQuota": 7, "seatsUsed": 4, "exceeded": false, "daysOverQuota": 0, "gracePeriodDays": 7, "blocked": false, "upgradeUrl": "https://portal.azure.com/..."}POST /api/chat
Visitor sends a chat message. Authentication: visitor JWT in Authorization: Bearer (issued by the widget’s /api/widget.js bootstrap).
Body:
{ "message": "Hi, I need help with...", "sessionId": "<uuid optional>" }When the session is bot-handled: returns 200 with the bot’s reply. When the session has been claimed by an agent: returns 202 queued-for-agent and broadcasts the visitor message to the agent via SignalR.
POST /api/negotiate
SignalR negotiate for visitors. Returns connection info bound to userId = sessionId. Anonymous; the widget posts here.
Admin-key gated endpoints
All require ?code=<admin-key> query param, Authorization: Bearer <key> header, OR a valid session cookie.
| Endpoint | Returns |
|---|---|
GET /api/dashboard | HTML admin dashboard |
GET /api/cost?window=24h|7d&bucketHours=N | Time-bucketed cost data |
GET /api/sessions?sortBy=cost&limit=N | Top sessions list |
GET /api/sessions/search?q=... | Full-text search across messages |
GET /api/sessions/{id}/transcript | Full transcript for one session |
POST /api/ops/rotate-key | Generate + return new admin key |
GET /api/teams-app.zip | Per-deployment Teams app .zip download |
GET /api/teams-setup | Teams setup wizard HTML |
Agent endpoints (Teams SSO gated)
All require Authorization: Bearer <Teams-SSO-token>. The customer-runtime validates the JWT against your AAD app (AAD_APP_CLIENT_ID + AAD_APP_TENANT_ID).
GET /api/agent/me
Returns the authenticated agent’s normalized claims:
{ "oid": "...", "upn": "agent@tenant.onmicrosoft.com", "email": "...", "tenantId": "..." }POST /api/agent/negotiate
SignalR negotiate for agents. Returns connection info bound to userId = agent.oid.
GET /api/agent/sessions[?status=&claimedBy=&limit=]
Lists chat sessions visible to agents. Filters:
status—open,human_requested,claimed,closedclaimedBy— agent oid, ormeto filter to own claimed sessionslimit— 1-200, default 50
POST /api/agent/sessions/{id}/claim
Claim a session. Seat-gated:
- Under quota → 200 with the updated session
- Grace period → 200 +
quotaStatusblock in response body - Post-grace + new agent → 403
{ error: "seat-quota-exceeded", upgradeUrl, ... } - Already claimed by another agent → 409
- Already claimed by caller → 200
{ alreadyClaimed: true }(idempotent)
POST /api/agent/sessions/{id}/message
Send a message from the owning agent. Body: { "content": "string (1-4000 chars)" }. Broadcasts to the visitor via SignalR.
- Not the owning agent → 403
- Session closed → 409
POST /api/agent/sessions/{id}/close
Close a session. Owning agent only.
ISV control plane endpoints
These live on the ISV side at https://pocai-isv-cp.azurewebsites.net/api/ and are mostly invoked by Microsoft Marketplace, Microsoft Graph, or our own orchestrator. The public ones:
GET /api/plans— list all plans (Start / Growth / Professional)GET /api/plans/{planId}— single plan details
Both are anonymous with 5-minute cache.