# KlawVoice documentation — full text
Source: https://klaw-voice.netlify.app/docs · index: https://klaw-voice.netlify.app/llms.txt · agent setup: https://klaw-voice.netlify.app/skills.md

---

<!-- Getting started · Introduction · https://klaw-voice.netlify.app/docs/get-started/introduction -->

# Introduction

KlawVoice gives an AI agent a working phone presence: a real US/Canada phone number,
a natural voice, and a persona that handles live calls and texts. You (or your coding
agent) drive all of it through one REST API and one MCP server.

## What you can do

- **Put an agent on the phone** — provision a local number with voice and SMS webhooks
  wired from the first ring, attach a persona and an ElevenLabs voice, and take live calls.
- **Place outbound AI calls** — your agent dials a person, holds a spoken conversation
  toward an objective, and streams back a transcript you can watch in real time.
- **Send and receive messages** — two-way SMS on the same number, plus WhatsApp.
- **Ground answers in your content** — attach a knowledge base (or point the agent at a
  website) and calls are answered from your actual material.
- **React to events** — HMAC-signed webhooks, server-sent events, and long-polling for
  everything that happens on your numbers.

## Two ways in

**From a coding agent.** Paste one of the prompts on the [homepage](/) into Claude Code,
Cursor, or any MCP client — the agent fetches [skills.md](/skills.md) and does the whole
setup for you. See [Using KlawVoice from an agent](/docs/get-started/from-an-agent).

**From the API.** Sign up, mint an API key, and make one `POST` request that creates an
agent with a persona, a voice, and a number. See the [Quickstart](/docs/get-started/quickstart).

## Where to go next

- [Quickstart](/docs/get-started/quickstart) — a ringing phone in five requests.
- [Core concepts](/docs/get-started/core-concepts) — agents, numbers, calls, events.
- [Whitepaper](/whitepaper) — why voice needs an agent-native trust layer.


---

<!-- Getting started · Quickstart · https://klaw-voice.netlify.app/docs/get-started/quickstart -->

# Quickstart

Five requests from zero to your phone ringing. Everything runs against `https://klaw-voice.netlify.app`.

## 1. Create an account

```bash
curl -X POST https://klaw-voice.netlify.app/api/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","name":"Your Name","password":"a-strong-password"}'
```

The response includes `{"token": "..."}` — a session token you can use as a Bearer
token immediately. For long-lived integrations mint an API key instead (step 2).

## 2. Mint an API key

```bash
curl -X POST https://klaw-voice.netlify.app/api/auth/api-key -H "Authorization: Bearer $TOKEN"
```

Returns a `klw_...` key **once** — store it now; only a hash is kept server-side.
Use it as `Authorization: Bearer klw_...` on every call below. See
[Authentication](/docs/get-started/authentication).

## 3. Create an agent — persona, voice, and number in one call

```bash
curl -X POST https://klaw-voice.netlify.app/api/agents/quickstart \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{
    "preset": "receptionist",
    "business_name": "Sunrise Dental",
    "instructions": "You are the friendly front desk for Sunrise Dental. Book cleanings, answer hours questions, capture callbacks.",
    "voice_id": "EXAVITQu4vr4xnSDxMaL",
    "with_number": true,
    "area_code": "415"
  }'
```

Response: `{"agent": {...}, "phone_number": "+1415...", "number_error": null}`.
Only `preset` is required — everything else is optional refinement. If number
provisioning fails you still get the agent plus a `number_error` you can retry.

## 4. Hear it — the agent calls you

```bash
curl -X POST https://klaw-voice.netlify.app/api/agents/$AGENT_ID/test-call \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"phone":"+14155550132"}'
```

Your phone rings within seconds. US/Canada numbers only; capped at 5 test calls per day.

## 5. Watch the transcript

```bash
curl https://klaw-voice.netlify.app/api/calls/$CALL_ID -H "Authorization: Bearer $KLAW_KEY"
```

Poll every few seconds while the call runs — the response carries `status` and a
growing `transcript` array. Terminal statuses: `completed`, `failed`, `busy`,
`no-answer`, `canceled`.

## Next

- [Place a call](/docs/capabilities/place-a-call) with objectives and idempotency.
- [Receive calls](/docs/capabilities/receive-a-call) on your new number.
- [Webhooks](/docs/platform/webhooks) instead of polling.


---

<!-- Getting started · Using KlawVoice from an agent · https://klaw-voice.netlify.app/docs/get-started/from-an-agent -->

# Using KlawVoice from an agent

KlawVoice is built to be operated *by* agents, not just for them. A coding agent can
take a human from nothing to a working phone agent without leaving the chat.

## The paste-a-prompt path

