Sign up
An agent can create its own Ackuna organization and API key. Two requests, one emailed code. No key is needed for either request.
API sign-up can be closed by the operator, independently of the console's registration form.
While it is closed, both requests answer 503 registration_disabled and nothing is created
or mailed; a code issued earlier cannot be redeemed until it reopens.
1. Ask for a code
POST /v1/signup
Content-Type: application/json
{"email": "ops@yourcompany.com", "organization_name": "Robot Co"}
{"data": {"object": "signup", "signup_id": "sgn_01k4c2v8qf3m7d5b0y6xz4rt1c", "email": "ops@yourcompany.com", "expires_at": "2026-09-04T12:15:00.000Z"}}
The status is 202: nothing has been created yet, a code has only been mailed to that
address. It is valid for 15 minutes and 5 attempts. The address is normalized before use —
lower-cased, a +tag in the local part is dropped, and for Gmail (gmail.com,
googlemail.com) dots are dropped and the domain becomes gmail.com — so
ops+robots@yourcompany.com and ops@yourcompany.com are the same account, and so are
jane.doe@gmail.com and janedoe@googlemail.com. Disposable mail providers are refused with
422 invalid_request. If the address already belongs to an Ackuna user you get
409 email_already_registered: sign in to the console with it and issue a key there instead.
One code per address at a time. While a code is live, asking again answers
409 signup_pending and mails nothing; the first code keeps working, and Retry-After says
when it expires. Keep the signup_id from the first response.
Rate limits on this path are deliberately tight: 5 requests per hour per IP, 3 per hour per address, and 5 completed sign-ups per IP per day shared with the console's registration form; the verify step allows 30 per hour per IP on top of the 5 attempts per code. Read the code from the mailbox — do not loop on this request.
2. Prove the mailbox
POST /v1/signup/verify
Content-Type: application/json
{"signup_id": "sgn_01k4c2v8qf3m7d5b0y6xz4rt1c", "code": "K7MP2XQ9"}
{"data": {
"object": "signup_completed",
"organization": {"id": "org_01k4c2v8qf3m7d5b0y6xz4rt2d", "name": "Robot Co"},
"api_key": {"key": "ak_9f2c1e7b4a6d8035f1c9a2b7e4d6f803a1b2c3d4", "prefix": "ak_9f2c1e7b4", "scopes": ["inboxes:read", "inboxes:write", "messages:read", "messages:send", "webhooks:read", "webhooks:write", "domains:read", "domains:write"]},
"console_url": "https://agents.ackuna.com/login?product=agent-mail",
"docs_url": "https://agents.ackuna.com/docs/quickstart",
"console_claim": "Use \"Forgot password\" on the console login page; the owner account has no password yet."
}}
The status is 201: the organization, its owner account and that key now exist. The key is
shown once — store it now. console_claim is the sentence to hand a human who wants the
console: the owner account was created without a password, so it is claimed through "Forgot
password" rather than a normal sign-in. A wrong code answers 422 signup_code_invalid with
the attempts remaining; an expired, used or exhausted sign-up answers 410 signup_expired —
ask for a new code; and if a person registered that address through the web form while the
code was in flight, verification answers 409 email_already_registered — sign in to the
console and issue a key there instead.
What you have now
- An organization on the Free plan: 3 inboxes, 100 outbound messages a day, 3,000 a
month, 1 webhook endpoint.
GET /v1/meshows the exact numbers. - An owner account for that organization, already verified — the code was the proof — so sending is unlocked immediately. See Errors for what organizations registered through the web form see before their owner clicks the link.
- The console at
console_url, where a person can watch what the agent is doing once they have claimed the account as described above.
Continue with the Quickstart from step 2.