# KeyID's SDK provisions an email address and then gets out of the way

> KeyID's Python package gives an AI agent a working email address with no signup and no human in the loop: generate an Ed25519 keypair, call provision(), then send, receive, reply and search, while the service handles domains, address rotation, reputation and deliverability. What is worth checking before relying on it is the gap between the README and the package metadata, and the fact that the last push to main was on 2026-03-13.

**KeyID-AI/sdk-py** — Free email for AI agents. No signup, no human needed. Install → provision → send and receive. Ed25519 keypair auth.

- Repository: https://github.com/KeyID-AI/sdk-py
- Website: https://keyid.ai
- Stars: 301 · Forks: 0
- Language: Python
- License: not declared
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/keyid-ai-sdk-py

## provision() hands back an address and the service keeps it

The division of labour is the whole design, and it is stated in two sentences at the top of the README. Your agent generates a keypair and calls provision(). KeyID.ai handles everything on the other side of that call: domain management, rotation, reputation monitoring and deliverability. So the SDK is not a mail server and not an SMTP client in the usual sense; it is an authenticated handle onto an address that someone else operates. That framing explains the API shape. Identity has four methods, and the interesting ones are not provision() itself but get_addresses(), which lists current and historical addresses so an agent can see the ones it has burned through, and get_recovery_token(), which exists for key rotation. The README's promise of a real address in three lines of code is accurate in the sense that matters: the agent's first call returns something it can send from. Install is one command.

```bash
pip install keyid
```

## Ed25519 challenge-response, with a signed nonce on every call

Authentication is Ed25519 challenge-response, and the SDK handles it without the caller doing anything, which is a design choice worth naming because it removes the token-management step most agent frameworks get wrong. The sequence has three parts. On first use a keypair is generated, or loaded from environment or constructor options. provision() registers the public key and returns an email address. Every subsequent call authenticates automatically through a signed nonce exchange, so there is no bearer token to store, rotate or leak. Three constructor forms are documented.

```python
# Option 1: Auto-generate keypair (default)
agent = KeyID()

# Option 2: Provide existing keypair
agent = KeyID(public_key="...hex...", private_key="...hex...")

# Option 3: Custom base URL
agent = KeyID(base_url="https://your-instance.com")
```

Option 2 is what lets an agent's identity survive a process restart, and option 3 is the interesting one, because a custom base URL implies you can point the client at an instance you control. Nothing in the README says what software that would be, whether it is the same service, or which of the features above still work.

## The requirements list omits the library that does the signing

Compare the two places the dependencies are declared and one is missing. The README has a Requirements section with two bullets: Python 3.9 or newer, and httpx, noted as installed automatically. The package metadata tells a longer story. Under the build system it requires setuptools 68 or newer plus wheel, using the setuptools.build_meta backend. The project block names the distribution keyid at version 0.1.2, declares requires-python as 3.9 or newer to match the README, and lists two runtime dependencies: httpx at 0.25 or newer, and cryptography at 41.0 or newer. That second dependency is the one doing the Ed25519 work, so the README's requirements list is incomplete rather than merely terse. It is a small thing, and the kind of thing that costs an afternoon when a build environment pins only what the documentation said. The metadata also carries a keyword list, keyid, agent, email, ed25519 and identity, which is a more honest description of the package than the README's opening line.

## One release, and it landed seven minutes after the last push

Take the release history seriously, because there is very little of it. Exactly one release is listed: v0.1.2, published on 2026-03-13. The last push to main was also on 2026-03-13, a few minutes after that tag. As of this snapshot the repository has been quiet for the best part of seven months, and no other tag exists, so there is no v0.1.1 or v0.1.0 to compare against and no changelog in the tree to explain what changed. A version of 0.1.2 as the only published release suggests the earlier numbers existed during development and were never cut as releases, which is common and harmless. The top-level listing is correspondingly thin: .github, .gitignore, README.md, the keyid package directory and pyproject.toml. There is no LICENSE file anywhere in it, even though the README has a License section reading MIT and pyproject declares license as MIT text. Two places assert the licence and no file carries it.

