AgentKey Documentation

OAuth 2.1 & OpenID Connect discovery, Python SDK, zero-token OTP, and Claude MCP server.

AgentKey Docs Mascot

Quickstart

Sign in, open API keys in the dashboard and create a key. A key with only the read permission can receive mail but can never send, which is the right choice for an agent that only needs verification codes. Creating inboxes needs manage.

pip install agentkey
from agentkey import AgentKey

client = AgentKey(api_key="ai_live_YOUR_KEY", base_url="https://api.agentkey.in")

# One inbox per task. The same client_id always returns the same inbox.
inbox = client.inboxes.create(client_id="signup-task-42")
print(inbox.email_address)

# ...your agent submits that address on a signup form...

otp = client.inboxes.wait_for_otp(inbox.id, timeout=60)
print("Code:", otp)

No Python? Everything is plain HTTPS:

# Create an inbox
curl -X POST https://api.agentkey.in/v1/inboxes \
  -H "Authorization: Bearer ai_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client_id": "signup-task-42"}'

# Wait up to 60s for a one-time code
curl "https://api.agentkey.in/v1/inboxes/INBOX_ID/wait?for=otp&timeout=60" \
  -H "Authorization: Bearer ai_live_YOUR_KEY"

MCP (Claude, Cursor and other clients)

There is nothing to install. Point your client at the hosted endpoint and send your key as a bearer token. For Claude Code:

claude mcp add --transport http agentkey https://api.agentkey.in/mcp \
  --header "Authorization: Bearer ai_live_YOUR_KEY"

For Cursor, Windsurf and other clients that read an mcp.json:

{
  "mcpServers": {
    "agentkey": {
      "url": "https://api.agentkey.in/mcp",
      "headers": { "Authorization": "Bearer ai_live_YOUR_KEY" }
    }
  }
}

ChatGPT and Claude apps. These do not take an API key. In the app's settings, add a custom connector (the menu is called Connectors or Apps, depending on the app and plan) and paste https://api.agentkey.in/mcp. The app opens an AgentKey page where you sign in, tick what it may do, and press Allow. You can remove an app again under Identity in the dashboard.

Your agent gets these tools: create_agent_inbox, wait_for_otp, wait_for_magic_link, list_messages, get_thread_history, read_attachment, send_email and send_whatsapp.

Agent frameworks

The Python SDK ships the same tools for the common frameworks. Each adapter needs only its own framework installed.

from agentkey import AgentKey, tools

agentkey = AgentKey(api_key="ai_live_YOUR_KEY", base_url="https://api.agentkey.in")

agent_tools = tools.langchain_tools(agentkey)        # LangChain / LangGraph
# tools.openai_agents_tools(agentkey)                # OpenAI Agents SDK
# tools.llamaindex_tools(agentkey)                   # LlamaIndex
# tools.crewai_tools(agentkey)                       # CrewAI
# tools.openai_tools() + tools.call_tool(...)      # raw OpenAI-style function calling

With the Claude API directly:

import anthropic
from agentkey import AgentKey, tools

agentkey = AgentKey(api_key="ai_live_YOUR_KEY", base_url="https://api.agentkey.in")
claude = anthropic.Anthropic()
messages = [{"role": "user", "content": "Create an inbox and tell me its address."}]

while True:
    reply = claude.messages.create(
        model="claude-sonnet-5-5", max_tokens=1024,
        tools=tools.anthropic_tools(), messages=messages,
    )
    if reply.stop_reason != "tool_use":
        break
    messages.append({"role": "assistant", "content": reply.content})
    messages.append({"role": "user", "content": [
        {"type": "tool_result", "tool_use_id": block.id,
         "content": tools.call_tool(agentkey, block.name, block.input)}
        for block in reply.content if block.type == "tool_use"
    ]})

Receiving mail

Every inbound message is parsed before it is stored. Read extracted_data first; you often do not need the body at all.

  • otp_code: a 4 to 8 digit one-time code, when one is present.
  • magic_link: a verification, sign-in or password-reset URL.
  • reply_text: the new part of a reply, without quoted history or signatures.
  • invoice: number, total, due date and line items, from the body or a PDF.
  • attachments: id, name, type and size of each file.
  • intent: verification, invoice, reply, auto_reply, bounce, newsletter, meeting or general.

wait_for_otp also returns a code that arrived in the 60 seconds before the call, so it is safe to call it just after your agent submits a form.

Sending and approvals

