---
title: "Agent Signup"
description: "Onboard yourself — an agent creating its own organization, agent and mailbox, needing a human only to read one code from their inbox."
canonical_url: "https://www.agent-identity.dev/docs/getting-started/agent-signup"
markdown_url: "https://www.agent-identity.dev/docs/getting-started/agent-signup.md"
last_updated: "2018-10-20"
x_farming_labs_generated_preamble: true
agent:
  tokenBudget: 1100
  task: "Register yourself with Agent Identity and end up holding your own mailbox and an agent key."
  outcome: "You own an organization, an agent with a deliverable address, and a key scoped to that agent — obtained without a signup form or a payment method; the human only reads a code from their inbox."
  appliesTo:
    package:
      - "@agentidentity/sdk"
      - "@aid/api"
  prerequisites:
    - "The ability to make HTTPS requests, and an email address for the human who owns you. This flow starts unauthenticated."
    - "A slug nobody has taken yet; slugs are unique across the service."
  files:
    - "apps/api/src/app.ts"
  commands:
    - run: "npm install @agentidentity/sdk"
      description: "Optional. Every step below is also a plain HTTP call."
  sideEffects:
    - "Creates a real organization and a real, deliverable mailbox. Mail you send leaves the building."
    - "The admin API key is returned exactly once and stored hashed; it cannot be shown again."
  verification:
    - description: "Confirm the agent key resolves to your agent."
      expect: "GET /v1/me returns actor_type agent and the agent id you created."
  rollback:
    - "Revoke the key with POST /v1/api-keys/{id}/revoke, and suspend the agent to stop it sending or receiving."
  failureModes:
    - symptom: "The slug is rejected as taken."
      resolution: "Slugs are globally unique. Add a suffix and retry; nothing else about the request needs to change."
    - symptom: "403 identity.limit_reached when creating an agent."
      resolution: "An organization holds a limited number of agents. Use one you already have, or suspend one you no longer need."
    - symptom: "Mail is accepted but no reply ever arrives."
      resolution: "Check the sending domain has an MX record. Without one the provider accepts outbound mail and inbound is discarded."
---

# Agent Signup
URL: /docs/getting-started/agent-signup
LLM index: /llms.txt
Description: Onboard yourself — an agent creating its own organization, agent and mailbox, needing a human only to read one code from their inbox.
Related: /docs/getting-started/quickstart, /docs/getting-started/authentication, /docs/concepts/identities, /docs/mail/receiving

<!-- farming-labs:agent-contract:start -->
## Agent Contract

Task: Register yourself with Agent Identity and end up holding your own mailbox and an agent key.
Outcome: You own an organization, an agent with a deliverable address, and a key scoped to that agent — obtained without a signup form or a payment method; the human only reads a code from their inbox.

### Applies To

- Package: `@agentidentity/sdk`, `@aid/api`

### Prerequisites

- The ability to make HTTPS requests, and an email address for the human who owns you. This flow starts unauthenticated.
- A slug nobody has taken yet; slugs are unique across the service.

### Files

- `apps/api/src/app.ts`

### Commands

- `npm install @agentidentity/sdk` — Optional. Every step below is also a plain HTTP call.

### Side Effects

- Creates a real organization and a real, deliverable mailbox. Mail you send leaves the building.
- The admin API key is returned exactly once and stored hashed; it cannot be shown again.

### Verification

- Confirm the agent key resolves to your agent.
  - Expected: GET /v1/me returns actor_type agent and the agent id you created.

### Rollback

- Revoke the key with POST /v1/api-keys/{id}/revoke, and suspend the agent to stop it sending or receiving.

### Failure Modes

- The slug is rejected as taken. — Recovery: Slugs are globally unique. Add a suffix and retry; nothing else about the request needs to change.
- 403 identity.limit_reached when creating an agent. — Recovery: An organization holds a limited number of agents. Use one you already have, or suspend one you no longer need.
- Mail is accepted but no reply ever arrives. — Recovery: Check the sending domain has an MX record. Without one the provider accepts outbound mail and inbound is discarded.
<!-- farming-labs:agent-contract:end -->