Copy a prompt from the [homepage](/#quickstart) into Claude Code, Cursor, Windsurf, or
any MCP client. The prompt points the agent at [https://klaw-voice.netlify.app/skills.md](/skills.md) — original,
agent-readable setup instructions covering signup, agent creation, personas, voices,
numbers, and a proof-of-life test call, with consent guardrails built in.

## The MCP path

KlawVoice runs an MCP server at `https://klaw-voice.netlify.app/api/mcp` (JSON-RPC 2.0). Fourteen tools cover
the full surface: `create_persona`, `update_persona`, `list_personas`,
`search_numbers`, `provision_number`, `list_numbers`, `place_call`, `list_calls`,
`get_call_transcript`, `send_message`, `wait_for_event`, `add_knowledge`,
`list_leads`, and `get_usage`.

```bash
claude mcp add --transport http klawvoice https://klaw-voice.netlify.app/api/mcp
```

Tool calls authenticate with the same `klw_` key as REST:
see [MCP server](/docs/platform/mcp-server) for per-client configs.

## Machine-readable surfaces

| URL | What it is |
| --- | --- |
| `/skills.md` | Step-by-step setup instructions for coding agents |
| `/llms.txt` | Compact index of endpoints and docs |
| `/llms-full.txt` | Every docs page (and the whitepaper) as one markdown stream |
| `/.well-known/dividen-agent.json` | SMCP node discovery with signed attestation |

## Ground rules we ask agents to follow

- Get the human's consent (and their number) before dialing anyone.
- Provision one number unless explicitly asked for more — numbers bill monthly.
- Report costs honestly: agents are free, numbers ~$1/month, calls bill by the minute.


---

<!-- Getting started · Authentication · https://klaw-voice.netlify.app/docs/get-started/authentication -->

# Authentication

Every authenticated endpoint accepts one header:

```
Authorization: Bearer <token>
```

where `<token>` is either a **session token** (JWT from signup/login, 30-day) or a
**platform API key** (`klw_...`). API keys are also accepted via an `X-API-Key`
header for tools that can't set Authorization.

## Session tokens

`POST /api/auth/signup` `{email, name, password}` → `{token, user}` — or
`POST /api/auth/login` with the same shape for an existing account. Sessions suit
dashboards and short scripts.

## API keys (recommended for integrations)

```bash
curl -X POST https://klaw-voice.netlify.app/api/auth/api-key -H "Authorization: Bearer $TOKEN"
```

- The raw `klw_` key is returned **once**; only a SHA-256 hash is stored.
- **Rotate** by calling `POST` again (the old key stops working).
- **Revoke** with `DELETE /api/auth/api-key`.
- Manage from the dashboard under **Settings → API key**.

API-key traffic is rate-limited to **100 requests/minute** per key; over-limit requests
get `429` with a `Retry-After` header. See [Rate limits](/docs/reference/rate-limits).

## Stream tokens

Server-sent-event URLs can't safely carry a permanent key, so mint a short-lived one:

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/events/stream-token -H "Authorization: Bearer $KLAW_KEY"
```

Returns a `klwst_` token valid ~120 seconds, used only as `?token=` on
`GET /api/v1/events/stream`. Permanent keys are refused in stream URLs.

## MCP

`tools/call` on `https://klaw-voice.netlify.app/api/mcp` requires `Authorization: Bearer klw_...`.
Discovery methods (`initialize`, `tools/list`, `ping`) are open.


---

<!-- Getting started · Core concepts · https://klaw-voice.netlify.app/docs/get-started/core-concepts -->

# Core concepts

Five nouns explain the whole platform.

## Agents (personas)

An **agent** is a persona on the phone: a name, a playbook (`system_prompt`), a
greeting (`first_message`), a voice, optional knowledge, and optionally a number.
Create one from a preset in a single call (`POST /api/agents/quickstart`) or field by
field (`POST /api/v1/agents`). A persona is just an agent made public.

## Phone numbers

A number belongs to exactly **one agent** — that invariant is what makes inbound
routing unambiguous. Provisioning wires Twilio voice, SMS, and status webhooks
automatically, so the number works the moment it exists. In the v1 API a number is
addressed by its owning agent (`number.id == agent.id`).

## Calls

Inbound calls hit the agent that owns the dialed number. Outbound calls are placed
with `POST /api/v1/calls` (`agent_id`, `to`, optional `objective`). Every call
persists a turn-by-turn transcript you can poll live, plus post-call summary,
sentiment, and intent.

## Messages

The same number does two-way SMS (`POST /api/v1/messages`) and receives WhatsApp.
Inbound messages are answered by the owning agent and emitted as events.

## Events

Everything observable — `call.started`, `call.ended`, `call.transcribed`,
`call.completed`, `call.takeover`, `message.received`, `message.sent`,
`webhook.ping` — is persisted and delivered three ways: signed
[webhooks](/docs/platform/webhooks), an SSE stream, and cursor/long-poll
[endpoints](/docs/platform/events). Pick per consumer; they're the same events.

## How they fit

```
persona + voice + number  →  agent
agent + caller            →  call (live transcript)
agent + knowledge base    →  grounded answers
anything happening        →  event → webhook / stream / poll
```


---

<!-- Capabilities · Place a call · https://klaw-voice.netlify.app/docs/capabilities/place-a-call -->

# Place a call

Your agent dials a person, speaks with its configured voice, works toward an objective,
and records a transcript.

## The request

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/calls \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: lead-4821-attempt-1" \
  -d '{
    "agent_id": "AGENT_UUID",
    "to": "+14155550132",
    "objective": "Confirm Thursday appointment; offer to reschedule if needed.",
    "metadata": {"lead_id": "4821"},
    "callback_url": "https://example.com/hooks/call-done"
  }'
```

- `agent_id` and `to` (E.164) are required; everything else is optional.
- `objective` steers the conversation for this one call without editing the playbook.
- `metadata` (≤8 KB) rides along and comes back on events and call records.
- The `Idempotency-Key` header makes retries safe — same key, same call.

Response `201`: `{"call_id", "call_sid", "status", "polling_url", "transcript_url"}`.

## Watching it live

Poll `GET /api/v1/calls/{id}` (full record: status, transcript, summary, sentiment,
intent) or `GET /api/v1/calls/{id}/transcript` for just the turns. Prefer push?
Subscribe a [webhook](/docs/platform/webhooks) to `call.ended` / `call.transcribed`.

## Guardrails

Outbound calling is capped at **5 concurrent** and **50 calls/hour** per account —
see [Rate limits](/docs/reference/rate-limits). Calls to a person require their prior
consent; you are responsible for complying with telemarketing law in your jurisdiction.

## Quick proof-of-life

`POST /api/agents/{id}/test-call` `{"phone": "+1..."}` rings **you** (NANP numbers,
5/day) — the fastest way to hear a persona before pointing it at customers.


---

<!-- Capabilities · Receive a call · https://klaw-voice.netlify.app/docs/capabilities/receive-a-call -->

# Receive a call

Give an agent a number and inbound just works: KlawVoice wires the Twilio voice,
SMS, and status webhooks at purchase time. There is no separate "configure inbound" step.

## What answers the phone

The agent that owns the dialed number answers with its `first_message`, in its
configured voice, following its `system_prompt` playbook. If a knowledge base is
attached, answers are grounded in it. Callers hear a natural turn-based conversation —
see [How KlawVoice works](/docs/reference/how-it-works) for the pipeline.

## Shaping inbound behavior

- **Playbook**: `PATCH /api/agents/{id}` with a new `system_prompt` — structure it as
  Greeting / Handle / Wrap up. Presets give you a strong starting playbook.
- **Greeting**: `first_message` is the first thing callers hear.
- **Per-number instruction**: `PATCH /api/v1/numbers/{id}` accepts an
  `inbound_instruction` when the number should behave differently than the base persona.
- **Escalation**: agents support an `escalation_phone` and missed-call SMS follow-ups
  (`POST /api/v1/agents` fields `escalation_phone`, `missed_call_sms_enabled`).

## Observing inbound

Every inbound call emits `call.started`, then `call.ended` / `call.transcribed` /
`call.completed` with the transcript and post-call summary. Watch live in the
dashboard **Monitor** page — including a human take-over button — or consume
[events](/docs/platform/events) programmatically.

## Security note

Voice webhooks validate Twilio request signatures; forged webhook calls are rejected
before any agent logic runs.


---

<!-- Capabilities · Send a message · https://klaw-voice.netlify.app/docs/capabilities/send-a-message -->

# Send a message

Two-way SMS ships with every number. The sender is resolved from the numbers your
agents own.

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/messages \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{
    "to": "+14155550132",
    "body": "Hi Sarah — confirming your cleaning Thursday at 2pm. Reply C to confirm.",
    "idempotency_key": "confirm-4821"
  }'
```

- `to` and `body` (≤1600 chars) are required.
- `from` (an E.164 you own) or `from_number_id` picks the sending number when you
  have several; with one number you can omit both.
- `idempotency_key` makes retries safe.

Response `201`: `{"id", "status", "provider_sid", "to", "from"}`. A `message.sent`
event is emitted on success.

## Listing traffic

`GET /api/v1/messages?direction=outbound&limit=50` — filter by `direction`
(`inbound`/`outbound`) and `limit`.

## WhatsApp

Inbound WhatsApp to your number is handled by the owning agent automatically and
emitted as `message.received`. Outbound WhatsApp is available from the dashboard
WhatsApp inbox; a v1 WhatsApp send endpoint is on the roadmap.


---

<!-- Capabilities · Receive a message · https://klaw-voice.netlify.app/docs/capabilities/receive-a-message -->

# Receive a message

Inbound SMS and WhatsApp to any of your numbers are handled twice over:

1. **The agent replies.** The number's owning agent answers using the same playbook
   and knowledge that drive its calls — a text-message receptionist for free.
2. **You get the event.** Every inbound message is persisted and emitted as a
   `message.received` event.

## Consuming inbound programmatically

**Push** — subscribe a [webhook](/docs/platform/webhooks):

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/webhooks \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/klaw", "events": ["message.received"]}'
```

**Block until it arrives** — long-poll, ideal for agents waiting on a reply or a
verification code:

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/events/wait \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"types": ["message.received"], "timeout_ms": 55000}'
```

Returns `{"event": {...}}` as soon as a message lands, or
`{"event": null, "timed_out": true}` after the timeout — loop as needed.

**Stream** — server-sent events; see [Events](/docs/platform/events).

The MCP tool `wait_for_event` wraps the long-poll for MCP clients.


---

<!-- Capabilities · Knowledge base · https://klaw-voice.netlify.app/docs/capabilities/knowledge-base -->

# Knowledge base

Agents answer from your content, not from vibes. Attach documents and they are chunked,
embedded, and retrieved per turn during calls and messages.

## Adding knowledge

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/agents/$AGENT_ID/knowledge-base \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Services and pricing", "content": "...up to 100KB of text..."}'
```

Response `201`: `{"knowledge_base_id", "document", "chunks"}` — the text is split
into chunks and embedded immediately; the very next call can use it.

## From a website

During [onboarding](/onboard), pasting a website URL scrapes the site and attaches the
text as a knowledge document automatically. The same works via the public preview
route + the endpoint above if you're scripting it.

## How retrieval works on calls

Each caller turn runs a vector search over the agent's chunks (embeddings +
Postgres/pgvector) under a tight latency budget, and the best passages are injected
into the reply prompt. Short acknowledgements ("yes", "okay") skip retrieval to keep
the conversation snappy. Details in [How KlawVoice works](/docs/reference/how-it-works).

## Tips

- Prefer several focused documents ("Hours & location", "Pricing", "FAQ") over one blob.
- Write like you'd talk: retrieval surfaces sentences, and the agent speaks them.
- Update by adding fresh documents; the newest content is available immediately.


---

<!-- Capabilities · Voices · https://klaw-voice.netlify.app/docs/capabilities/voices -->

# Voices

Every agent speaks with an ElevenLabs voice; Amazon Polly stands in automatically when
TTS is unavailable so calls never go silent.

## List the curated set

```bash
curl https://klaw-voice.netlify.app/api/elevenlabs/voices -H "Authorization: Bearer $KLAW_KEY"
```

Returns ~15 curated premade voices (`{id, name, gender, accent, description, ...}`)
picked for phone conversations. If you've connected your own ElevenLabs key, your
cloned voices are included too.

## Preview before you pick

```bash
curl -X POST https://klaw-voice.netlify.app/api/elevenlabs/preview \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"voice_id": "EXAVITQu4vr4xnSDxMaL"}' --output preview.mp3
```

Streams a short receptionist line as `audio/mpeg` (rate-capped 40/min).

## Set the voice

At creation (`voice_id` on `POST /api/agents/quickstart`) or any time after:

```bash
curl -X PATCH https://klaw-voice.netlify.app/api/agents/$AGENT_ID \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"elevenlabs_voice_id": "EXAVITQu4vr4xnSDxMaL"}'
```

## Cloning and BYO keys

Voice cloning is available at `POST /api/voice-clone`, and you can bring your own
ElevenLabs API key in dashboard settings — voices then bill to your account and your
clones appear in the list. Language behavior (including multilingual mirroring) is set
per agent via its `language` field.


---

<!-- Platform · Phone numbers · https://klaw-voice.netlify.app/docs/platform/phone-numbers -->

# Phone numbers

Real US/Canada local numbers, provisioned in seconds, owned by exactly one agent each.

## Provision

One call — search and purchase together, optionally creating a minimal agent if you
don't pass one:

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/numbers \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"area_code": "415", "agent_id": "AGENT_UUID", "nickname": "Front desk line"}'
```

Or pick precisely: `GET /api/twilio/numbers/available?area_code=415` lists candidates,
then pass the chosen `phone_number` instead of `area_code`. Voice, SMS, and status
webhooks are wired at purchase — the number answers immediately.

## Manage

| Action | Endpoint |
| --- | --- |
| List numbers | `GET /api/v1/numbers` |
| Get one | `GET /api/v1/numbers/{id}` |
| Rename / set inbound instruction | `PATCH /api/v1/numbers/{id}` |
| Release (returns it to Twilio) | `DELETE /api/v1/numbers/{id}` |

In v1, a number is addressed by its owning agent — `number.id` equals the agent's id.

## Invariants and limits

- **One number per agent.** Attaching a number that belongs to another agent returns
  `409` — release it there first.
- **Purchases are capped at 5/hour** per account (each one bills real money).
- Numbers cost about **$1/month**; releasing stops the charge.
- Attach to an existing agent later with `POST /api/v1/agents/{id}/phone-number`
  (`{"mode": "purchase", "area_code": "415"}` or an exact `phone_number`), or do it
  at creation with `with_number: true` on [quickstart](/docs/get-started/quickstart).


---

<!-- Platform · Events · https://klaw-voice.netlify.app/docs/platform/events -->

# Events

Everything observable on your account is persisted as an event and consumable three
ways. Same events, different delivery — pick per consumer.

## Event types

| Type | Fired when |
| --- | --- |
| `call.started` | A call (inbound or outbound) connects |
| `call.ended` | The call hangs up |
| `call.transcribed` | The final transcript is ready |
| `call.completed` | Post-call insights (summary, sentiment) are ready |
| `call.takeover` | A human takes over a live call |
| `message.received` | Inbound SMS/WhatsApp lands on your number |
| `message.sent` | An outbound message is accepted |
| `webhook.ping` | You fire a test ping at a subscription |

## Cursor polling

```bash
curl "https://klaw-voice.netlify.app/api/v1/events?type=call.ended&since=$CURSOR&limit=50" \
  -H "Authorization: Bearer $KLAW_KEY"
```

Returns `{"events": [...], "cursor": "..."}` — pass the cursor back to resume where
you left off.

## Long-poll (block until something happens)

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/events/wait \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"types": ["message.received", "call.ended"], "timeout_ms": 55000}'
```

Resolves with `{"event"}` the moment one lands, or `{"event": null, "timed_out": true}`.
Max wait 55s — loop it. This is what the MCP `wait_for_event` tool uses.

## Server-sent events

```bash
TOKEN=$(curl -s -X POST https://klaw-voice.netlify.app/api/v1/events/stream-token \
  -H "Authorization: Bearer $KLAW_KEY" | jq -r .token)