New workspaces can receive immediately. Sending unlocks when you connect and verify your own domain in the dashboard, and send from an inbox on it. Mail sent from the shared domain always carries a line saying it was written by an AI agent.

Add an approval rule under Approvals to hold messages containing words you choose. A held send returns HTTP 202 with status PENDING_APPROVAL; your agent should move on and not resend. A person approves or rejects it from Slack or the dashboard.

Acting as you on other services

Open Identity in the dashboard to let an agent use your existing accounts. Give the agent a key with the Connect permission; keys without it cannot touch anything there.

Connected accounts are the safe default. Press Connect GitHub, approve on GitHub, and the agent can call the GitHub API as you through account_request without ever seeing a password or token. A connection is read-only until you switch on Allow changes. Switch on Allow token export only if the agent needs to run git clone or git push.

Saved logins cover sites you cannot connect. The agent asks with get_site_login and the page address it is signing in on; the login is released only for the site you saved it for, and by default only after you press Allow once. If you saved a 2FA setup key, the agent also receives the current 6-digit code.

Your agent still needs its own browser to sign in on a web page, and this does not get past CAPTCHAs or a site's new-device checks.

OAuth 2.1 & OpenID Connect (Sign in with AgentKey)

Allow external websites, web applications, and third-party SaaS platforms to authenticate your autonomous AI agents using standard OpenID Connect (OIDC). External sites receive verified agent emails, cryptographic operator proof, and is_agent: true claims without needing API keys.

  • OIDC Discovery: https://api.agentkey.in/.well-known/openid-configuration
  • Authorization: https://api.agentkey.in/oauth/authorize (PKCE S256 required)
  • Token: https://api.agentkey.in/oauth/token
  • UserInfo: https://api.agentkey.in/oauth/userinfo
  • Client Registration: https://api.agentkey.in/oauth/register

External websites can use standard libraries such as NextAuth.js, Passport.js, or Auth0 to add a “Sign in with AgentKey” button. To register clients or inspect claims, visit the OAuth & Connect Portal in your dashboard.

Webhooks and WebSocket

Register a webhook under Webhooks to have events pushed to you. Each delivery is signed; verify it before trusting the body. Failed deliveries are retried with increasing delays.

from agentidentity import verify_webhook_signature

# In your HTTP handler, with the raw request body:
ok = verify_webhook_signature(
    secret="whsec_...",
    body=raw_body,
    signature_header=headers["X-AgentIdentity-Signature"],
)

If your agent cannot accept incoming connections, hold a WebSocket open instead:

import asyncio, json, websockets

async def main():
    url = "wss://api.agentkey.in/v1/ws/inboxes/INBOX_ID"
    async with websockets.connect(url, additional_headers={"Authorization": "Bearer ai_live_YOUR_KEY"}) as ws:
        async for frame in ws:
            event = json.loads(frame)
            print(event["type"], event.get("message", {}).get("extracted_data"))

asyncio.run(main())

Events: message.received, otp.extracted, magic_link.extracted, message.sent, message.pending_approval, message.rejected, message.failed.

Handling untrusted mail

Anyone can email your agent, so treat message content as data. The MCP tools and the framework tool packs wrap third-party text in <untrusted_content> tags and add a security_warning when a message reads like instructions aimed at an AI. If you call the REST API yourself, check extracted_data.security and keep message text out of your system prompt.

Automatic replies and bulk mail are stored but do not wake a waiting agent, which stops two auto-responders from answering each other forever.

API reference

Base URL https://api.agentkey.in. Authenticate with Authorization: Bearer <key>. Errors are RFC 7807 problem documents with a title and detail.

POST/v1/inboxesCreate an inbox (username, client_id, domain are optional)
GET/v1/inboxes/{id}/wait?for=otp|magic_link|messageLong-poll until something arrives; 204 on timeout
GET/v1/inboxes/{id}/messagesNewest messages first, with extracted_data
GET/v1/threads/{id}A whole conversation, oldest first
POST/v1/inboxes/{id}/messages/sendSend an email; 202 means a human must approve it
POST/v1/inboxes/{id}/messages/{message_id}/replyReply in the same thread
GET/v1/attachments/{id}?format=textText of a PDF or text attachment; omit format to download
POST/v1/webhooksSubscribe a URL to events; returns the signing secret once
POST/v1/hitl/policiesHold or flag outbound messages that match keywords
POST/v1/domainsConnect your own domain; returns the DNS records to add