Quickstart
An agent signs itself up, gets an inbox, and waits for a verification code. You need Node.js 22 or later (for the proof of work) and curl.
1. Get a challenge
Section titled “1. Get a challenge”Signup is protected by a small proof of work instead of a human check.
curl -s https://api.replyz.io/v1/signup/challenge{ "challenge": "v1.20.1793948855346.PCF7eyz4rjio1wd6.2a1750216fee3ab330a253e5a3302fdbdc0946032a31e14a802a6119ed168da3", "difficulty": 20, "expires_at": "2026-11-06T07:07:35.346Z"}Treat challenge as an opaque string. It expires after 10 minutes and works for one signup.
2. Solve it and sign up
Section titled “2. Solve it and sign up”Find a nonce (1–32 characters from [0-9A-Za-z]) so that the SHA-256 of the UTF-8 string <challenge>:<nonce> starts with at least difficulty zero bits. At difficulty 20 that is about a million hashes on average: about one second on a laptop. This script does both steps and signs up (Node.js 22, no dependencies):
import { createHash } from "node:crypto";const API = "https://api.replyz.io";const zeroBits = (buf) => { let n = 0; for (const b of buf) { if (b === 0) { n += 8; continue; } return n + Math.clz32(b) - 24; } return n;};const c = await (await fetch(`${API}/v1/signup/challenge`)).json();let i = 0;while (zeroBits(createHash("sha256").update(`${c.challenge}:${i.toString(36)}`).digest()) < c.difficulty) i++;const res = await fetch(`${API}/v1/signup`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ challenge: c.challenge, nonce: i.toString(36), agent_name: "Scout Agent" }),});console.log(res.status, await res.json()); // store api_key now: it is shown onceagent_name is optional. It becomes the start of the address (Scout Agent → scout-agent-…). Names made of role words, brand names or look-alikes (support, paypal, g00gle) are refused with name_reserved; the challenge stays valid, so send it again with another name.
The answer is 201 Created:
{ "org_id": "org_01M6QTC7CSG2BWBDE0CRB4H3Y7", "status": "sandbox", "api_key": "rz_live_EXAMPLEexampleEXAMPLEexample0000", "inbox": { "id": "ibx_01M6QTC7CS22K8B68968B2BMTX", "address": "scout-agent-kncx62@youreplyz.com" }, "claim_url": "https://replyz.io/claim/EXAMPLEtokenEXAMPLEtokenEXAMPLE0", "expires_at": "2026-11-13T06:57:41.776Z", "limits": { "inboxes": 1, "receive_per_month": 1000, "send_scope": "none" }, "terms_url": "https://replyz.io/terms", "privacy_url": "https://replyz.io/privacy", "next": "Save api_key now (shown once). Send claim_url to your human so they can own this account."}- The account is a
sandboxaccount for 7 days (expires_at). After that it can still read its mail, but it receives nothing new. See Accounts. claim_urlis meant for the human owner, but the claim page is not available yet.send_scope: "none": the account cannot send email.
3. Use the address
Section titled “3. Use the address”Give inbox.address to the site the agent is signing up for, and keep inbox.id:
export REPLYZ_API_KEY=rz_live_… # from the signup responseexport INBOX=ibx_01M6QTC7CS22K8B68968B2BMTX4. Wait for the code
Section titled “4. Wait for the code”Right after the agent triggers the email, it calls wait. The call answers as soon as a matching message arrives, or after timeout seconds. With extract=otp,link the answer also carries the code and the verification link.
curl -sG "https://api.replyz.io/v1/inboxes/$INBOX/wait" \ -H "Authorization: Bearer $REPLYZ_API_KEY" \ --data-urlencode 'from=*@accounts.example.com' \ --data-urlencode 'exclude_returned=true' \ --data-urlencode 'extract=otp,link' \ --data-urlencode 'timeout=50' \ --max-time 65{ "status": "ok", "messages": [ { "id": "msg_01M6R51QPXKNV8E3Y0VE3JMR0J", "thread_id": "thr_01M6R51QPXKNV8E3Y0VE3JMR0J", "inbox_id": "ibx_01M6QTC7CS22K8B68968B2BMTX", "from": "no-reply@accounts.example.com", "to": ["scout-agent-kncx62@youreplyz.com"], "subject": "Your Example verification code", "snippet": "Your verification code is 482913. It expires in 10 minutes.", "received_at": "2026-11-06T10:04:12.381Z", "sender_trust": "unauthenticated", "injection_risk": "low", "otp_like": true, "has_attachments": false, "returned_before": false, "extracted": { "otp": { "code": "482913", "value": "482913", "confidence": 0.78 }, "otp_candidates": [], "primary_link": null, "links": [] } } ]}Type extracted.otp.value into the site, or, if the mail asks for a click, use extracted.primary_link.url, but only if its host is the site you signed up on. If nothing arrives in time, the answer is {"status": "timeout", …}: call wait again.
Next steps
Section titled “Next steps”- Get a verification code: the full flow, with low-confidence and timeout handling.
- Waiting for mail: filters,
sinceand the 5-hold limit. - Limits and Errors.