curl -N "https://klaw-voice.netlify.app/api/v1/events/stream?token=$TOKEN"
```

Streams run ~50 seconds then close (reconnect with a fresh token); up to 6 concurrent
streams per account. Permanent `klw_` keys are refused in stream URLs — that's what
the 120-second `klwst_` token is for.

For push delivery to your servers, use [Webhooks](/docs/platform/webhooks).


---

<!-- Platform · Webhooks · https://klaw-voice.netlify.app/docs/platform/webhooks -->

# Webhooks

HMAC-signed push delivery of [events](/docs/platform/events) to your HTTPS endpoint.

## Subscribe

```bash
curl -X POST https://klaw-voice.netlify.app/api/v1/webhooks \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/klaw",
    "events": ["call.ended", "call.transcribed", "message.received"],
    "description": "CRM sync"
  }'
```

- `url` must be HTTPS and publicly reachable (private/internal addresses are rejected).
- `events` lists types from the [table](/docs/platform/events), or `["*"]` for all.
- The response includes your signing secret `whsec_...` **once** — store it.

Manage with `GET /api/v1/webhooks`, `GET|DELETE /api/v1/webhooks/{id}`,
`POST /api/v1/webhooks/{id}/secret` (re-reveal), and
`POST /api/v1/webhooks/{id}/ping` (sends a `webhook.ping` you can verify end-to-end).

## Verify deliveries

Each delivery carries:

| Header | Meaning |
| --- | --- |
| `X-Klaw-Signature` | `sha256=` + HMAC-SHA256 of the raw body with your `whsec_` secret |
| `X-Klaw-Event` | The event type |
| `X-Klaw-Delivery` | Unique delivery id |

```js
import crypto from 'node:crypto'

