InboxSpecDocumentation

Getting started

Your first email

Receive your first verification code with JavaScript/TypeScript, Python, Java or Bash/curl.

Receive your first email

Register an inbox, wait for a code, then read the matching message.

Set INBOXSPEC_API_KEY in the environment that runs your example. Use a key with inbox read/write and message wait/read permissions. Keep the key out of source code, browser code and chat. You can override the API origin with INBOXSPEC_API_URL (no trailing slash).

Choose your language

Run one example. It creates a fresh inbox and prints its address. While the wait is running, send “Your code is 123456” to that address from your app or email client. A match returns code candidates; a timeout means no matching mail arrived. HTTP and permission errors are separate failures.

JavaScript / TypeScript

Use Node.js 24+. Save as first-email.mjs; no packages are required. This JavaScript also works in a server-side TypeScript module.

Example
// Save as first-email.mjs. Requires Node.js 24+; no packages to install.
const apiUrl = process.env.INBOXSPEC_API_URL || "https://api.inboxspec.com";
const apiKey = process.env.INBOXSPEC_API_KEY;
if (!apiKey) throw new Error("Set INBOXSPEC_API_KEY to your project API key first.");

async function request(path, body) {
  const response = await fetch(new URL(path, apiUrl), {
    method: body === undefined ? "GET" : "POST",
    headers: { Authorization: "Bearer " + apiKey, "Content-Type": "application/json" },
    body: body === undefined ? undefined : JSON.stringify(body),
    signal: AbortSignal.timeout(70_000),
  });
  if (!response.ok) {
    // An HTTP error is different from a successful wait that found no email.
    const problem = await response.json().catch(() => null);
    throw Object.assign(new Error("HTTP " + response.status + ": check the API error reference before retrying."), {
      code: problem?.error?.code,
    });
  }
  return response;
}

const runId = "first-" + crypto.randomUUID();
const inbox = await (await request("/v1/inboxes/for-run", {
  run_id: runId, retention_seconds: 600,
})).json();
if (typeof inbox.address !== "string") throw new Error("No inbox address returned.");
console.log("Run ID:", runId);
console.log("Send a test email containing 'Your code is 123456' to: " + inbox.address);
console.log("Waiting up to 60 seconds…");
const result = await (await request("/v1/messages/wait", {
  inbox: inbox.address, match: { has_code: true }, timeout_ms: 60_000,
})).json();
if (result.status === "timeout") {
  console.log("No matching email. Check the address and your sender, then try a new run.");
  console.log({ reason: result.reason, arrivals: result.non_matching_arrivals, hint: result.hint });
  process.exitCode = 1;
} else if (result.status === "matched" && typeof result.message?.id === "string") {
  console.log("Code candidates:", result.message.codes);
  const bodyPath = "/v1/messages/" + encodeURIComponent(result.message.id) + "/body?format=";
  let body;
  try {
    body = await request(bodyPath + "text");
  } catch (error) {
    if (error.code !== "unsupported_format") throw error;
    console.log("This email is HTML-only. Email HTML:");
    body = await request(bodyPath + "html");
  }
  console.log(await body.text());
} else {
  throw new Error("Unexpected wait response. Check the API error reference.");
}
// Messages expire after ten minutes; the inbox remains until explicitly deleted. Accepted messages still count toward usage.
Example
node first-email.mjs

The JavaScript, Python and Java examples also print the matched body, falling back to HTML for an HTML-only message. Treat email HTML as untrusted text. They request ten-minute message retention; the inbox remains until you delete it. Accepted messages still count toward usage.

After all senders and waits finish, delete only this test’s inbox from the console. For Bash / curl, continue in the same terminal to read the matched body and clean up this run. Those Bash guides use the Bash tab’s variables; program variables do not carry over into your terminal.

If the request does not succeed
Missing inbox
Run registration first and use the returned address with a key from the same project.
Invalid input
Check the error’s field details. Preserve the documented field names and milliseconds for timeout.
Sign-in or permission error
Check the project key and its scopes. Console sign-in does not authenticate these terminal commands.
Quota exhausted
Check Usage and the reported reset time. Waiting is unmetered but still checks the received-message quota.
Too many waits or requests
Reduce concurrency and follow the server’s retry guidance within your test’s total time budget.
Network or service failure
Check the API address and connection. Retry within a bounded budget; do not treat the error as a timeout result.

Full error codes and remedies