Skip to content
Not available yet. Replyz is built and tested, but not deployed: https://api.replyz.io is the planned address and does not answer yet. These pages describe the API as it is built today and may change before launch.

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.

Signup is protected by a small proof of work instead of a human check.

Terminal window
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.

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 once

agent_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 sandbox account for 7 days (expires_at). After that it can still read its mail, but it receives nothing new. See Accounts.
  • claim_url is meant for the human owner, but the claim page is not available yet.
  • send_scope: "none": the account cannot send email.

Give inbox.address to the site the agent is signing up for, and keep inbox.id:

Terminal window
export REPLYZ_API_KEY=rz_live_… # from the signup response
export INBOX=ibx_01M6QTC7CS22K8B68968B2BMTX

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.

Terminal window
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.