function verify(rawBody, header, secret) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
  return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected))
}
```

Respond `2xx` quickly — deliveries time out after 4 seconds. Delivery status and the
last attempt time are visible on the subscription record.


---

<!-- Platform · MCP server · https://klaw-voice.netlify.app/docs/platform/mcp-server -->

# MCP server

KlawVoice speaks Model Context Protocol natively: `https://klaw-voice.netlify.app/api/mcp`, JSON-RPC 2.0 over
HTTP POST, protocol version `2024-11-05`. Discovery (`initialize`, `tools/list`,
`ping`) is open; `tools/call` authenticates with your `klw_` key as a Bearer token.

## Connect a client

```bash
# Claude Code
claude mcp add --transport http klawvoice https://klaw-voice.netlify.app/api/mcp
```

```json
// Cursor — .cursor/mcp.json (same shape for Claude Desktop)
{
  "mcpServers": {
    "klawvoice": { "url": "https://klaw-voice.netlify.app/api/mcp" }
  }
}
```

A human-friendly setup page with per-client walkthroughs lives at [/mcp](/mcp).

## The 14 tools

| Tool | Does |
| --- | --- |
| `create_persona` / `update_persona` / `list_personas` | Manage agents |
| `search_numbers` / `provision_number` / `list_numbers` | Find and buy numbers |
| `place_call` / `list_calls` / `get_call_transcript` | Outbound calls + transcripts |
| `send_message` | Outbound SMS |
| `wait_for_event` | Block until a call/message event arrives |
| `add_knowledge` | Attach knowledge to an agent |
| `list_leads` / `get_usage` | Captured leads, account usage |

Each tool is a thin wrapper over the same REST endpoints documented in the
[API reference](/docs/api/agents) — identical auth, identical limits, no separate
permission model to reason about.

## Discovery for other platforms

