Quickstart

Wait for the OTP. One API call.

Point your signup form at a mailsocket inbox, then block on the wait endpoint until the OTP or magic link arrives. No polling loop, no Gmail, no IMAP.

Three steps

  1. Create an inbox and an API key. Sign up, verify your email, and open the dashboard. Your first inbox is created automatically, and you can mint an API key in one click.
  2. Point your signup or test at your inbox address. Give your signup form an address of the form <key>@in.inboxpipe.net.
  3. Wait for the code. Call GET /api/v1/inboxes/<id>/messages/wait with Authorization: Bearer <key>. The call blocks until the OTP or magic link arrives, then returns it.

The wait endpoint

GET /api/v1/inboxes/{id}/messages/wait blocks until a matching parsed message arrives, or returns empty when the window elapses. This is the "one call, wait for the code" primitive.

Query parameters

ParamTypeMeaning
timeout seconds (float) How long to block. Default 20. Clamped to [1, 25] server-side.
since ISO-8601 | public_id | unix ts Only messages received strictly after this point match. Default: the request start time, so a code arriving during the call is caught but a pre-existing one is not. Pass since=0 (the epoch) to mean "return any existing unseen code".
require otp | link | any What counts as a match. Default otp. link matches magic_link IS NOT NULL; any matches either.
min_confidence float 0..1 Only match an OTP whose otp_confidence is at least this. Default 0.0. Ignored for link.

Responses

StatusBodyMeaning
200 {"data": {...otp, magic_link, subject, from...}} A matching parsed message arrived (the earliest strictly newer than since).
204 empty Waited, nothing matched yet — call again. This is success, not an error.
404 error body The inbox is not owned or does not exist.
429 error body The concurrent-wait cap is exhausted. Code too_many_wait_requests (per-account cap: 2 free / 3 paid) or wait_capacity (global cap of 16). Retry shortly.
200 response
{
  "data": {
    "subject": "Your verification code",
    "from": "[email protected]",
    "otp": "482193",
    "magic_link": null
  }
}

Code samples

Each sample submits a signup form, then blocks on the wait endpoint for the OTP. Replace *** with your real API key and inbox_xxx with your inbox id.

curl
# 1. submit your signup form with a mailsocket address
curl -X POST https://app.example.com/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'

# 2. block until the OTP lands — one call, no polling
curl "https://dash.mailsocket.app/api/v1/inboxes/inbox_xxx/messages/wait?require=otp&timeout=20" \
  -H "Authorization: Bearer ***"
Python (requests)
import requests

requests.post("https://app.example.com/signup", json={"email": "[email protected]"})

# block until the OTP lands — one call, no polling
r = requests.get(
    "https://dash.mailsocket.app/api/v1/inboxes/inbox_xxx/messages/wait",
    params={"require": "otp", "timeout": 20},
    headers={"Authorization": "Bearer ***"},
)
if r.status_code == 200:
    print(r.json()["data"]["otp"])   # → "482193"
Node / JS (fetch)
// 1. submit your signup form with a mailsocket address
await fetch("https://app.example.com/signup", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email: "[email protected]" }),
});

// 2. block until the OTP lands — one call, no polling
const url = new URL("https://dash.mailsocket.app/api/v1/inboxes/inbox_xxx/messages/wait");
url.searchParams.set("require", "otp");
url.searchParams.set("timeout", "20");
const res = await fetch(url, {
  headers: { Authorization: "Bearer ***" },
});
if (res.status === 200) {
  const { data } = await res.json();
  console.log(data.otp);   // → "482193"
}

Run it in your E2E suite

There's a ready-to-copy Playwright example that fills a signup form with a mailsocket address and awaits the OTP — see examples/playwright/otp-signup.spec.ts in this repository. It reads MAILSOCKET_API_KEY and MAILSOCKET_INBOX_ID from the environment.

More references