Changelog

RingDeveloper API Changelog


All notable changes to the public API surface and MCP tools.


Format: date, version, breaking/non-breaking, summary.


---


[0.3.10] - 2026-06-14


### Non-breaking


  • **Passive prompt-coach hook for Claude Code + `install` subcommand (MCP package; no API change).** Adds a second coaching surface alongside the `coach_prompt` tool: a Claude Code `UserPromptSubmit` hook that posts a one-line, non-blocking nudge when a just-submitted prompt looks clearly underspecified (red band). It is the zero-network sibling of `coach_prompt` -- it redacts locally and runs the SAME local heuristic, never calls the backend, never blocks or alters the prompt, and stays silent on green/amber drafts so it cannot nag. New CLI subcommand `npx @ringdev/mcp install claude-code` copies the bundled hook to `~/.ringdev/coach-hook.mjs` and idempotently registers it in `~/.claude/settings.json` (existing hooks preserved). MCP-package only; no `/v1` surface change. Ships in `@ringdev/mcp` 0.7.0.

  • ---


    [0.3.9] - 2026-06-14


    ### Non-breaking


  • **In-IDE prompt coaching documented and activated (M5 backend + M6 Phase 1 tool).** Backfills and turns on the prompt-coaching surface that shipped dark behind `RINGDEV_COACHING_ENABLED` (default off) across PRs #55 (M5 backend) and #57 (M6 Phase 1). Three POST endpoints under `/v1/coach` (scoped to the authenticated caller, standard `{ success, data, error }` envelope, `Idempotency-Key` on the writes): `POST /v1/coach/score` (returns a quality band for a redacted draft), `POST /v1/coach/rewrite` (a sharper rewrite plus the per-change explanation and the caller's remaining daily allowance; accepts the MCP API key so the stdio client can call it), and `POST /v1/coach/feedback` (records thumbs up/down on a rewrite). A new stdio MCP tool `coach_prompt` (`@ringdev/mcp`) redacts the draft locally, runs a zero-network local heuristic, short-circuits a clearly-good ("green") prompt with no network call, and only sends a weak draft (already redacted) to `/v1/coach/rewrite`; it fails open (never blocks the developer's prompt) and reports "send as-is" on any error or when the backend flag is off. With the flag off the endpoints report `enabled: false` and the tool sends the prompt as-is, so the surface is purely additive. Flag enabled in production on 2026-06-14.

  • ---


    [0.3.8] - 2026-06-06


    ### Fixed


  • **Login 429 incident — `/v1/auth/refresh` rate limit + web refresh burst.** Two compounding bugs broke login: (1) the web client's axios 401-interceptor fired a *separate* `/v1/auth/refresh` for every concurrent 401, so a dashboard mount (many SWR calls before the access token exists) produced a burst of simultaneous refreshes; (2) `/auth/refresh` and `/auth/login` used `@Throttle({ default: … })`, but the configured throttlers are named `auth`/`api` (there is no `default`), so the decorator was a no-op and the routes silently fell back to the global `auth` limit of **5/min per IP**. Burst > 5 → 429 → bootstrap refresh failed → redirect to `/sign-in`. Fixed by (a) collapsing all web refreshes into a single in-flight request (one `/refresh` per mount, not N), and (b) keying the decorators correctly — `/auth/refresh` is now **30/min**, `/auth/login` **10/min** per IP. The refresh token itself was never revoked (no rotation/reuse-detection), so no sessions were lost.

  • ---


    [0.3.7] - 2026-06-06


    ### Non-breaking


  • **Inbound targeting Phase 4 — voice "which session?" pick UX (flag-gated).** When `RINGDEV_INBOUND_TARGETING_ENABLED` is on, the inbound voice agent's `conversation-initiation` `system_prompt` now lists each live coding session with its `session_id` (non-spoken) and the START NEW SESSION capability routes the task: exactly one live session → auto-target it (set `target_session_id`) and confirm by name; more than one → ask which, then target; none → queue untargeted (today's behavior). The `start_coding_session` ElevenLabs server tool gains an optional, LLM-filled `target_session_id` param; the backend already resolves + stamps it against the verified caller's OWN live sessions (since [0.3.6]/M3 — a foreign id is ignored). Session UUIDs are still NEVER read aloud (the spoken `first_message` carries none). Flag off ⇒ the prompt is byte-identical to pre-Phase-4 (plain untargeted start).

  • ---


    [0.3.6] - 2026-06-06


    ### Non-breaking


  • **Inbound claim is targeting-aware behind a flag (inbound targeting, Phase 3, dark-shipped).** `GET /v1/mcp/inbound-sessions` now accepts an optional `X-RingDev-Agent-Session` request header carrying the id of the caller's live `AgentSession`. When `RINGDEV_INBOUND_TARGETING_ENABLED=true`, the claim is narrowed to the tasks routed to that session or repo, plus any task with no explicit session/repo target (disjoint precedence; a spoken project is metadata/label only, never a routing filter — so project-scoped tasks are claimable by anyone and never starve); the header is resolved server-side and scoped to the authenticated account, so it can never claim another user's work, and an unknown/foreign id falls back to the untargeted claim. With the flag off (default), or with the header absent, the claim is byte-identical to today's per-user first-come delivery. Targeting is always server-derived from the connection, never from a tool argument: the remote `check_inbound_requests` tool contract is unchanged (still no parameters). The `InboundSession` response shape gains two additive, nullable fields — `target_repo` (the canonicalized git remote the task was routed to) and `label` (the human label of the targeted live session) — both null for untargeted tasks; existing fields are unchanged. The published `@ringdev/mcp` stdio client now learns its `AgentSession` id from a relay `session:registered` ack and sends the `X-RingDev-Agent-Session` header when known (older clients/servers simply omit it, unchanged behavior).

  • ---


    [0.3.5] - 2026-06-06


    ### Security


  • **`start-session` identity hardened (IDOR fix).** `POST /v1/agent-webhooks/inbound/start-session` now resolves the developer identity from the VERIFIED caller binding (the dialed number's owner, gated on the caller's verified phone) — the same gate `conversation-initiation` and `session-status` apply — NOT from a tool-supplied `user_id`. A forged `user_id` is ignored; an unverified caller is refused (no session created, no IDE poke). Previously a forged `user_id` could create a coding task under another user's account that their connected IDE would then pick up. The ElevenLabs `start-session` server tool must forward `caller_id` + `called_number` (it no longer uses `user_id`).

  • ---


    [0.3.4] - 2026-06-06


    ### Non-breaking


  • **Inbound status now reflects live IDE/agent sessions (inbound targeting, Phase 2).** `POST /v1/agent-webhooks/inbound/conversation-initiation` and `POST /v1/agent-webhooks/inbound/session-status` now merge the developer's live `AgentSession` registry rows (repo, branch, label, current task) with RingDev's own `CallSession` rows, so a developer who is mid-session in their IDE with no open call no longer hears "no active coding sessions." The spoken opener (`first_message`) and `system_prompt` carry distinct zero / one / many phrasings; session UUIDs are never placed in any spoken field (the voice model mis-reads them). `session-status` gains a `live_sessions` array (each entry: `name`, `repo`, `branch`, `ide`, `current_task` — no UUID). No targeting/claim behavior changes (that is a later, flag-gated phase); this only makes status accurate.
  • **`session-status` identity hardened (security).** `POST /v1/agent-webhooks/inbound/session-status` now resolves the developer identity from the VERIFIED caller binding (the dialed number's owner gated on the caller's verified phone), the same gate `conversation-initiation` already applies — NOT from a tool-supplied `user_id`. A forged or mismatched `user_id` argument is ignored and returns no sessions, so the voice agent cannot be coerced into reading back another user's data. An unverified caller receives empty session lists.

  • ---


    [0.3.3] - 2026-06-06


    ### Non-breaking


  • **New MCP tool `register_session` (inbound targeting, Phase 1).** Lets a connected agent declare its working context so a phoned-in coding task can later be routed to the right live session. Params (all optional): `repo` (a git remote URL, canonicalized server-side), `branch`, `label`, `current_task`; a call updates the caller's live `AgentSession` row. Requires the `calls:read` scope. Optional and idempotent: omitting it leaves inbound delivery untargeted (today's behavior). Example: `register_session({ repo: "git@github.com:acme/api.git", branch: "main", label: "api worktree", current_task: "fix the login bug" })`. This is write-only registry plumbing; the routing/claim behavior ships in a later, flag-gated phase.

  • ---


    [0.3.2] - 2026-06-05


    ### Non-breaking


  • **Insights privacy and settings surfaces (M4).** New dashboard endpoints (JWT session auth, every query scoped to the calling user): `GET /v1/insights/settings` returns the current settings snapshot plus the count of signals awaiting review; `GET /v1/insights/pending` lists the user's manual/strict captures not yet approved (cursor-paginated, default 20 max 100); `POST /v1/insights/pending/{id}/approve` marks a pending signal approved so it becomes scoreable; `POST /v1/insights/pending/{id}/reject` removes it; `GET /v1/insights/history` searches the user's approved signals by a case-insensitive summary substring (cursor-paginated); `GET /v1/insights/export` returns a complete JSON export (settings, signals, scorecards, badges); and `DELETE /v1/insights/data` cascades a delete of the user's signals, scorecards, and quarantine records and returns the counts removed. A cross-user id sees an empty list or a 404, never another user's data. The approve and reject endpoints honour an `Idempotency-Key`. Full OpenAPI on all (operation summary+description, pagination/search query params, success and 401/404 responses, Authorization header).
  • **Insights settings now also accepts PATCH.** `PATCH /v1/insights/settings` performs the same partial update as the existing `POST /v1/insights/settings` (REST-correct verb for the dashboard); both validate the body, write only the provided fields, and record the change to the admin audit log. The POST is unchanged.

  • ---


    [0.3.1] - 2026-06-05


    ### Non-breaking


  • **Insights signal endpoint hardened (M3).** `POST /v1/insights/signal` now enforces the standard platform contract: it requires a Bearer credential (an `rdk_` API key or an OAuth access token; missing or invalid returns 401, capture-not-enabled returns 403), honours `Idempotency-Key` (a replay returns the first result and stores no duplicate), and is rate-limited to 60 requests per minute per API key (429 with a `Retry-After` header on exceed). When the server-side redactor detects a possible secret the capture is quarantined and the user is emailed out of band (detector type only, never the secret value). OpenAPI now documents the 401/403/429 responses, the `Authorization` and `Idempotency-Key` headers, and a request-body example.
  • **Insights settings validated and audited (M3).** `POST /v1/insights/settings` now validates its body (typed fields, bounded retention, and the previously-ignored `insightsLeaderboardOptIn`) and rejects malformed input with 400; `POST /v1/insights/pause` resumes when `durationMinutes` is 0. Every settings change and every pause/resume is recorded to the admin audit log.

  • ---


    [0.3.0] - 2026-06-04


    ### Non-breaking


  • **OAuth 2.1 for the hosted MCP server (Layer B2) — now LIVE.** IDEs connect to `https://mcp.ringdeveloper.com/mcp` by URL + browser sign-in, with no API key. New surface at the issuer root (outside the `/v1` prefix): `GET /.well-known/oauth-protected-resource` (+ `/.well-known/oauth-protected-resource/mcp`), `GET /.well-known/oauth-authorization-server`, and `GET /.well-known/jwks.json` (RFC 9728 / 8414 / 9068); `GET /oauth/authorize` + `POST /oauth/authorize/decision` (browser consent); `POST /oauth/token` (`authorization_code` with PKCE S256, plus `refresh_token` rotation with reuse-detection; audience-bound RS256 JWT access tokens at a ~30 min TTL); `POST /oauth/register` (RFC 7591 Dynamic Client Registration, public/PKCE, rate-limited); and `POST /oauth/revoke` (RFC 7009). The `/mcp` guard now accepts EITHER `Authorization: Bearer rdk_...` (B1, unchanged) OR an OAuth JWT, resolving both to the same `{ userId, scopes }` principal. Gated by `RINGDEV_MCP_OAUTH_ENABLED` (now on). Spec Layer B / B2, Phases 1-3.
  • **OAuth dashboard CRUD (B2 Phase 4)** — `GET` / `DELETE /v1/oauth-dashboard/connections` (list + revoke authorized apps; revoke cascades the refresh-token family) and `GET` / `POST` / `DELETE /v1/oauth-dashboard/clients` (list + register + delete static clients; a confidential client returns its `client_secret` exactly once). JWT-authed, CSRF-guarded, ownership-scoped (404 on a cross-user id). Now documented in OpenAPI under the "OAuth Apps" tag.
  • **Dual-path install messaging** — the marketing site, docs, and post-login onboarding now present OAuth (browser sign-in, no key) alongside the API-key path; the home-page install block and docs single-source the hosted URL from `RINGDEV_REMOTE_URL`.
  • **Founder signup alert email** — a Resend email with the full signup + onboarding details is sent on first onboarding completion, to the addresses in `SIGNUP_ALERT_EMAILS`.

  • ### Security (auth audit remediation)


  • **CRITICAL — account-merge token forgery fixed.** The account-merge flow signed and verified its token with a hardcoded fallback secret, so an authenticated user could forge `{ sourceUserId, targetUserId }` and absorb any account. It now requires `MERGE_JWT_SECRET` (at least 32 chars, fail-closed) and pins the verification algorithm.
  • **OAuth / API-key scopes are now enforced.** Scopes were stored but never checked, so a read-only credential could place billable calls. Enforced per MCP tool (`ring_developer` / `notify_completion` require write, `check_inbound_requests` requires read) and on the REST call routes; `calls:write` and `calls:initiate` are synonyms, and write implies read.
  • **CSRF on `POST /oauth/authorize/decision`** — the consent decision route now runs the CsrfGuard (the guard existed but the route was missing it).
  • **Refresh tokens are rejected on the Bearer access path** (token-type confusion), and the access-token JWT verification algorithm is pinned.
  • **GitHub OAuth links only a verified email** — the strategy resolves a verified primary email from GitHub and refuses to auto-link an unverified email to an existing account (account-takeover fix).
  • **Rate-limit keys use `req.ip`** (behind Express `trust proxy`) instead of the spoofable left-most `X-Forwarded-For`, on both the global throttler and the DCR limiter.
  • **Removed credential logging** from `POST /v1/auth/refresh` (it was writing request headers and cookies, including the refresh JWT, to stdout).

  • ---


    [0.2.3] - 2026-06-03


    ### Non-breaking


  • **Hosted remote MCP transport (Streamable HTTP + Bearer)** — new `POST`/`GET`/`DELETE /mcp`, served at `https://mcp.ringdeveloper.com/mcp` (outside the `/v1` prefix). RingDev can now be added as a remote MCP connector by URL + `Authorization: Bearer rdk_...` — no local Node process, no per-IDE config file. Exposes the same three tools as the stdio server (`ring_developer`, `notify_completion`, `check_inbound_requests`); the outbound destination number is resolved server-side from the account's verified phone. Co-hosted in the API, gated by `RINGDEV_MCP_REMOTE_ENABLED` (default off — ship dark). The stdio package and `rdk_` auth are unchanged. Spec Layer B / B1. (Follow-ups: B2 OAuth one-click for Claude Desktop; Redis pub/sub for multi-replica result routing — currently in-process / single-replica; live server-to-client inbound push over SSE — inbound currently delivered via the `check_inbound_requests` poll tool.)

  • ---


    [0.2.2] - 2026-06-03


    ### Non-breaking


  • **`GET /v1/mcp/discovery` now authenticates with the `rdk_` API key** (`ApiKeyGuard` + `McpVersionGuard`) instead of `JwtAuthGuard`. The only caller, the MCP server, sends an API key, so the endpoint previously always returned 401 and project-based number routing (`RINGDEV_PROJECT_SLUG`) was non-functional. It now returns the bound inbound number for the authenticated key. No working JWT caller existed, so this is a fix, not a breaking change. Full Swagger coverage added (Authorization header, `projectSlug` query, 200/401 responses).
  • **MCP client envelope fix** — `discoverInboundNumber` unwraps the standard `{ success, data, error }` response envelope (it previously returned the whole envelope, so `inboundNumber` read as `undefined` and the server silently fell back to `RINGDEV_PHONE`). `initiateCall` was already correct.
  • **MCP client version derivation** — the `X-MCP-Client` header and the advertised `McpServer` version now derive from `package.json` instead of a hardcoded `0.1.0`, so the `McpVersionGuard` floor sees the real version.
  • **Shared IDE-config generator** — new `@ringdev/shared-types/mcp-config` (`generateIdeConfig`) is the single source of truth for per-IDE install config, consumed by the marketing install block, the dashboard `/api-keys` page, and a new IDE-aware CLI wizard (`npx @ringdev/mcp setup --ide=<id>`). The marketing snippet now always includes the required `env` block (it was credential-less and crashed on launch) and VS Code uses the native `servers` + `type:"stdio"` schema.

  • ---


    [0.2.1] - 2026-06-03


    ### Non-breaking


  • **Inbound voice-initiated coding sessions now reach the IDE** — `POST /v1/agent-webhooks/inbound/start-session` resolves the developer's owning API key, stamps `apiKeyId` on the created session, and dispatches the new `call.start_work` MCP event. Previously the session was created in the database but never delivered to any IDE.
  • **New endpoint `GET /v1/mcp/inbound-sessions`** (API-key auth) — a connected MCP relay claims the voice-initiated coding tasks queued for its owner. Each session is returned at most once (claimed sessions are marked delivered, so concurrent IDEs never pick up the same work). The relay calls it on connect and on each `call.start_work` poke, which also replays work queued while the IDE was offline.
  • **New MCP callback event `call.start_work`** — a poke telling the relay client to fetch newly queued inbound work. Distinct from `call.answered` / `call.failed`; carries only `session_id`.
  • **New MCP tool `check_inbound_requests`** — returns the coding tasks the developer started by phone, for the agent to pick up. Takes no parameters.

  • ---


    [0.2.0] - 2026-05-16


    ### Breaking


  • **JSON body size limit** — All endpoints now reject JSON payloads larger than 100KB with HTTP 413 (Payload Too Large). Webhook controllers using rawBody (Razorpay, Stripe) are unaffected. Artifact uploads use presigned S3 URLs and bypass this limit.

  • ### Non-breaking


  • **CORS hardening** — `CORS_ORIGINS=*` is now forbidden in production (API refuses to boot). In development, wildcard origin reflects the request origin but disables credentials. Resolved origins are logged at boot.
  • **Sign-out token revocation** — `POST /v1/auth/logout` now clears the `ringdev_refresh` httpOnly cookie server-side and blacklists the refresh token jti in Redis.
  • **HMAC nonce upgrade** — `signRequest()` nonce generation switched from `Math.random().toString(36)` to `crypto.randomBytes(12).toString('base64url')`. Both old and new nonce formats are accepted by verifiers (opaque string comparison).
  • **GitHub OAuth** — Added `GET /v1/auth/github` (redirect to GitHub authorize) and `GET /v1/auth/github/callback` (code exchange, token mint, cookie set). Persists `githubUsername` and `githubAvatarUrl` on the User record. Merges accounts by email.
  • **CSRF protection** — Double-submit cookie pattern via `ringdev_csrf` cookie + `X-CSRF-Token` header. `CsrfGuard` rejects state-changing requests where cookie and header do not match. Exempt: webhooks, API-key auth, safe methods.
  • **Per-user throttling** — Named throttler tiers (`auth`: 5/min, `api`: 100/min) with `UserScopedThrottlerGuard` that keys by userId or IP.
  • **Role from /me** — Frontend no longer decodes the JWT client-side. Role is fetched from `GET /v1/auth/me` server response.
  • **Enhanced /me response** — `GET /v1/auth/me` now returns full user profile from DB including `primaryTechStack`, `experienceBand`, `onboardedAt`, `marketplaceOptedInAt`, `githubUsername`, `githubAvatarUrl`.
  • **Onboarding endpoint** — Added `POST /v1/auth/onboarding` accepting `tech_stack` (max 5) and `experience_band` enum. Sets `onboarded_at` on the user record.
  • **Onboarding gate** — Users without `onboarded_at` are redirected to `/onboarding` from the app shell. The wizard collects phone, tech stack tags, and experience band.
  • **Unified signup** — `/sign-up` redesigned with GitHub OAuth as primary CTA, email/password as secondary. No marketplace language.
  • **Developer Portal gating** — Sidebar "Developer Portal" link now only visible when `marketplace_opted_in_at` is set.
  • **Phone management endpoints** — 7 new endpoints under `GET/POST/PUT/DELETE /v1/auth/me/phones` for add, verify (OTP), resend, set primary, remove, and `GET /v1/auth/me/primary-phone` for MCP bootstrap.
  • **Phone verification on calls** — `POST /v1/calls/initiate` now validates that `customer_phone` is verified. 30-day grace period (log-only), then hard reject with `phone_not_verified`.
  • **Phone masking** — `maskPhone()` utility masks E.164 numbers in logs and error messages per Rule 6.2.
  • **Developer live call panel** — New page at `/dev/jobs/active/[id]` with 3-column layout: question/context, artifacts, and auto-saving notes. Live timer, state badge with pulse animation, WebSocket artifact sync, "Mark resolved" + "Escalate to admin" footer.
  • **Job notes** — `MarketplaceJobNotes` model with `PUT /v1/developers/me/jobs/:id/notes` (auto-saved, 5s debounce, 50KB max). Notes visible to admins post-call.
  • **Job resolve** — `POST /v1/developers/me/jobs/:id/resolve` transitions job to completed with duration calculation. Idempotent.
  • **Conference bridging** — 6 new methods on TwilioPhoneService: `createConference`, `joinCallToConference`, `placeOutboundIntoConference`, `kickFromConference` (3-retry safety), `endConference`, `listConferenceParticipants`.
  • **Escalation orchestrator** — `EscalationService` managing steps 1–11 of Tier 2 flow: conference creation, customer redirect, developer bridge, and agent leg removal with safety guarantee.
  • **Conference webhook** — `POST /v1/twilio/conference/status` handling `conference-start`, `conference-end`, `participant-join`, `participant-leave`. Agent leg confirmed via participant-leave event.
  • **Stuck conference detector** — Cron every 15s: ends conferences with ≤1 participant for 30s, marks call failed with `conference_solo_participant`.
  • **Recording consent** — All 3 agent `firstMessage` strings now begin with "this call may be recorded for quality and training purposes".
  • **Stripe payment provider** — Added `POST /v1/billing/webhook/stripe` for subscription lifecycle events, `GET /v1/billing/subscription/portal` for Stripe Customer Portal, and country-based provider routing (Stripe for 21 countries, Razorpay for India).
  • **Stripe Connect for developers** — Added `POST /v1/developers/me/connect/onboard` and `GET /v1/developers/me/connect/status` for international developer payout onboarding.

  • ---


    [0.1.0] - 2026-05-03


    ### Non-breaking


  • **Response envelope standardized** — All endpoints now return `{ "success": true, "data": { ... }, "error": null }` on success and `{ "success": false, "data": null, "error": { "message", "code", "statusCode" } }` on failure.
  • **Idempotency-Key support** — All state-changing POST endpoints accept an `Idempotency-Key` header. Duplicate requests within 24h return the original cached response.
  • **API Reference (Scalar)** — Replaced Swagger UI with Scalar at `/reference`. Dark-themed, branded with amber accent. Old `/api-docs` and `/swagger` paths 308-redirect to `/reference` (redirect active for 30 days). `openapi.json` auto-generated in `docs/api/`.
  • **Atomic state transitions** — Call session state changes are now transactional with row-level locking to prevent race conditions from concurrent webhook deliveries.
  • **CI guard** — GitHub Actions workflow `openapi-check.yml` fails PRs if `openapi.json` diverges from the running app.

  • ### Endpoints documented


    | Method | Path | Tags |

    |--------|------|------|

    | POST | `/v1/auth/signup` | Auth |

    | POST | `/v1/auth/login` | Auth |

    | GET | `/v1/auth/me` | Auth |

    | POST | `/v1/auth/api-keys` | Auth |

    | GET | `/v1/auth/api-keys` | Auth |

    | DELETE | `/v1/auth/api-keys/:id` | Auth |

    | POST | `/v1/calls/initiate` | Calls |

    | POST | `/v1/calls/:id/escalate` | Calls |

    | GET | `/v1/calls/:id` | Calls |

    | GET | `/v1/calls` | Calls |

    | POST | `/v1/calls/:sessionId/artifacts/upload-url` | Artifacts |

    | POST | `/v1/calls/:sessionId/artifacts/snippet` | Artifacts |

    | GET | `/v1/calls/:sessionId/artifacts` | Artifacts |

    | POST | `/v1/agent-webhooks/submit-answer` | Webhooks |

    | POST | `/v1/agent-webhooks/request-clarification` | Webhooks |

    | POST | `/v1/agent-webhooks/escalate` | Webhooks |

    | POST | `/v1/agent-webhooks/post-call/transcription` | Webhooks |

    | POST | `/v1/agent-webhooks/post-call/audio` | Webhooks |

    | POST | `/v1/agent-webhooks/post-call/initiation-failure` | Webhooks |

    | GET | `/v1/health` | Health |