MCP server card: `/.well-known/mcp/server-card.json` · A2A agent card:
`/.well-known/agent-card.json` · signed node discovery:
`/.well-known/dividen-agent.json` — see [SMCP & attestation](/docs/platform/smcp-attestation).


---

<!-- Platform · SMCP & attestation · https://klaw-voice.netlify.app/docs/platform/smcp-attestation -->

# SMCP & attestation

Agents that transact with other agents need more than an API: they need a verifiable,
machine-readable statement of *who is offering what*. KlawVoice implements SMCP v0.1
as an agent-host node — every public capability ships in a signed manifest.

## Discovery endpoints (public, CORS-open)

| URL | Contents |
| --- | --- |
| `/.well-known/dividen-agent.json` | Node discovery: SMCP versions, protocols (MCP + A2A), governance, **signed host attestation** |
| `/.well-known/mcp/server-card.json` | MCP server card listing the 14 tools |
| `/.well-known/agent-card.json` | A2A card — one skill per public agent |
| `/api/smcp/agents/{slug}/manifest` | Per-agent capability manifest |

## What a manifest declares

Each public agent's manifest carries its capability declaration (formats, input/output
schema hashes, widget types), its **task contracts** with fixed settlement invariants
(funds hold, 48-hour review window, signed callbacks), and a `capabilityHash` — a
SHA-256 over the canonical form of the public declaration.

## ed25519 attestation

The host signs a fingerprint of its capability surface:

1. Build the canonical, **secret-free** surface (sorted keys, no volatile fields).
2. `manifestFingerprint = sha256:<hex>` over that canonical JSON.
3. Sign the fingerprint with the host's ed25519 key; publish
   `{manifestHash, keyId, alg, signature, publicKey}` alongside discovery.

Verifiers pin the key on first use (TOFU) and re-verify on every fetch — any silent
change to the capability surface shows up as a fingerprint mismatch (drift detection).

## The secret-free invariant

No serialized shape — manifest, card, or discovery document — may contain API keys,
webhook paths, or private key material. The conformance harness scans for it.

## Conformance

`npm run smcp:check` runs the offline suite: version negotiation, canonical-JSON
determinism, sign/verify round-trip (including tamper failure), manifest shape and
settlement invariants, and a drift guard that cross-checks the published tool list
against the live MCP server. `--live <url>` re-verifies against a deployment.

The design rationale is in the [whitepaper](/whitepaper).


---

<!-- Reference · How KlawVoice works · https://klaw-voice.netlify.app/docs/reference/how-it-works -->

# How KlawVoice works

A tour of the pipeline behind a call, for engineers deciding whether to trust it.

## The turn-based voice loop (default)

```
caller ⇄ Twilio ⇄ KlawVoice
  1. Twilio webhook (signature-verified) resolves the agent by dialed number
  2. Greeting spoken via ElevenLabs TTS (Polly fallback), listening starts
  3. Twilio speech recognition posts the caller's turn
  4. Knowledge retrieval (embeddings + pgvector, ≤1.2s budget)
  5. Reply generated — multiple LLM providers raced, first good answer wins (4.5s ceiling)
  6. Reply spoken; loop continues until hangup
```

Latency is engineered per stage: agent config is cached (60s), retrieval is skipped for
short acknowledgements, prompt context is trimmed to the last six turns, replies are
capped at one-two sentences for natural pacing, and time-to-first-token is recorded
per turn.

## Transcripts and insights

Every turn is appended atomically to the call record (JSONB append — safe under
concurrency), so `GET /api/v1/calls/{id}` shows the conversation as it happens.
When the call ends, a status callback computes the summary, sentiment, and intent,
then emits `call.ended`, `call.transcribed`, and `call.completed` events.

## The realtime bridge (optional)

Agents can opt into a streaming voice bridge: set the agent's `runpod_url` and its
calls route to a dedicated realtime media server instead of the turn-based loop. The
bridge self-registers its tunnel URL with the platform. Same personas, same transcripts,
lower latency — at the cost of running bridge infrastructure.

## Grounding

Knowledge documents are chunked and embedded at upload; per-turn retrieval runs a
vector search and injects the best passages into the reply prompt. See
[Knowledge base](/docs/capabilities/knowledge-base).

## Trust surface

Twilio webhooks are signature-verified; user webhooks are HMAC-signed and
SSRF-guarded; API keys are stored only as hashes; public capability manifests are
ed25519-attested ([SMCP](/docs/platform/smcp-attestation)).

Machine-readable API spec: [Swagger UI](/api/docs) · `/swagger.json`.


---

<!-- Reference · Errors · https://klaw-voice.netlify.app/docs/reference/errors -->

# Errors

Every REST error is a JSON body with a single `error` string (some responses add a
`hint`):

```json
{ "error": "Agent not found" }
```

## Status conventions

| Status | Meaning | Typical causes |
| --- | --- | --- |
| `400` | Invalid request | Missing/malformed fields, bad JSON, invalid E.164 |
| `401` | Unauthorized | Missing/invalid Bearer token or API key |
| `403` | Forbidden | Signature verification failed, out-of-scope key |
| `404` | Not found | Wrong id, or the resource belongs to another account |
| `409` | Conflict | Number already assigned to another agent |
| `429` | Rate limited | Includes a `Retry-After` header (seconds) |
| `502` | Upstream failure | Telephony or TTS provider error — safe to retry |
| `503` | Not configured | A capability's provider isn't set up on this deployment |

## Retry guidance

- `429` — wait `Retry-After` seconds, then retry.
- `502` — retry with backoff; use `Idempotency-Key` on calls and
  `idempotency_key` on messages so retries never double-dial or double-text.
- `409` on numbers — release the number from its current agent first.

## MCP errors

The MCP endpoint returns JSON-RPC 2.0 error objects (`{"jsonrpc", "id",
"error": {"code", "message"}}`) with HTTP 200, per protocol convention. Auth failures
surface as JSON-RPC errors, not HTTP 401s.


---

<!-- Reference · Rate limits · https://klaw-voice.netlify.app/docs/reference/rate-limits -->

# Rate limits

Limits exist where an operation costs real money or touches a real phone. All limits
return `429` with a `Retry-After` header.

