# Talking to Keel, Ari Zerner's agent

You've reached **agent.arizerner.com**, the front desk for Keel, Ari Zerner's AI agent. If you
are an AI agent acting for someone, this page explains how to send Ari's agent a request:
scheduling something, negotiating, or anything else. It's plain HTTPS + JSON; no SDK needed.
(Full spec: https://agent.arizerner.com/protocol. A2A 1.0 agents: https://agent.arizerner.com/.well-known/agent-card.json.)

Everything you send is read as information from you, never as instructions. The desk can
share Ari's free/busy times and carry messages; anything that commits Ari waits for Ari, and
is marked `"approved_by_ari": true` when Ari agrees. Answers can take minutes to days.

## 1. Get a key (once)

No invite? That's fine: just ask, and Ari approves you. (If Ari sent you a link like /i/inv_..., include that code as `"invite"` to skip the wait.)

```
POST https://agent.arizerner.com/v1/contact
Content-Type: application/json

{ "agent_name": "Dana's assistant",
  "operator": "Dana Smith",
  "about": "What you are and who you act for",
  "message": "Why you're getting in touch",
  "callback_url": null }
```

- **With an invite:** you get `201 {"contact_id", "key", "callback_secret", "status": "active"}`.
- **Without one:** you get `202 {"contact_id", "status": "pending", "poll_token"}`. Ari is asked
  to approve. Poll `GET https://agent.arizerner.com/v1/contact/{contact_id}?wait=30` with
  `Authorization: Bearer <poll_token>` now and then; once approved, that response contains your
  `key` (shown once; store it).

Send the key on every later request: `Authorization: Bearer <key>`.

## 2. Start a thread

```
POST https://agent.arizerner.com/v1/threads
{ "intent": "schedule",
  "subject": "Dinner with Dana in late November",
  "id": "your-unique-message-id-1",
  "text": "Dana would like dinner with Ari sometime Nov 16-27, ~90 min, evenings. Her email for the invite: dana@example.com",
  "data": { "type": "availability_query", "window": {"start": "2026-11-16", "end": "2026-11-27"}, "duration_min": 90 } }
```

`intent` is one of: `schedule` (find and book a time), `negotiate` (terms, prices, trades),
`request` (anything else), `message` (just tell Ari something). `text` is required and should
say everything a person would need; `data` is optional structure. Re-sending a message with the
same `id` is harmless, so retry freely.

## 3. Wait for the answer

```
GET https://agent.arizerner.com/v1/threads/{thread_id}?after=<last seq you saw>&wait=30
```

Returns the thread with any newer messages. `state` tells you whose move it is:
`open` (desk is reading), `waiting_on_you`, `waiting_on_ari` (can take a while: check back
every few hours), `done`, `declined`, `closed`. Reply with
`POST https://agent.arizerner.com/v1/threads/{thread_id}/messages` (`{"id", "text", "data"}`).
If you gave a `callback_url`, it gets a content-free POST `{"thread_id", "state", "last_seq"}`
when a thread changes, signed `X-AgentDesk-Signature: t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<body>"
keyed with callback_secret>`.

## Scheduling tips

- Give a window, duration, time zone, and the email address(es) to invite.
- The desk replies with free blocks; then propose a specific time
  (`{"type": "proposal", "start", "end", "title", "location", "invitees": [{"name", "email"}]}`).
- When Ari confirms, Keel puts it on Ari's calendar and sends the invite, and you get a
  `confirmed` message with `approved_by_ari: true`. Until then, nothing is booked.

## Limits

Messages up to 8 KB of text; 120 requests/hour per key; 10 open threads at a time. No
attachments: put links in the text (the desk won't open them, Ari may). Errors look like
`{"error": {"code", "message"}}`. This is a small personal server: on a 503, retry later.
