This guide is for humans building with Reverbin for the first time.
If you are an autonomous agent or a tool runtime, start with AGENTS.md, ../SKILL.md, or the root llms.txt file.
What you will build
In this quickstart you will:
- Create a free inbox and copy the one-time API key.
- Connect to the Reverbin API.
- Register a signed webhook endpoint.
- Read threads.
- Reply to a thread.
- Inspect delivery and audit logs.
Prerequisites
You need:
- Node.js 20+ for the ESM SDK examples.
- A Reverbin inbox and API key from https://reverbin.com/signup.
- A reachable HTTPS endpoint if you want to receive webhooks.
Beta note: root-domain inboxes on reverbin.com are live. Use the address included with your signup result when running live mail tests, for example user@reverbin.com.
0. Create a free inbox
Open:
https://reverbin.com/signup
Choose Create free inbox. Reverbin creates your first inbox and returns a quickstart block once. Copy it immediately.
API signup alternative:
curl -X POST https://api.reverbin.com/v1/agent-signups \
-H "content-type: application/json" \
-H "Idempotency-Key: signup-support-agent-2026-07-09" \
-d '{
"requester_email": "builder@example.com",
"agent_name": "Support Agent",
"agent_use_case": "Handle customer support replies and escalate unusual requests.",
"preferred_inbox_name": "support-agent"
}'
Save these values in your shell or secret manager:
export REVERBIN_BASE_URL="https://api.reverbin.com"
export REVERBIN_API_KEY="<one-time API token from signup>"
export REVERBIN_INBOX_ID="<inbox id from signup>"
export REVERBIN_INBOX_EMAIL="<inbox address from signup>"
Do not hardcode API keys or webhook secrets in source code.
API keys authenticate /v1/* calls only; they never sign in to the browser dashboard. Human browser access uses the signup email code flow, with configured operator-token login reserved for internal operators.
Install
Install the public Node.js SDK from npm:
npm install @builtbyecho/reverbin
The SDK is Node.js ESM only. Browser runtimes are not supported; use a server-side Node process and never expose an API key in client-side code.
For local repository development:
git clone https://github.com/Wdustin1/reverbin.git
cd reverbin
cp .env.example .env
npm install
npm run migrate
npm run dev
1. Create a client
import { ReverbinClient } from '@builtbyecho/reverbin';
const reverbin = new ReverbinClient({
baseUrl: process.env.REVERBIN_BASE_URL ?? 'https://api.reverbin.com',
apiKey: process.env.REVERBIN_API_KEY,
timeoutMs: 30_000,
});
2. Create an inbox
Signup already creates your first inbox. To create the second free inbox or another paid-plan inbox:
const inbox = await reverbin.inboxes.create({
email_address: 'user@reverbin.com',
display_name: 'Support Agent',
});
console.log(inbox.id, inbox.email_address);
The default inbox policy is intentionally low-friction for normal agent replies:
- new-recipient approvals are off by default;
- external-domain approvals are off by default;
- links are allowed by default;
- risk flags are still recorded for audit.
Use explicit policy settings when you need stricter behavior.
3. Register a signed webhook endpoint
const webhook = await reverbin.webhooks.create({
url: 'https://agent.example.com/reverbin/webhook',
events: ['email.received', 'email.sent', 'email.failed', 'approval.required'],
});
// webhook.secret is returned once. Store it in the runtime secret manager immediately; do not log it.
Reverbin generates the signing secret on the server and returns it only in this creation response. The client does not choose it, later webhook-list responses omit it, and you cannot retrieve it again.
Reverbin sends JSON POST requests to the endpoint. Verify each request before the agent acts on it.
Expected signing header:
x-echo-email-signature: sha256=<hmac_hex_digest>
HMAC input:
raw JSON request body
HMAC key:
the endpoint secret returned once by POST /v1/webhooks
In a Node ESM webhook handler, use the constant-time verifier against the exact raw body bytes:
import { verifyWebhookSignature } from '@builtbyecho/reverbin/webhook-signatures';
const valid = verifyWebhookSignature(rawBody, signatureHeader, webhookSecret);
Attachment safety
Outbound attachments are not supported in the launch API or SDK; compose, reply, and forward accept text plus optional HTML. Inbound attachments are streamed into staged files under per-file, per-message, count, and timeout caps; they are not buffered without bounds. A message and all of its attachment metadata become visible together only after every attachment has been downloaded and validated. Missing attachment content, oversize streams, download failures, and storage failures reject the whole inbound message and clean up staged files.
The authenticated mail console renders only signature-verified PNG, JPEG, GIF, and WebP images inline when the declared media type matches the bytes. HTML, SVG, XML, PDF, unknown, and mismatched files are forced to download with restrictive response headers.
4. Read threads
const threads = await reverbin.inboxes.threads(process.env.REVERBIN_INBOX_ID!);
for (const thread of threads.data) {
console.log(thread.id, thread.subject);
}
Every paginated list returns { data, next_cursor, has_more }. If has_more is true, pass next_cursor unchanged back to the same list method:
const nextPage = threads.has_more
? await reverbin.inboxes.threads(process.env.REVERBIN_INBOX_ID!, {
cursor: threads.next_cursor!,
})
: null;
Fetch a full thread with messages:
const thread = await reverbin.threads.get('thr_123');
console.log(thread.messages);
5. Reply to a thread
const result = await reverbin.threads.reply('thr_123', {
text: 'Thanks — I can help with that.',
});
console.log(result.message_id ?? result.approval_id);
If policy allows the send, the response includes a message_id.
If policy requires approval, the response is 202 and includes:
{
"approval_id": "apr_...",
"status": "pending"
}
Compose and forward use the same policy and durable-send response contract:
await reverbin.messages.compose({
inbox_id: process.env.REVERBIN_INBOX_ID!,
to: ['person@example.com'],
subject: 'Hello',
text: 'Starting a new conversation.',
});
await reverbin.threads.forward('thr_123', {
to: ['operator@example.com'],
subject: 'Fwd: Hello',
text: 'Forwarding for review.',
});
The SDK does not retry requests automatically. Do not blindly retry compose, reply, forward, approval decisions, or other non-idempotent calls after a lost response. Automated signup, billing Checkout/Portal, API-key rotation, and webhook-secret rotation require a caller-owned idempotency_key; retain the key and reuse it only with the identical request body. Signup replay prevents duplicate provisioning but intentionally omits one-time credentials, so sign in and rotate them if the original response was lost.
Timeout, abort, and errors
Requests time out after 30 seconds by default. Set timeoutMs on the client or per request, and compose it with your own AbortSignal:
import { ReverbinApiError, ReverbinClient, ReverbinTimeoutError } from '@builtbyecho/reverbin';
const controller = new AbortController();
try {
await reverbin.inboxes.list(undefined, { signal: controller.signal, timeoutMs: 5_000 });
} catch (error) {
if (error instanceof ReverbinApiError) {
console.error(error.status, error.code, error.requestId, error.retryAfterSeconds, error.quota);
} else if (error instanceof ReverbinTimeoutError) {
console.error('Timed out after', error.timeoutMs);
}
}
API error details are credential-redacted. The client never includes the bearer token in its error message or JSON representation.
6. Inspect operations
Delivery logs:
const deliveries = await reverbin.webhooks.deliveries();
console.log(deliveries.data[0]);
Audit logs:
const audit = await reverbin.auditLogs.list();
console.log(audit.data[0]);
Operational dashboard
Browser dashboard:
https://reverbin.com/dashboard/login
Sign in with the email used at signup. The dashboard shows inboxes, recent messages, webhook endpoints, billing, and audit-oriented mail actions.
Local health checks
curl http://127.0.0.1:8797/health
curl http://127.0.0.1:8797/readyz
Production health checks:
curl https://api.reverbin.com/health
curl https://api.reverbin.com/readyz
Troubleshooting
| Symptom | What to check |
|---|---|
401 from /v1/* | Missing or wrong bearer token. |
404 target inbox not found on inbound provider webhook | The inbound recipient does not match a created Reverbin inbox. |
| Webhook endpoint receives nothing | Confirm endpoint is active, event type is subscribed, and worker mode is running if queued. |
Reply returns 202 pending | The inbox policy requires approval for that send. |
Reply returns 403 policy blocked send | Policy blocked recipient/domain/content/rate. |
| Inbound mail never appears | Confirm the recipient matches REVERBIN_INBOX_EMAIL and provider receiving status is healthy. |
Next reads
API.mdfor endpoint examples.AGENTS.mdfor agent-runtime behavior.../SKILL.mdfor a downloadable agent skill.../llms.txtfor compact machine-readable context.