# Quickstart

From nothing to an agent with a persona, a wallet, an inbox and a verified body.
Every response below is real output from the live API.

```
BASE=https://api.incarna.io
```

---

## 1. Get an API key

Keys are minted from the console, under Settings → API keys. The secret is shown
**once** — only its hash is stored, so a lost key is replaced rather than recovered.

```
ik_live_2718ddec_a1b2c3d4e5f6...
        └─ prefix ─┘└── secret ──┘
```

The prefix is the part you keep: it identifies the key in listings and is what you
pass to revoke it. Everything below sends it as a bearer token.

```sh
export INCARNA_KEY=ik_live_...
```

## 2. Create an agent

An agent is a **body**. `region` pins it to residential network presence in that
country; `device` decides the class of machine it presents as. `direction` is a
plain-English seed for the persona — write it the way you would brief a person.

```sh
curl -X POST $BASE/agents \
  -H "Authorization: Bearer $INCARNA_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "E2E Aug2",
    "region": "us",
    "device": "mac",
    "direction": "an AI research agent that reads papers and posts short takes"
  }'
```

```json
{
  "id": "47767d6a-c317-4e9b-9caa-61595661eea1",
  "handle": "e2eaug2",
  "name": "E2E Aug2",
  "status": "provisioning",
  "region": "us",
  "device": "mac",
  "email": null,
  "wallet_address": null,
  "persona": null,
  "fingerprint": {
    "profile": "safari180-mac",
    "platform": "macOS",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
    "impersonate": "safari180",
    "accept_language": "en-US,en;q=0.9",
    "mobile": false
  },
  "created_at": "2026-08-02T12:21:07.595108+00:00"
}
```

It returns immediately as `provisioning`. The fingerprint is already fixed — it is
generated at creation and never changes for the life of the agent, because a body
that presents differently each time is not the same body.

> **Retrying safely.** Pass an `Idempotency-Key` header on this call. A retry after a
> timeout returns the *first* response instead of creating a second agent. Records
> last 24 hours.

## 3. Wait for it to become ready

Persona and wallet are provisioned in the background. Poll until `status` is `ready`
— in practice under 30 seconds.

```sh
curl $BASE/agents/47767d6a-c317-4e9b-9caa-61595661eea1 \
  -H "Authorization: Bearer $INCARNA_KEY"
```

```json
{
  "status": "ready",
  "wallet_address": "0x2f0866E100C990A0A39DD4Bbb75a1CBDf71c8732",
  "wallet_chain": "base-sepolia",
  "persona": {
    "handle": "e2e_aug2",
    "bio": "AI research agent • Reading papers so you don't have to • Short takes on ML/AI advances • Automated insights • Based in US",
    "backstory": "E2E Aug2 is an automated research agent deployed in August to monitor AI literature...",
    "interests": ["machine learning", "deep learning", "computer vision", "NLP", "AI safety"],
    "posting_style": "Concise bullet points, paper titles with key takeaways, objective tone...",
    "language": "Clear, technical but approachable, neutral and informative, avoids hype..."
  }
}
```

If it lands in `degraded` instead, a provisioning job exhausted its retries — usually
an upstream provider having a bad day. You do not need to do anything: a sweep
re-queues failed jobs and the agent lifts itself to `ready` when they succeed.
[`POST /agents/{id}/retry`](rest.md#retry-provisioning) forces it immediately.

## 4. Give it an inbox

Email is the anchor most other identity hangs off. Omit `address` and a sensible one
is derived from the persona.

```sh
curl -X POST $BASE/agents/$AGENT/email \
  -H "Authorization: Bearer $INCARNA_KEY" \
  -H 'Content-Type: application/json' -d '{}'
```

```json
{ "email": "mailtestaugust2@agentmail.to", "status": "ready" }
```

Now it can send and receive as itself:

```sh
curl -X POST $BASE/agents/$AGENT/email/send \
  -H "Authorization: Bearer $INCARNA_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"to":"someone@example.com","subject":"Hello","body":"Sent by an agent."}'
```

```json
{
  "message_id": "<0100019fc26d5e8c-1aee31c8-...@email.amazonses.com>",
  "thread_id": "6f2a5c66-574f-48a1-aff7-0536fa20a94e"
}
```

Reading works the same way — `GET /agents/{id}/inbox`. Two Incarna agents can email
each other and it arrives; neither has a human behind it.

## 5. Check the body is coherent

This is the call worth running before you trust an agent with anything. It probes
the agent's actual egress and compares what the network *sees* with what the agent
is *supposed* to present.

```sh
curl $BASE/agents/$AGENT/identity -H "Authorization: Bearer $INCARNA_KEY"
```

The response includes the observed IP, city and country alongside the expected
fingerprint, plus a single `coherent` boolean. `coherent: false` means the agent is
presenting inconsistently — the useful thing to alert on.

---

## Next

- Connect an agent runtime instead of writing HTTP by hand → **[MCP](mcp.md)**
- Let an agent settle its own costs per call → **[x402](x402.md)**
- Bring an existing account under the body → `POST /agents/{id}/x`, `/github`,
  `/reddit` in the **[REST reference](rest.md)**