## Almost every method ends in kwargs, so the typed surface is thin

Read the API tables closely and a pattern emerges that the prose does not mention. The identity methods are specific, but get_inbox takes keyword arguments for pagination, filtering and search. get_message takes an id. update_message takes an id and more keyword arguments for labels and read or starred status. send takes a recipient, a subject, a body and more keyword arguments for HTML, CC, BCC and scheduling. list_threads, get_forwarding, set_forwarding, set_auto_reply, list_contacts, create_contact, get_webhook_deliveries and get_metrics all end the same way. So the tables give you method names and one-line meanings, but almost no parameter types, no return shapes and no enumeration of what the keyword arguments accept. The features section is where the real parameter names surface, one per line: scheduled_at for a scheduled send, search for full-text inbox search, is_starred on update_message, enabled and body on set_auto_reply, and html on send. If you are generating calls from these docs rather than from an editor, you are working from examples, not from a specification.

## Two defaults encode policy: permanent=False and body=None

Small signature choices tell you what the designers considered normal, and two of them here are worth attention. delete_thread takes permanent with a default of False, so the ordinary path is a reversible delete and permanent removal is something you have to ask for. That is a sensible default for an SDK that an autonomous agent will call. forward takes body with a default of None, so forwarding without adding commentary is the default case. Against those, send_draft is a separate method rather than an argument to send, which means outbound mail has two paths: one that composes and transmits immediately, and one that stages a draft you can update before calling send_draft to transmit it. For an agent that needs to prepare content before committing to send, that split is the useful part of the surface. The settings group rounds it out with signature, forwarding and auto-reply accessors, and contacts and webhooks are conventional CRUD with webhooks carrying delivery history.

## Conclusion

KeyID's Python SDK fits a team building an autonomous agent that needs to send and receive mail without provisioning accounts through a human, and that can accept depending on a hosted service for domains and deliverability. It does not fit anyone who needs a signed stable release, since only v0.1.2 exists, published on 2026-03-13, and the last push to main was the same day. Before you build on it, read pyproject.toml rather than the requirements list, because cryptography is a hard dependency the README does not mention, and remember that the licence is declared as MIT in two metadata places but no licence file exists in the repository, so confirm the terms before you vendor the code.

## FAQ

### How does KeyID authenticate an agent?

With Ed25519 challenge-response, handled automatically by the SDK. A keypair is generated on first use or loaded from environment or constructor options, provision() registers the public key and returns an address, and later calls authenticate through a signed nonce exchange.

### What does KeyID's Python SDK need to install?

The README lists Python 3.9 or newer and httpx, installed automatically. The package metadata additionally requires cryptography 41.0 or newer alongside httpx 0.25 or newer, and the build itself needs setuptools 68 or newer plus wheel. Installation is pip install keyid.

### What can a KeyID agent do with its address?

Beyond provision() there is get_identity(), get_addresses() for current and historical addresses, and get_recovery_token() for key rotation. The message surface covers inbox, single message, labels, unread count, send, reply, reply_all and forward, with separate thread, draft, contact, webhook, list and metrics methods.

### Can I point KeyID at my own server?

The constructor accepts a base_url, documented as a custom base URL pointing at your own instance. The README does not say what software would run there, whether it is the same service, or which features remain available.

### How current is KeyID's Python SDK?

Only one release is listed, v0.1.2, published on 2026-03-13, and the last push to main was on the same day. pyproject.toml declares the same version, and the repository contains no changelog and no licence file.

## Sources

- [Issues](https://github.com/KeyID-AI/sdk-py/issues)
- [KeyID-AI/sdk-py on GitHub](https://github.com/KeyID-AI/sdk-py)
- [Project website](https://keyid.ai)
- [README](https://github.com/KeyID-AI/sdk-py/blob/main/README.md)
- [Releases](https://github.com/KeyID-AI/sdk-py/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/keyid-ai-sdk-py