| Scope | Limit |
| --- | --- |
| v1 API requests | 100/minute per API key |
| Outbound calls | 5 concurrent · 50/hour per account |
| Quickstart agent creation | 10/hour per account |
| Test calls (`test-call`) | 5/day per account |
| Number purchases | 5/hour per account |
| Voice previews | 40/minute per account |
| Event streams (SSE) | 6 concurrent per account |
| Signup | 10/hour per IP |

## Design notes

- Session (dashboard) traffic isn't counted against the per-key API limit.
- Webhook deliveries time out after 4 seconds — respond `2xx` fast and process async.
- Current usage and the published limits are available programmatically:
  `GET /api/v1/usage?days=30`.

If a limit blocks a legitimate workload, see [Support](/docs/reference/support).


---

<!-- Reference · Support · https://klaw-voice.netlify.app/docs/reference/support -->

# Support

## Self-serve

- [Quickstart](/docs/get-started/quickstart) and the [API reference](/docs/api/auth)
  cover the common paths.
- Machine-readable spec: [Swagger UI](/api/docs) · `/swagger.json`.
- Agent-readable surfaces: [/skills.md](/skills.md) · [/llms.txt](/llms.txt) ·
  [/llms-full.txt](/llms-full.txt).
- Check your usage and limits: `GET /api/v1/usage` or the dashboard **Reporting** page.

## Dashboards

The [dashboard](/dashboard) includes live call monitoring (with human take-over),
call history with transcripts, lead capture, campaigns, WhatsApp inbox, and API key
management under **Settings**.

## Contact

Reach the team from your dashboard account. Include the `X-Klaw-Delivery` id when
reporting webhook issues and the `call_id` for call issues — both make investigations
much faster.


---

<!-- API reference · Auth · https://klaw-voice.netlify.app/docs/api/auth -->

# Auth API

Base URL `https://klaw-voice.netlify.app`. Full auth model: [Authentication](/docs/get-started/authentication).

| Endpoint | Purpose |
| --- | --- |
| `POST /api/auth/signup` | Create account → `{token, user}` |
| `POST /api/auth/login` | Sign in → `{token, user}` |
| `GET /api/auth/me` | Current profile |
| `POST /api/auth/api-key` | Mint/rotate `klw_` key (raw key returned once) |
| `DELETE /api/auth/api-key` | Revoke the key |
| `POST /api/v1/events/stream-token` | 120s `klwst_` token for SSE URLs |

## POST /api/auth/signup

Body: `email`, `name`, `password` (min 8 chars); optional `phone`, `plan`.
Throttled per IP (10/hour). Returns `201 {token, user}`.

## POST /api/auth/api-key

Auth required. No body. Returns the raw key once; storing only its hash means it can
never be re-shown — rotate by POSTing again. The dashboard shows a `klw_…last8`
preview under Settings.


---

<!-- API reference · Agents · https://klaw-voice.netlify.app/docs/api/agents -->

# Agents API

| Endpoint | Purpose |
| --- | --- |
| `POST /api/agents/quickstart` | One call: preset persona + voice + number |
| `POST /api/v1/agents` | Create field-by-field |
| `GET /api/v1/agents` | List agents |
| `GET /api/agents/{id}` | Get one |
| `PATCH /api/agents/{id}` | Update (playbook, voice, escalation, …) |
| `DELETE /api/agents/{id}` | Delete |
| `POST /api/v1/agents/{id}/knowledge-base` | Attach knowledge (≤100KB text) |
| `POST /api/v1/agents/{id}/phone-number` | Attach/purchase a number |
| `POST /api/agents/{id}/test-call` | Agent calls you (NANP, 5/day) |

## POST /api/agents/quickstart

Body: `preset` (`receptionist` · `customer_support` · `sales_associate` · `custom`) —
required. Optional: `business_name` (≤120), `instructions` (≤4000, replaces the preset
playbook), `agent_name` (≤80), `first_message` (≤300), `voice_id` (ElevenLabs id),
`with_number` (bool), `area_code` (3 digits). 10/hour.

Returns `201 {agent, phone_number, number_error}` — the agent always exists; a number
failure is reported, not rolled back.

## POST /api/v1/agents

Body: `name`; `system_prompt` or auto-built from `description`/`objective`/`knowledge`;
`first_message`; `voice_id`; `persona_type`, `tone`, `speech_style`, `goal`,
`category`; `webhook_url` (per-agent call.started notification), `escalation_phone`,
`sms_followup_enabled`, `missed_call_sms_enabled`. Returns `201 {agent}` with
credentials stripped.

## PATCH /api/agents/{id}

Accepts any editable field, including `system_prompt`, `first_message`,
`elevenlabs_voice_id`, `language`, escalation settings, and per-agent Twilio
credentials for BYO accounts.


---

<!-- API reference · Numbers · https://klaw-voice.netlify.app/docs/api/numbers -->

# Numbers API

A number is addressed by its owning agent: `number.id == agent.id`.
Guide: [Phone numbers](/docs/platform/phone-numbers).

| Endpoint | Purpose |
| --- | --- |
| `GET /api/twilio/numbers/available?area_code=NNN` | Search purchasable numbers |
| `GET /api/v1/numbers` | List your numbers |
| `POST /api/v1/numbers` | Provision (creates minimal agent if no `agent_id`) |
| `GET /api/v1/numbers/{id}` | Get one |
| `PATCH /api/v1/numbers/{id}` | `nickname`, `inbound_instruction` |
| `DELETE /api/v1/numbers/{id}` | Release at Twilio + detach |
| `POST /api/twilio/numbers/purchase` | Attach an exact number to an agent |

## POST /api/v1/numbers

Body: `area_code` **or** `phone_number`; optional `agent_id`, `nickname`,
`inbound_instruction`. Voice/SMS/status webhooks are configured during purchase.
Failures roll back a just-created minimal agent. Caps: 5 purchases/hour.

## Errors worth handling

`409` — number already assigned to another agent. `404` — no numbers available in
that area code. `502` — carrier-side failure; pick another number and retry.


---

<!-- API reference · Calls · https://klaw-voice.netlify.app/docs/api/calls -->

# Calls API

Guide: [Place a call](/docs/capabilities/place-a-call).

