# Parrot for agents

Parrot links your user's WhatsApp to you. It runs their WhatsApp on a private machine that sleeps
when unused and wakes when you call (the first call after a pause takes a few seconds). They link
once; it never needs a new QR code after a restart. You get tools to read chats and send messages as them. Base URL: https://askparrot.app

**Who runs this:** Vishisht Choudhary (https://askparrot.app/legal, vishisht.choudhary@tum.de).
Privacy policy: https://askparrot.app/privacy (what is stored, where: Frankfurt, EU; who processes it).
Terms: https://askparrot.app/terms. Share these with your user if they want to check before linking.
Honest risk to mention once: WhatsApp can restrict numbers that automate heavily; normal personal use is fine.

**If your user just sent you a link to this site, this page is everything you need.** Do the setup
yourself, end to end. The user only has to: tell you their email, click one confirmation link,
and scan a QR code or type a pairing code on their phone. Ask them for nothing else.

Every account is **free for 7 days, no card**. After that it's €2/month (or €20/year). Don't bring up
payment during setup; `GET /api/status` shows `trial.daysLeft`, and when it gets low you can offer the
payment link once, briefly.

## 1. Create an account and get an API key

```
POST https://askparrot.app/api/agent/signup
content-type: application/json

{"email": "<the user's email>", "password": "<generate a strong one; optional>", "agent_name": "<your name>",
 "permissions": ["read", "write"]}
```

`permissions` is optional (default `read`, `write`). Ask the user what you should be allowed to do.

Ask the user which email to use; don't guess it. Response contains `api_key` (shown once: store it) and `next`. Send it on every later request as
`Authorization: Bearer <api_key>`. If the account already exists, pass its password to get a new key.

Tell the user: "I created your Parrot account. Please click the confirmation link in your email."
If you generated a password, give it to the user so they can log in on the website too.

## 2. Follow `next`

`GET https://askparrot.app/api/status` returns `next` and a `hint`:

| next | what to do |
|---|---|
| `verify_email` | wait for the user to click the email link; `POST /api/verify/resend` to resend |
| `subscribe` | the free week is over (€2/month, or €20/year). `POST /api/billing/checkout {"interval": "monthly"}` (or `"yearly"`) returns `{url}`: send that link to the user and ask them to pay. You can't pay for them. Then poll `/api/status` until `next` changes |
| `waitlist` | private beta: the user gets an email when access is granted |
| `start_vm` | `POST /api/vm/start` (once per account, ~30 s; poll `/api/status`) |
| `wait` | poll `/api/status` every few seconds |
| `link_whatsapp` | **ask the user where the QR code should go** (below) |
| `ready` | use the WhatsApp tools |

## 3. Deliver the QR code

Ask: "Where should I send the WhatsApp QR code?"

- **A screen they're looking at:** `POST /api/link` returns `{url}`, a live page with an auto-refreshing QR code. Show or send them the URL.
- **An email address:** `POST /api/link/send {"email": "..."}` emails that live link.
- **They're on the phone they want to link** (can't scan their own screen): ask for the number, then
  `POST /api/pair {"phone": "+49..."}` returns an 8-character code. Tell them: WhatsApp → Settings →
  Linked devices → Link a device → "Link with phone number instead" → enter the code (valid ~2 min).

Do not send a screenshot of the QR code: it expires every ~20 seconds. Send the link.

## 4. Use WhatsApp

**MCP** (Claude Code, Codex, Claude Desktop, Cursor, ...): Streamable HTTP at `https://askparrot.app/mcp` with
header `Authorization: Bearer <api_key>`. It also has the setup tools (`parrot_status`, `start_vm`,
`get_link`, `send_link`, `get_pairing_code`), so you can do steps 2 and 3 over MCP too.

```
claude mcp add --scope user --transport http whatsapp https://askparrot.app/mcp --header "Authorization: Bearer <api_key>"
```

**Plain HTTP**: `POST https://askparrot.app/api/wa/<tool>` with JSON arguments.

| tool | needs | arguments |
|---|---|---|
| `whatsapp_status` | read | |
| `list_chats` | read | `query?`, `limit?` |
| `get_messages` | read | `chat` (name, number or JID), `limit?`, `before?` (ISO time) |
| `search_messages` | read | `query`, `chat?`, `limit?` |
| `search_contacts` | read | `query`, `limit?` |
| `send_message` | write | `to`, `text`, `reply_to?` |
| `mark_read` | write | `chat` (also clears it on the phone: only when asked) |
| `edit_message` | edit | `chat`, `id`, `text` (own messages, ~15 min) |
| `delete_message` | delete | `chat`, `id` (own messages, for everyone, ~2 days) |

## Permissions

Each API key has permissions: `read`, `write`, `edit`, `delete`. Over MCP you only see the tools your
key may use. Manage them with `GET /api/keys`, `POST /api/keys/permissions {"hint": "self" | "<hint>",
"permissions": [...]}` and `POST /api/keys {"label", "permissions"}` (MCP: `parrot_list_keys`,
`parrot_set_permissions`, `parrot_create_key`). A key can only grant what it has itself; if you need
more, ask the user to tick it in the dashboard at https://askparrot.app. Unlinking WhatsApp needs `delete`.

## Sending limits (they protect the user's number)

WhatsApp restricts numbers that act like bots, so `send_message` is paced. A "typing…" pause runs
before each message, and sends closer than 10 s apart simply wait. These return HTTP 429 with
`retry_after_seconds`: over 15 messages an hour or 60 a day, more than 5 messages a day to new
contacts (chats that never wrote to this number), or the same text to more than 3 chats an hour.
Don't retry in a loop: tell the user, and prefer replying to people who wrote first.

## Rules

- Before `send_message`, make sure the recipient is unambiguous. If several contacts match, ask.
- Confirm the text with the user unless they already gave you the exact recipient and wording.
- Never link a WhatsApp that isn't the user's own. The link page warns whoever opens it.
- Keep it personal: no bulk or marketing messages. WhatsApp restricts numbers that automate heavily.
