{"components":{"schemas":{"BulkRequest":{"properties":{"tokens":{"items":{"type":"string"},"maxItems":10,"minItems":1,"type":"array"}},"required":["tokens"],"type":"object"},"Error":{"properties":{"error":{"properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"type":"object"}},"required":["error"],"type":"object"},"Link":{"properties":{"label":{"type":"string"},"url":{"format":"uri","type":"string"}},"required":["label","url"],"type":"object"},"ListResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MessageSummary"},"type":"array"},"meta":{"properties":{"cached":{"type":"boolean"},"fetched_at":{"type":"string"},"has_more":{"type":"boolean"},"returned":{"type":"integer"},"window":{"type":"integer"}},"type":"object"}},"required":["data","meta"],"type":"object"},"Mailbox":{"properties":{"email":{"format":"email","type":"string"},"id":{"format":"uuid","type":"string"}},"required":["id","email"],"type":"object"},"MessageBody":{"allOf":[{"$ref":"#/components/schemas/MessageSummary"},{"properties":{"blocks":{"items":{"properties":{"runs":{"items":{"properties":{"bold":{"type":"boolean"},"href":{"type":"string"},"italic":{"type":"boolean"},"text":{"type":"string"}},"type":"object"},"type":"array"},"type":{"enum":["paragraph","heading","list-item","pre"],"type":"string"}},"type":"object"},"type":"array"},"images_blocked":{"type":"integer"},"links":{"items":{"$ref":"#/components/schemas/Link"},"type":"array"},"text":{"type":"string"},"truncated":{"type":"boolean"}},"type":"object"}]},"MessageSummary":{"properties":{"address":{"type":"string"},"code":{"nullable":true,"type":"string"},"date":{"type":"string"},"epoch":{"type":"string"},"from":{"type":"string"},"sender":{"type":"string"},"snippet":{"type":"string"},"subject":{"type":"string"},"uid":{"type":"string"}},"required":["uid","epoch","subject","from","date","snippet"],"type":"object"},"TokenRequest":{"oneOf":[{"not":{"required":["mailbox_id"]},"required":["email"]},{"not":{"required":["email"]},"required":["mailbox_id"]}],"properties":{"email":{"type":"string"},"mailbox_id":{"type":"string"},"password":{"format":"password","maxLength":128,"type":"string"}},"required":["password"],"type":"object"},"TokenResponse":{"properties":{"access_token":{"type":"string"},"expires_in":{"example":3600,"type":"integer"},"mailbox":{"$ref":"#/components/schemas/Mailbox"},"scope":{"enum":["mail:read"],"type":"string"},"token_type":{"enum":["Bearer"],"type":"string"}},"required":["access_token","token_type","expires_in","scope","mailbox"],"type":"object"}},"securitySchemes":{"mailboxBearer":{"description":"Token returned by POST /api/v1/token.","scheme":"bearer","type":"http"}}},"info":{"description":"Mailbox-scoped read-only API. Tokens expire after 3600 seconds and are revoked by password changes. 120 reads/token/minute, 300 IP credits/minute; bulk costs 10 IP credits. Poll every 10 seconds or slower. One shared inbox via IMAP or Gmail HTTPS API; INBOX only. Gmail message UIDs have a g_ prefix; since_uid is IMAP-only.","title":"Mailread API","version":"1.0.0"},"openapi":"3.0.3","paths":{"/api/v1/bulk/messages":{"post":{"description":"Read up to ten mailboxes in one request. Every mailbox must have its own valid token; a token cannot authorize another mailbox. Results preserve input order, with per-item errors.\n\nHTTP 200 can contain successful and failed items. Each token consumes one read from its quota. A batch consumes ten IP request credits. All tokens and credentials stay out of URLs.","operationId":"bulk","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"results":[{"data":[{"address":"hello@example.com","code":"123456","date":"2026-10-23T10:00:00+00:00","epoch":"100","from":"Example <hello@example.com>","sender":"Example","snippet":"Your verification code is 123456.","subject":"Your verification code","uid":"42"}],"index":0,"mailbox":{"email":"you@example.com","id":"11111111-1111-4111-8111-111111111111"},"meta":{"cached":false,"fetched_at":"2026-10-23T10:00:00+00:00"}},{"error":{"code":"invalid_token","message":"A valid mailbox Bearer token is required."},"index":1}]},"schema":{"properties":{"results":{"items":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MessageSummary"},"type":"array"},"error":{"properties":{"code":{"type":"string"},"message":{"type":"string"}},"type":"object"},"index":{"type":"integer"},"mailbox":{"$ref":"#/components/schemas/Mailbox"},"meta":{"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[],"summary":"Read multiple authorized mailboxes","tags":["Mail"]}},"/api/v1/health":{"get":{"description":"Checks the web process, not upstream mail-provider connectivity. It does not reveal configuration or mailbox counts.\n\n","operationId":"health","responses":{"200":{"content":{"application/json":{"example":{"api_version":"1","status":"ok"},"schema":{"properties":{"api_version":{"type":"string"},"status":{"type":"string"}},"type":"object"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[],"summary":"Check application health","tags":["Mail"]}},"/api/v1/latest":{"get":{"description":"Returns the newest summary, or {\"data\":null} with HTTP 200 when nothing matches.\n\n","operationId":"latest","parameters":[{"description":"Case-insensitive substring within recent messages.","in":"query","name":"search","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"sender","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"subject","schema":{"maxLength":200,"type":"string"}},{"description":"IMAP-only exclusive minimum UID; reset when epoch changes. Unsupported with Gmail API.","in":"query","name":"since_uid","schema":{"pattern":"^[0-9]{1,20}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address":"hello@example.com","code":"123456","date":"2026-10-23T10:00:00+00:00","epoch":"100","from":"Example <hello@example.com>","sender":"Example","snippet":"Your verification code is 123456.","subject":"Your verification code","uid":"42"}},"schema":{"properties":{"data":{"nullable":true,"properties":{"address":{"type":"string"},"code":{"nullable":true,"type":"string"},"date":{"type":"string"},"epoch":{"type":"string"},"from":{"type":"string"},"sender":{"type":"string"},"snippet":{"type":"string"},"subject":{"type":"string"},"uid":{"type":"string"}},"required":["uid","epoch","subject","from","date","snippet"],"type":"object"}},"required":["data"],"type":"object"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[{"mailboxBearer":[]}],"summary":"Get the newest matching message","tags":["Mail"]}},"/api/v1/links":{"get":{"description":"Reads the newest matching message body and returns visible, deduplicated HTTP(S) links without visiting them.\n\nNo matching mail returns {\"data\":{\"uid\":null,\"links\":[]}} with HTTP 200.","operationId":"links","parameters":[{"description":"Case-insensitive substring within recent messages.","in":"query","name":"search","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"sender","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"subject","schema":{"maxLength":200,"type":"string"}},{"description":"IMAP-only exclusive minimum UID; reset when epoch changes. Unsupported with Gmail API.","in":"query","name":"since_uid","schema":{"pattern":"^[0-9]{1,20}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"links":[{"label":"Continue verification","url":"https://example.com/verify?token=demo"}],"uid":"42"}},"schema":{"properties":{"data":{"properties":{"links":{"items":{"$ref":"#/components/schemas/Link"},"type":"array"},"uid":{"nullable":true,"type":"string"}},"type":"object"}},"type":"object"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[{"mailboxBearer":[]}],"summary":"Read links from the latest email","tags":["Mail"]}},"/api/v1/mailbox":{"get":{"description":"Returns only the mailbox authorized by the token. There is no endpoint that lists other users\u2019 mailboxes.\n\n","operationId":"mailbox","responses":{"200":{"content":{"application/json":{"example":{"data":{"email":"you@example.com","id":"11111111-1111-4111-8111-111111111111"}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/Mailbox"}},"required":["data"],"type":"object"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[{"mailboxBearer":[]}],"summary":"Identify the authorized mailbox","tags":["Mail"]}},"/api/v1/messages":{"get":{"description":"Newest-first summaries from the latest 30 provider search candidates, after exact-recipient filtering. This is a recent-mail window, not a complete mailbox export.\n\nFilters apply within the 30-message window. has_more means upstream search returned over 30 candidates; it does not expose a pagination cursor. Message data is cached in RAM for up to five seconds.","operationId":"messages","parameters":[{"description":"Case-insensitive substring within recent messages.","in":"query","name":"search","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"sender","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"subject","schema":{"maxLength":200,"type":"string"}},{"description":"IMAP-only exclusive minimum UID; reset when epoch changes. Unsupported with Gmail API.","in":"query","name":"since_uid","schema":{"pattern":"^[0-9]{1,20}$","type":"string"}},{"in":"query","name":"limit","schema":{"default":30,"maximum":30,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"address":"hello@example.com","code":"123456","date":"2026-10-23T10:00:00+00:00","epoch":"100","from":"Example <hello@example.com>","sender":"Example","snippet":"Your verification code is 123456.","subject":"Your verification code","uid":"42"}],"meta":{"cached":false,"fetched_at":"2026-10-23T10:00:00+00:00","has_more":false,"returned":1,"window":30}},"schema":{"$ref":"#/components/schemas/ListResponse"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[{"mailboxBearer":[]}],"summary":"List recent mail","tags":["Mail"]}},"/api/v1/messages/{uid}":{"get":{"description":"Returns normalized text, safe structured blocks, visible HTTP(S) links and an image-blocking count. The UID and epoch must come from this mailbox\u2019s message list.\n\nImages, scripts, attachments and original sender HTML are never returned for rendering. IMAP reads the first 1 MiB of MIME. Gmail transfers at most 4 MiB of JSON and decodes up to 1 MiB of text, falling back to a snippet when oversized. Previews are limited to 200,000 characters/2,000 blocks; truncated=true indicates a bounded preview. Opened content is cached in RAM for up to two minutes.","operationId":"message","parameters":[{"in":"path","name":"uid","required":true,"schema":{"pattern":"^(?:[1-9][0-9]{0,19}|g_[A-Za-z0-9_-]{1,128})$","type":"string"}},{"in":"query","name":"epoch","required":true,"schema":{"pattern":"^[0-9]{1,20}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"address":"hello@example.com","blocks":[{"runs":[{"text":"Your verification code is 123456."}],"type":"paragraph"}],"code":"123456","date":"2026-10-23T10:00:00+00:00","epoch":"100","from":"Example <hello@example.com>","images_blocked":1,"links":[],"sender":"Example","snippet":"Your verification code is 123456.","subject":"Your verification code","text":"Your verification code is 123456.","truncated":false,"uid":"42"}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/MessageBody"}},"required":["data"],"type":"object"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[{"mailboxBearer":[]}],"summary":"Read a message","tags":["Mail"]}},"/api/v1/otp":{"get":{"description":"Finds the newest detected numeric verification code among the recent summaries, fetching up to five message bodies when snippets do not contain a code. Detection is heuristic, not proof of authenticity.\n\nJSON returns data:null with HTTP 200 when no code is detected. format=text returns just the code (200), or an empty response (204). This reads codes from mail; it does not generate TOTP codes from a 2FA secret.","operationId":"otp","parameters":[{"description":"Case-insensitive substring within recent messages.","in":"query","name":"search","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"sender","schema":{"maxLength":200,"type":"string"}},{"description":"Case-insensitive substring within recent messages.","in":"query","name":"subject","schema":{"maxLength":200,"type":"string"}},{"description":"IMAP-only exclusive minimum UID; reset when epoch changes. Unsupported with Gmail API.","in":"query","name":"since_uid","schema":{"pattern":"^[0-9]{1,20}$","type":"string"}},{"in":"query","name":"format","schema":{"default":"json","enum":["json","text"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"code":"123456","date":"2026-10-23T10:00:00+00:00","epoch":"100","uid":"42"}},"schema":{"properties":{"data":{"nullable":true,"properties":{"code":{"type":"string"},"date":{"type":"string"},"epoch":{"type":"string"},"uid":{"type":"string"}},"type":"object"}},"type":"object"}},"text/plain":{"example":"123456","schema":{"type":"string"}}},"description":"Success; see endpoint notes for empty results."},"204":{"description":"No code; only when format=text."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[{"mailboxBearer":[]}],"summary":"Extract a recent email code","tags":["Mail"]}},"/api/v1/token":{"post":{"description":"Exchange an email address (or mailbox_id from its reading URL) and website password for a read-only Bearer token. The token expires after one hour. Password changes invalidate existing tokens.\n\nNo cookies or CSRF token are needed for /api/v1. POST requests require application/json. Never put passwords or tokens in a URL.","operationId":"token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"access_token":"YOUR_MAILBOX_TOKEN","expires_in":3600,"mailbox":{"email":"you@example.com","id":"11111111-1111-4111-8111-111111111111"},"scope":"mail:read","token_type":"Bearer"},"schema":{"$ref":"#/components/schemas/TokenResponse"}}},"description":"Success; see endpoint notes for empty results."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid, expired or revoked token / incorrect credentials"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Message not found"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Body exceeds 128 KiB"},"415":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"JSON content type required"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limited"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unexpected server error"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Mail provider temporarily unavailable"}},"security":[],"summary":"Get a mailbox token","tags":["Authentication"]}}},"servers":[{"url":"/"}]}
