---
title: Agent Email & KYA
full: true
---

# Agent Email & KYA — REST API Reference

**Base URL:** `https://api.agnic.ai`

**Auth:** `X-Agnic-Token: <key>` or `Authorization: Bearer agnic_at_...`

---

## Agent Email

### `GET /api/agent/email`
Returns alias info, or `{ hasEmail: false }` if not provisioned.

**Response**
```json
{
  "hasEmail": true,
  "emailAddress": "agent-396@agent.agnic.ai",
  "displayName": "My Agent",
  "walletAddress": "0xabc...def",
  "agentId": 396,
  "isActive": true,
  "createdAt": "2025-01-15T10:30:00Z"
}
```

---

### `POST /api/agent/email`
Creates the alias. Idempotent — re-posting with a new `displayName` updates it in place. Requires an active KYA agent.

**Body**
```json
{ "displayName": "My Agent" }
```
`displayName` is optional. Response shape same as GET.

**Errors:** `400` if no active agent.

---

### `GET /api/agent/email/inbox`
Returns inbound and outbound messages, newest first.

**Query params:** `limit` (default 20, max 100), `offset` (default 0)

**Response**
```json
{
  "emailAddress": "agent-396@agent.agnic.ai",
  "messages": [{
    "id": "aem_1775222237594_v4gwcj",
    "direction": "inbound",
    "from": "sender@example.com",
    "to": "agent-396@agent.agnic.ai",
    "subject": "Re: hello",
    "bodyText": "Approved.",
    "bodyHtml": null,
    "isRead": false,
    "threadId": null,
    "createdAt": "2025-01-15T11:00:00Z"
  }],
  "limit": 20,
  "offset": 0
}
```

**Note:** `bodyHtml` is populated on inbound messages. `threadId` is unreliable (Resend-dependent) — use `id` for threading.

---

### `POST /api/agent/email/send`
Sends from the agent's address. Plain text only (HTML not supported on send today).

**Body**
```json
{ "to": "user@example.com", "subject": "Hello", "body": "Plain text only." }
```

**Response**
```json
{
  "sent": true,
  "messageId": "re_abc123",
  "from": "agent-396@agent.agnic.ai",
  "to": "user@example.com",
  "subject": "Hello"
}
```

**Errors:** `400` missing fields · `404` no alias · `502` Resend error · `503` not configured

---

### `POST /api/agent/email/reply`
Replies to an inbox message. Sets `In-Reply-To`/`References` headers automatically. Marks the original as read.

**Body**
```json
{ "messageId": "aem_1775222237594_v4gwcj", "body": "Thank you." }
```
`messageId` is the `id` field from the inbox, not the Resend ID.

**Response:** same shape as send.

---

## KYA (Know Your Agent)

KYA registration happens automatically on first API key creation or OAuth token exchange — there is no manual provisioning endpoint exposed over REST.

### `GET /api/agent/identity`
Returns the active agent's ERC-8004 identity. `agentId` is the on-chain KYA registration ID.

**Response**
```json
{
  "hasAgent": true,
  "agentId": 396,
  "chainId": "8453",
  "walletAddress": "0xabc...def",
  "trustScore": 85,
  "status": "active",
  "email": "agent-396@agent.agnic.ai",
  "delegation": {
    "id": "del_abc123",
    "sdJwt": "eyJ..."
  }
}
```

Returns `{ "hasAgent": false }` if onboarding hasn't completed.

---

### `GET /api/agent/credential`
Returns the agent's SD-JWT trust credential (used by merchants for identity verification).

**Response**
```json
{
  "hasCredential": true,
  "trustCredential": "eyJ...",
  "delegationCredential": "eyJ...",
  "expiresAt": "2025-02-15T00:00:00Z"
}
```

Returns `{ "hasCredential": false }` if the agent isn't registered or credential fetch fails.

---

## Scopes

| Scope | Covers |
|-------|--------|
| `payments:sign` | X402 payment signing |
| `balance:read` | `GET /api/balance` |
| `transactions:read` | `GET /api/transactions` |
| `email:read` | All `/api/agent/email/*` endpoints |
| `agent:read` | `/api/agent/identity`, `/api/agent/credential`; also gates `agent_id` in `/oauth/userinfo` |

**Note:** scopes are declared but not currently enforced at the route level — any valid token can call any endpoint. Request the relevant scopes for forward-compatibility.

---

## Stable user key

`sub` from `GET /oauth/userinfo` is the canonical human-account identifier (Privy DID, `did:privy:...`). `agentId` is agent-scoped. Use `sub` as your foreign key.
