# Quickstart

> Create a webhook watch, test your receiver, read its events and delete it with five curl commands.

Percia watches a camera or video URL and calls your webhook each time a plain-language goal becomes true. Replace `$BASE` with your Percia host (for local dev, `http://localhost:5173`).

Authenticate with an API key. Sign in to the dashboard once, open **API keys**, create a key with the scopes you need (`watches:read`, `watches:write`, `events:read`; `integrations:read` and `integrations:write` to reach Slack and other services) and copy it: it is shown once. Send it as `Authorization: Bearer pk_live_...`. API-key requests need no Turnstile and no cookie.

| Scope | Allows |
|---|---|
| `watches:read` / `watches:write` | List and read watches, agents and sites / create and change them, test a delivery |
| `watches:delete` | Delete watches, agents, sites and connections, rotate a secret, clear site memory |
| `events:read` | Events, keyframe images, metrics |
| `cameras:read` / `cameras:write` | List phone cameras / add one (returns a pairing link a person scans) and remove one |
| `devices:write` | Register or remove a phone for push alerts (OAuth grant of the Percia Camera app; not offered for API keys in the dashboard) |
| `integrations:read` / `integrations:write` | List connected services / start a connect link for Slack, Discord, Telegram, Home Assistant, IFTTT or a webhook |

A 403 `insufficient_scope` names the missing scope. Account, billing, API key and provider key changes are never available to a key.

```bash
BASE=https://your-percia-host
KEY=pk_live_...   # from the dashboard, API keys page

# 1. Create a webhook watch. The response is the only time you see webhookSecret: save it.
curl -sS -X POST "$BASE/api/watches/owned" -H "Authorization: Bearer $KEY" \
  -H 'content-type: application/json' \
  -d '{"sourceUrl":"rtsp://cam.example.com/stream","goal":"A person is standing at the front door","notify":{"type":"webhook","target":"https://example.com/hooks/percia"}}'

# 2. Send a signed test event to your receiver (no camera needed)
curl -sS -X POST "$BASE/api/watches/$WATCH_ID/test-delivery" -H "Authorization: Bearer $KEY"

# 3. Read it back (the secret is never returned again; you get secretHint, its last 4 characters)
curl -sS "$BASE/api/watches/$WATCH_ID" -H "Authorization: Bearer $KEY"

# 4. Read the decisions it produced, newest first
curl -sS "$BASE/api/watches/$WATCH_ID/events?limit=20" -H "Authorization: Bearer $KEY"

# 5. Delete it when you are done
curl -sS -X DELETE "$BASE/api/watches/$WATCH_ID" -H "Authorization: Bearer $KEY"
```

An MCP client can use the same key at `$BASE/mcp`. It has six tools: `search` (find a route in the OpenAPI document), `execute` (call routes with JavaScript, with your key and scopes), `docs`, `whoami`, `view_image` and `show_link` (show a pairing or connect link as a QR card). `$BASE/mcp/directory` serves the same API as separate `read` (GET), `write` (POST, PUT, PATCH) and `delete` tools with `search_api`, `docs`, `whoami`, `view_image` and `show_link`, for clients and directories that want no catch-all tool. `$BASE/mcp/chatgpt` serves 19 named tools, one fixed operation each (`list_watches`, `create_watch`, `delete_watch`, `list_events`, `connect_destination`, `add_phone_camera`, `get_account` and more), for the ChatGPT app directory; camera addresses come back as scheme and host only. The docs alone are at `$BASE/mcp/docs` with no key (tools `search_docs` and `get_page`). The older one-tool-per-route set (`create_watch`, `list_watches`, `list_events` and so on) is at `$BASE/mcp?tools=all`. Setup for Claude Code, Claude.ai and Cursor: [/coding-agents](/coding-agents).

The create response (HTTP 201) has `id`, `status` (`active`), `displayStatus`, `eventCount`, `secretHint` and, once, `webhookSecret` (`whsec_...`). Use `webhookSecret` to verify every delivery: see [webhooks](/docs/webhooks.md).

Next steps:
- [Writing a goal](/docs/writing-a-goal.md): wording that judges well.
- [Agents](/docs/agents.md) (versioned configs with several concerns and zones), [sites and memory](/docs/sites.md), [evidence and tests](/docs/evidence.md), [phone cameras](/docs/phone-camera.md) and [actions, outputs, keys and usage](/docs/actions.md) (in progress).
- [Limits](/docs/limits.md) and [errors](/docs/errors.md).
- The full route list is the OpenAPI document at `/api/openapi.json`.
- Pause or resume with `PATCH /api/watches/$WATCH_ID` and `{"status":"paused"}` or `{"status":"active"}`. Rotate a lost secret with `POST /api/watches/$WATCH_ID/secret/rotate`.
- No video: when the camera stops sending video, the watch shows `noVideoSince` (and `displayStatus` `attention`). After 60 minutes without video it is paused automatically (`pausedReason` `no_video`) and the owner gets one email. Nothing is judged meanwhile. Resume it with `{"status":"active"}` once the camera is back.
- With a key or MCP (`POST /api/watches/owned`), `notify` may be left out: alerts then email the account owner. Slack and other services are added on top as rules (see Integrations).
- Email watches (`"notify":{"type":"email","target":"you@example.com"}`) need no sign-in: `POST /api/watches` with a Turnstile token, and the manage link arrives by email. Webhook watches always need a signed-in owner.

## Use it from an AI coding agent

Install the Percia skill so your agent follows the webhook rules (verify the HMAC, reject timestamps older than 300 s, dedupe on `Percia-Idempotency-Key`, keep secrets out of front-end code, word goals well):

```bash
npx skills add <owner>/percia-cf --skill percia
```

Cursor reads the same rules from `.cursor/rules/percia.mdc`. The skill source is `skills/percia/SKILL.md`.