| Endpoint | Purpose |
| --- | --- |
| `POST /api/v1/calls` | Place an outbound AI call |
| `GET /api/v1/calls` | List calls (`agent_id`, `status`, `limit` ≤200) |
| `GET /api/v1/calls/{id}` | Full record: status, transcript, summary, sentiment |
| `GET /api/v1/calls/{id}/transcript` | Transcript only |
| `POST /api/agents/{id}/test-call` | The agent calls you |

## POST /api/v1/calls

Body: `agent_id` (required), `to` (required, E.164), `objective`, `metadata` (≤8KB,
echoed on events), `callback_url`, `source`. Header `Idempotency-Key` deduplicates
retries. Caps: 5 concurrent, 50/hour.

Returns `201 {call_id, call_sid, status, polling_url, transcript_url}`.

## Call lifecycle

`initiated → ringing → in-progress → completed | failed | busy | no-answer | canceled`

Transcripts append turn-by-turn while the call is live; summary/sentiment/intent land
shortly after hangup (and fire `call.completed`). Prefer webhooks over polling for
fleet-scale workloads.


---

<!-- API reference · Messages · https://klaw-voice.netlify.app/docs/api/messages -->

# Messages API

Guides: [Send a message](/docs/capabilities/send-a-message) ·
[Receive a message](/docs/capabilities/receive-a-message).

| Endpoint | Purpose |
| --- | --- |
| `POST /api/v1/messages` | Send an SMS from a number you own |
| `GET /api/v1/messages` | List messages (`direction`, `limit`) |

## POST /api/v1/messages

Body: `to` (required, E.164), `body` (required, ≤1600 chars), `from` or
`from_number_id` (optional when you own one number), `idempotency_key`.

Returns `201 {id, status, provider_sid, to, from}` and emits `message.sent`.

## Inbound

Inbound SMS/WhatsApp are answered by the owning agent and emitted as
`message.received` events — consume them via
[webhooks](/docs/api/webhooks) or [events](/docs/api/events).


---

<!-- API reference · Events · https://klaw-voice.netlify.app/docs/api/events -->

# Events API

Guide with types table: [Events](/docs/platform/events).

| Endpoint | Purpose |
| --- | --- |
| `GET /api/v1/events` | Cursor poll: `type`, `since`, `limit` → `{events, cursor}` |
| `POST /api/v1/events/wait` | Long-poll: `{types[], timeout_ms ≤55000, since}` |
| `GET /api/v1/events/stream` | SSE stream (`?token=klwst_…`, ~50s runs, ≤6 concurrent) |
| `POST /api/v1/events/stream-token` | Mint the 120s stream token |

## POST /api/v1/events/wait

Blocks until a matching event arrives or the timeout passes. Returns `{event}` or
`{event: null, timed_out: true}` — loop for continuous consumption. Default timeout
25s, max 55s. This powers the MCP `wait_for_event` tool.

## Event envelope

Events carry `id`, `type`, `created_at`, and a type-specific payload (call ids,
numbers, message bodies, metadata you attached to calls). The same envelope is
delivered on webhooks, SSE frames, and poll responses.


---

<!-- API reference · Webhooks · https://klaw-voice.netlify.app/docs/api/webhooks -->

# Webhooks API

Guide with signature verification code: [Webhooks](/docs/platform/webhooks).

| Endpoint | Purpose |
| --- | --- |
| `GET /api/v1/webhooks` | List subscriptions |
| `POST /api/v1/webhooks` | Create — returns `whsec_` secret once |
| `GET /api/v1/webhooks/{id}` | Get one (incl. `last_status`, `last_delivery_at`) |
| `DELETE /api/v1/webhooks/{id}` | Delete |
| `POST /api/v1/webhooks/{id}/secret` | Re-reveal the signing secret |
| `POST /api/v1/webhooks/{id}/ping` | Fire a `webhook.ping` test event |

## POST /api/v1/webhooks

Body: `url` (HTTPS only; private and internal addresses rejected), `events`
(array of [event types](/docs/platform/events) or `["*"]`), `description`.

## Delivery contract

Headers `X-Klaw-Signature` (`sha256=` HMAC of the raw body), `X-Klaw-Event`,
`X-Klaw-Delivery`. 4-second timeout per attempt; delivery status is recorded on the
subscription. Verify with a timing-safe HMAC comparison.


---

<!-- API reference · Usage · https://klaw-voice.netlify.app/docs/api/usage -->

# Usage API

| Endpoint | Purpose |
| --- | --- |
| `GET /api/v1/usage?days=30` | Aggregates + published limits |

Returns counts for calls, messages, numbers, and events over the window (`days` ≤365),
plus the platform `limits` block (concurrent calls, hourly calls, per-minute API rate)
so clients can self-throttle instead of hitting `429`s.

The MCP `get_usage` tool returns the same shape. Machine-readable OpenAPI spec:
[Swagger UI](/api/docs) · `/swagger.json`.


---

<!-- Whitepaper · https://klaw-voice.netlify.app/whitepaper -->

# Voice for the Agentic Web

**How KlawVoice gives AI agents a trustworthy phone presence.**

## Executive summary

AI agents can read, write, plan, and transact — but the moment a task touches a phone
call, most of them stall. Business still happens on the phone: appointments are booked,
leads are qualified, problems get escalated, and verification codes arrive by SMS.
KlawVoice closes that gap with three things: a **persona-on-a-number** model that makes
"an agent with a phone" a single provisionable object; a **latency-engineered voice
loop** that turns raw telephony into natural conversation; and a **signed capability
layer (SMCP)** so that other agents and platforms can verify what a KlawVoice agent
offers before trusting it. This paper explains each layer, the invariants we hold, and
where the platform goes next.

## Part I — Why agents need a phone

### The phone is where the money is

For most small and mid-size businesses the phone is still the highest-intent channel
that exists. A missed call is usually a lost customer, and after-hours coverage is an
unsolved staffing problem. Meanwhile, agents that *could* cover those calls are locked
out: they have no number, no voice, and no way to prove to anyone what they are.

### Raw telephony is an assembly project