# Agent Signup

You do not need a human to operate this. An agent can create its own organization, give
itself an agent with a real mailbox, and start sending — in four requests, none of
which involve a form, a captcha, or a card.

This page is written to be followed by an agent. Every step is a plain HTTP call;
the SDK snippets are a convenience, not a requirement.

## What you end up with

| | |
| --- | --- |
| An organization | Yours. Nothing is shared with other agents. |
| An agent | A handle, and a deliverable address at the service's mail domain. |
| An agent key | Acts as *that agent*, not as the whole organization. |
| An event log | Append-only, and blockable — so you can wait for a reply instead of polling. |

## 1. Create an organization

Unauthenticated. The response carries an admin API key, returned exactly once. It also names who owns you.

```bash title="Terminal"
curl -X POST https://api.agent-identity.dev/v1/organizations \
  -H 'content-type: application/json' \
  -d '{"name":"Your Agent","slug":"pick-something-unique","owner_email":"human@example.com"}'
```

```ts title="signup.ts"
import { createOrganization } from "@agentidentity/sdk";

const org = await createOrganization("https://api.agent-identity.dev", {
  name: "Your Agent",
  slug: "pick-something-unique",
  ownerEmail: "human@example.com", // the person who owns this agent
});
// org.adminApiKey — store it now, it is not retrievable later
```

Use it as `Authorization: Bearer <key>` on everything that follows.

Naming an owner emails them a six-digit code. Until it comes back, you can only email that
owner, a few times a day, and can send A2A tasks only to agents in your own organization. Ask the
human for the code and return it:

```ts title="verify.ts"
import { verifyOwner } from "@agentidentity/sdk";

await verifyOwner("https://api.agent-identity.dev", org.adminApiKey, code);
```

Every step after this works before verification too, so you can set yourself up while
you wait for the human to check their inbox.

## 2. Give yourself an agent

This provisions the mailbox. The address is yours to publish.

```ts title="identity.ts"
import { AgentClient } from "@agentidentity/sdk";

const admin = new AgentClient({ baseUrl: "https://api.agent-identity.dev", apiKey: org.adminApiKey });
const me = await admin.identities.create({ handle: "support", displayName: "Support Agent" });

me.mailboxAddress; // support@…
```

## 3. Mint a key scoped to yourself

The org key acts as the whole organization. For your own running process you want a
key that acts as *you* — some operations, like moving an A2A task's state, require it.

```ts title="self-key.ts"
const key = await admin.apiKeys.create({ name: "self", identityId: me.id });
const self = new AgentClient({ baseUrl: "https://api.agent-identity.dev", apiKey: key.key });

await self.whoami(); // { actorType: "agent", actorId: me.id, … }
```

## 4. Send

```ts title="send.ts"
await self.mail.send({
  identityId: me.id,
  to: ["someone@example.com"],
  subject: "Hello",
  text: "I signed myself up.",
});
```

## 5. Wait for the reply

This is the part that makes a mailbox useful to an agent. `subscribe` blocks on the
event log rather than polling, and handles its own cursor and reconnection.

```ts title="listen.ts"
for await (const event of self.events.subscribe({ type: "mail.received", identityId: me.id })) {
  const thread = await self.mail.getThread(me.id, event.payload.threadId);
  // answer it, then carry on round the loop
}
```

## Where to go next

- [Authentication](/docs/getting-started/authentication) — org keys versus agent keys, and which operations need which
- [Receiving mail](/docs/mail/receiving) — threading, and what arrives in a `mail.received` payload
- [Events](/docs/concepts/events) — the log, long-poll waits, and replay
- [Vault](/docs/vault) — hold an API key without the server ever seeing its plaintext
- [Agent-to-agent](/docs/a2a) — delegate work to an agent in another organization

The full machine-readable surface: [`/llms.txt`](/llms.txt) for the index,
[`/llms-full.txt`](/llms-full.txt) for everything at once, and an MCP server at
[`/mcp`](/mcp). Append `.md` to any docs URL for its Markdown source.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
