---
title: "Wait for an OTP or magic link"
method: GET
path: "/inboxes/{id}/messages/wait"
tags: ["messages"]
---

# Wait for an OTP or magic link

`GET /inboxes/{id}/messages/wait`

## Request

- Base URL: `https://dash.mailsocket.app/api/v1`
- URL: `https://dash.mailsocket.app/api/v1/inboxes/{id}/messages/wait`
- Auth: HTTP bearer

Blocks until a matching parsed message arrives, or returns empty when the
window elapses. This is the "one call, wait for the code" primitive.

- `timeout`: seconds to block (default 20, clamped to `[1, 25]`).
- `since`: only messages received strictly after this point match.
  Accepted forms: an ISO-8601 datetime, a message `public_id` (resolved
  to that owned message's `received_at`), or a unix timestamp (seconds;
  values ≥ 1e12 are treated as milliseconds). Default: the request start
  time. Pass `since=0` (the epoch) to mean "match messages already in
  the inbox".
- `require`: `otp` (default) | `link` | `any`. Any other value is
  rejected with `422 validation_error` (`fields.require` lists the
  allowed values); it is never silently coerced.
- `min_confidence`: float, default 0.0; an OTP must have
  `otp_confidence >= min_confidence`. Clamped to `[0, 1]`. Ignored for
  `require=link`.

Waiting in a loop: every `200` and `204` carries a
`Mailsocket-Wait-Since` header with the cutoff this call used (your
`since`, or the request start). Pass this back as `since` on your next
wait call to never miss a message. Without it, each new call starts a
fresh cutoff, so a message that arrives between two calls is skipped.

A single wait occupies one gthread worker for up to `timeout` seconds.
Concurrency is bounded by a per-account cap and a global cap, surfaced
as the two distinct `429` codes below.

## Path parameters

- `id` string, required

## Query parameters

- `timeout` number
- `since` string
- `require` 'otp' | 'link' | 'any'
- `min_confidence` number

## Response `200`

A matching parsed message arrived.

- object
  - `data` Message, required: Full message representation: `MessageSummary` minus `has_html`, plus `envelope_from`, `envelope_recipient`, `text` and `html`.
    - `id` string, required
    - `inbox_id` string, required
    - `from` string, required: The From header.
    - `to` string[], required
    - `cc` string[], required
    - `subject` string, required
    - `received_at` string, date-time, required
    - `status` 'received' | 'parsing' | 'parsed' | 'failed', required
    - `otp` string, nullable
    - `otp_confidence` number, nullable
    - `magic_link` string, nullable
    - `links` string[], nullable
    - `detected_otp` string, nullable
    - `otp_context` string, nullable: A short (≤160 character) plain-text snippet around `otp`; null when no OTP or not locatable.
    - `otp_candidates` object[], nullable: Ranked plausible codes beyond the primary `otp`; null/empty when only one or none.
      - `code` string, required
      - `confidence` number, required
    - `provider_hint` string, nullable: Best-effort sending-service label from the From domain; null when unknown.
    - `envelope_from` string, required
    - `envelope_recipient` string, required
    - `text` string, required: The plain-text body.
    - `html` string, required: The sanitized HTML body.
    - `read` boolean: Whether the message has been marked read (`read_at IS NOT NULL`).
    - `metadata` object, required: The owning inbox's `metadata` (`{}` when unset). Present in poll/latest/wait/batch fetch AND the webhook delivery payload (which is this exact schema).

## Other responses

- `204`: Waited, nothing matched yet; call again. Success, not an error. Send the `Mailsocket-Wait-Since` value back as `since` on that next call.
- `401`: Missing or invalid API key.
- `403`: Account is not permitted to use the API.
- `404`: Resource not found (unknown or not owned).
- `422`: Request validation failed (malformed body or invalid parameter).
- `429`: Concurrent-wait cap exhausted. Two distinct codes: `too_many_wait_requests` (your plan's per-account cap) and `wait_capacity` (service-wide cap). A slot frees when a wait returns, times out, or the client disconnects. Retry after the number of seconds in `Retry-After`.

---

[API](https://skmtc.dev/mailsocket/apis/mailsocket-api.md) · [All operations](https://skmtc.dev/mailsocket/apis/mailsocket-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mailsocket/apis/mailsocket-api/revisions/e579500dfb7e?raw)
