# AGENTS.md - PyAI website guidance

Use this guide when building against or editing the PyAI website.

## Positioning

- PyAI is the OpenAI-compatible voice AI stack for production phone agents.
- Lead with buyer outcomes: lower all-in minute cost, lower latency, faster
  migration, safer production operations, and transparent billing.
- Treat Hear and Speak as primitives and on-ramps. Lead public GTM with Omni API,
  Omni Agents, Trace, and Cast.
- Keep competitor copy respectful and specific: compare cost, latency,
  architecture, and migration effort.

## Developer Links

- API docs: https://api.pyai.com/docs
- OpenAPI spec: https://api.pyai.com/openapi.json
- Agent index: https://api.pyai.com/llms.txt
- Website llms.txt: https://pyai.com/llms.txt

## Billing Language

- AI products bill per second by default and round once at the invoice line.
- Managed telephony is the explicit exception: connected minutes bill on a
  1-minute pulse because carrier economics are different.
- Do not describe PyAI as merely cheap. The positioning is honest production
  voice infrastructure at the real cost curve.

## Product Names

Use customer-facing product names only: Hear, Speak, Omni, Agents, Trace, Recap,
Cue, Telephony, and Cast.
# Building against PyAI - a guide for AI agents

PyAI is a telephony-grade voice AI platform. This file tells coding agents how to
integrate correctly. The machine-readable source of truth is the OpenAPI spec at
`https://api.pyai.com/openapi.json` - fetch it; never invent endpoints.

## Base URL & auth
- REST base: `https://api.pyai.com/v1`
- Send the key as a bearer token: `Authorization: Bearer pyai_live_...`
  (`x-api-key: <key>` is an accepted alias).
- Sandbox keys (`pyai_test_...`) are instant, free, and hard-daily-capped - use
  them for prototypes and evals.
- Treat keys as opaque strings (<=512 chars). Never parse, split, decode, or log
  them. They work on every surface the instant they are created.

## Prefer the official SDKs
- TypeScript/JS: `npm install @pyai/sdk` then `import PyAI from "@pyai/sdk"`.
- Python: `pip install pyai-sdk` then `from pyai import PyAI`.
Both wrap auth, retries, idempotency, typed errors, and realtime. Only hand-roll
HTTP if no SDK exists for your language.

## Core endpoints
| Task | Endpoint | Scope |
|------|----------|-------|
| Text-to-speech (Speak) | `POST /v1/audio/speech` | `voice:synthesize` |
| Speech-to-text (Hear) | `POST /v1/audio/transcriptions` | `hear:transcribe` |
| Async batch transcription | `POST/GET /v1/transcription/jobs` | `hear:transcribe` + `transcribe:jobs` |
| Voice / model catalog | `GET /v1/voices`, `GET /v1/models` | any active key |
| Realtime agent (Omni) | `wss://api.pyai.com/v1/omni?agent_id=<id>&format=pcm16&rate=24000` | `omni:session` |

OpenAI-compatible: you can point an OpenAI client at `base_url=https://api.pyai.com/v1`
for transcription and speech and keep your existing code.

## Realtime (Omni)
- Native: `wss://api.pyai.com/v1/omni?agent_id=<id>&format=pcm16&rate=24000`.
- OpenAI-realtime-compatible alias: `wss://api.pyai.com/v1/realtime?model=pyai-omni-realtime&agent_id=<id>`.
- Authenticate on the upgrade with the subprotocol `pyai-key.<key>` (works in the
  browser), or append `?api_key=<key>` for server-side clients.
- `agent_id` is an opaque label authorized by your org.

## Errors - branch on the stable `code`
Data-plane errors use the OpenAI envelope: `{ "error": { "code", "message", "type" } }`.
React to: `402 credit_exhausted` (add credit or use a test key - not a bug),
`429 rate_limit_exceeded` / `concurrency_limit_exceeded` (back off, honor
`Retry-After`), `403 forbidden` (key lacks the scope). Don't retry 4xx except 429.

## Don'ts
- Don't parse or persist key internals; read keys from env vars.
- Don't hardcode deprecated endpoints - fetch the OpenAPI spec.
- Don't assume one error shape; handle the documented codes.

Get a free key at https://console.pyai.com and read the full docs at
https://api.pyai.com/docs.