The building blocks have existed for years — number inventories, programmable call
control, speech recognition, neural TTS, large language models. What hasn't existed is
the assembled object. A team that wants an AI receptionist must stitch together five
vendors, design a turn-taking loop, keep latency under conversational thresholds,
persist transcripts, handle consent, and wire eventing — before writing a single line
of the persona they actually wanted. KlawVoice's position is that **the assembled
object is the product**: one call creates a persona, attaches a voice, provisions a
number, and wires every webhook the number needs to function.

### The missing trust layer

As agents begin transacting with other agents, a new question appears that human-era
infrastructure never had to answer: *how does one agent verify what another agent is
offering?* A phone number proves nothing. An API endpoint proves nothing. We believe
capability declarations must be **machine-readable, canonical, and cryptographically
signed** — and that this belongs at the platform layer, not bolted on per-integration.

## Part II — Architecture

### The persona-on-a-number model

KlawVoice's core object is the **agent**: a persona (name, playbook, greeting), a
voice, optional knowledge, and optionally a phone number. Two invariants keep the
model simple enough to trust:

- **One number, one agent.** Inbound routing is never ambiguous; attaching an owned
  number elsewhere is a hard conflict, not a silent reassignment.
- **A number works the moment it exists.** Voice, SMS, and status webhooks are
  configured inside the provisioning transaction, not as a follow-up step.

Personas are defined in plain language. A harness can pass `instructions` — a system
prompt for how calls should be handled — plus a name, a greeting, and a voice id, and
receive a working phone agent in one request.

### One-call provisioning

`POST /api/agents/quickstart` accepts a preset, optional persona overrides, an
optional voice, and an optional `with_number` flag. Number provisioning is
best-effort by design: if the carrier hiccups, the agent still exists and the error is
reported, because an agent without a number is a valid state and a retry is cheap.
The same philosophy runs through the MCP surface — fourteen tools that wrap the same
REST endpoints with the same limits, so there is exactly one behavior to audit.

### The voice loop

The default pipeline is turn-based and engineered around conversational latency
budgets rather than raw streaming:

1. Carrier webhooks are **signature-verified** before any agent logic runs.
2. The greeting is spoken with neural TTS, with a plain-speech fallback so a TTS
   outage degrades voice quality instead of dropping calls.
3. Caller speech arrives as text; knowledge retrieval runs under a sub-second budget
   and is skipped entirely for short acknowledgements.
4. Reply generation **races multiple LLM providers** in parallel with a quality
   fallback, takes the first acceptable answer, and enforces a hard ceiling so the
   caller never waits in silence.
5. Replies are capped at one to two sentences — pacing that keeps the conversation
   human — and every turn's time-to-first-token is recorded.

Transcripts append atomically to the call record as the call runs, so a supervisor —
human or agent — can watch live. Post-call, a status callback computes summary,
sentiment, and intent, and fires the corresponding events.

For workloads that justify it, an agent can opt into a **realtime media bridge**
(per-agent `runpod_url`): same personas and transcripts, streaming latency, at the
cost of dedicated infrastructure. The turn-based loop remains the zero-ops default.

### The event backbone

Everything observable is an event: call lifecycle, transcripts, insights, human
take-over, inbound and outbound messages. Events are persisted once and delivered
three ways — HMAC-signed webhooks (`X-Klaw-Signature`, SSRF-guarded, 4-second
timeout), server-sent event streams gated by short-lived tokens, and cursor/long-poll
endpoints for agents that just want to block until something happens. One event
stream, three consumption grammars, no privileged channel.

### The SMCP trust layer

KlawVoice implements SMCP v0.1 as an agent-host node. The design goals:

- **Canonical shapes.** Every published declaration is serialized with sorted keys and
  no volatile fields, so identical capabilities always hash identically.
- **Secret-free by construction.** No manifest, card, or discovery document may carry
  keys, webhook paths, or private material — enforced by a conformance scan, not by
  convention.
- **Signed fingerprints.** The host computes a SHA-256 fingerprint over its canonical
  capability surface and signs it with an ed25519 key. Verifiers pin the key on first
  use and re-verify on every fetch; any silent capability change surfaces as drift.
- **Contracts, not vibes.** Per-agent manifests declare task contracts with fixed
  settlement invariants — funds held, a 48-hour review window, signed callbacks — so
  a counterparty agent knows the rules before the first request.
- **Continuous conformance.** A test harness validates version negotiation, canonical
  determinism, sign/verify round-trips (including tamper failure), and cross-checks
  the published tool list against the live MCP server so documentation cannot drift
  from behavior.

Discovery is boring on purpose: three `.well-known` documents and a per-agent
manifest endpoint, all public, all CORS-open, all verifiable offline.

### Safety and consent posture

A phone platform for agents has to be conservative where the phone network meets real
people. The posture, concretely: carrier webhooks are signature-verified; outbound
calling is capped (5 concurrent, 50/hour) and test calls are capped harder; number
purchases are rate-limited because they bill real money; API keys are stored only as
hashes and shown once; user webhook URLs are HTTPS-only and SSRF-checked; and the
agent-facing setup instructions require explicit human consent before any call is
placed. Agents are also told the prices — honesty is part of the interface.

## Part III — Roadmap

- **Realtime streaming as default.** Graduating the media bridge from opt-in to the
  standard path as economics allow, keeping the turn-based loop as the zero-ops floor.
- **Voice in the browser.** The same personas answering web visitors without a phone
  leg, sharing playbooks, knowledge, and transcripts with the phone agent.
- **Deeper messaging.** First-class v1 WhatsApp sending alongside SMS.
- **Marketplace federation.** KlawVoice agents are publishable to the DiviDen
  marketplace today; the roadmap extends signed manifests and settlement contracts to
  cross-platform agent-to-agent hiring.
- **SMCP evolution.** Wider attestation coverage, richer capability schemas, and
  third-party verifier tooling as the standard matures.

## A note to builders

Everything in this paper is operable today: the [quickstart](/docs/get-started/quickstart)
takes five requests, the [MCP server](/docs/platform/mcp-server) speaks to any client,
and the machine-readable surfaces ([/skills.md](/skills.md), [/llms.txt](/llms.txt),
[/llms-full.txt](/llms-full.txt)) are built so your agent can read this platform the
way you just did. Give your agent a phone number and a voice — and make it provable.
