{"openapi":"3.1.0","info":{"title":"api.email","version":"1.0.0","description":"Disposable inboxes for automated tests and coding agents. Create a namespace, receive mail at any address under it, and read it back over REST or MCP."},"servers":[{"url":"https://api.email"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key from POST /v1/signup or POST /v1/keys, sent as \"Authorization: Bearer ae_...\"."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"hint":{"type":"string"}},"required":["code","message","hint"]}},"required":["error"]},"Message":{"type":"object","properties":{"id":{"type":"string"},"namespace":{"type":"string"},"tag":{"type":"string"},"address":{"type":"string"},"from":{"type":"object","properties":{"address":{"type":"string"},"name":{"type":"string"}},"required":["address","name"]},"to":{"type":"array","items":{"type":"string"}},"subject":{"type":"string"},"text":{"type":"string"},"html":{"type":["string","null"]},"extracted":{"type":"object","properties":{"otp_codes":{"type":"array","items":{"type":"string"}},"links":{"type":"array","items":{"type":"string"}},"verification_links":{"type":"array","items":{"type":"string"}}},"required":["otp_codes","links","verification_links"]},"received_at":{"type":"string","format":"date-time"},"expire_at":{"type":"string","format":"date-time"},"attachments":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"filename":{"type":"string"},"content_type":{"type":"string"},"size":{"type":"integer"}},"required":["index","filename","content_type","size"]}},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Only present on GET /v1/messages/{id}?headers=true."}},"required":["id","namespace","tag","address","from","to","subject","text","html","extracted","received_at","expire_at","attachments"]}}},"paths":{"/v1/signup":{"post":{"summary":"Create an account","description":"Creates a free-plan account, a namespace, and an API key. No authentication required.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"201":{"description":"Account created.","content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string"},"namespace":{"type":"string"},"api_key":{"type":"string","description":"Shown only once."},"plan":{"type":"string","enum":["free"]},"example_address":{"type":"string"},"docs":{"type":"string"},"hint":{"type":"string"}},"required":["account_id","namespace","api_key","plan","example_address","docs","hint"]}}}},"400":{"description":"email was present but not a valid address.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited: max 10 signups/hour per IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/messages":{"get":{"summary":"List messages","security":[{"bearerAuth":[]}],"parameters":[{"name":"namespace","in":"query","required":false,"description":"Restrict results to one namespace slug.","schema":{"type":"string"}},{"name":"tag","in":"query","required":false,"description":"Exact match on the tag (the local part before @).","schema":{"type":"string"}},{"name":"tag_prefix","in":"query","required":false,"description":"Prefix match on tag; ignored if \"tag\" is also set.","schema":{"type":"string"}},{"name":"since","in":"query","required":false,"description":"Only messages received after this time: epoch milliseconds or an ISO 8601 timestamp.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Max results, 1-100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},{"name":"offset","in":"query","required":false,"description":"Pagination offset.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Messages, newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"count":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["messages","count","limit","offset"]}}}},"400":{"description":"\"since\" could not be parsed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/messages/{id}":{"get":{"summary":"Get one message","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Message id, from GET /v1/messages.","schema":{"type":"string"}},{"name":"headers","in":"query","required":false,"description":"Pass \"true\" to include the raw email headers.","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"The message.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"$ref":"#/components/schemas/Message"}},"required":["message"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such message, or it belongs to another account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a message","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Message id, from GET /v1/messages.","schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/messages/{id}/attachments/{n}":{"get":{"summary":"Download an attachment","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Message id.","schema":{"type":"string"}},{"name":"n","in":"path","required":true,"description":"Zero-based index into the message's \"attachments\" array.","schema":{"type":"integer"}}],"responses":{"200":{"description":"The attachment bytes, with the original content-type and a content-disposition header.","content":{"*/*":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such message, or no attachment at that index.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/wait":{"get":{"summary":"Long-poll for the next message","security":[{"bearerAuth":[]}],"parameters":[{"name":"namespace","in":"query","required":false,"description":"Restrict results to one namespace slug.","schema":{"type":"string"}},{"name":"tag","in":"query","required":false,"description":"Exact match on the tag (the local part before @).","schema":{"type":"string"}},{"name":"tag_prefix","in":"query","required":false,"description":"Prefix match on tag; ignored if \"tag\" is also set.","schema":{"type":"string"}},{"name":"since","in":"query","required":false,"description":"Only messages received after this time: epoch milliseconds or an ISO 8601 timestamp.","schema":{"type":"string"}},{"name":"timeout","in":"query","required":false,"description":"Seconds to wait, 1-55 (default 30).","schema":{"type":"integer","minimum":1,"maximum":55,"default":30}}],"responses":{"200":{"description":"A message arrived, or the wait timed out.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"anyOf":[{"$ref":"#/components/schemas/Message"},{"type":"null"}]},"timed_out":{"type":"boolean"},"hint":{"type":"string","description":"Present only when timed_out is true."}},"required":["message","timed_out"]}}}},"400":{"description":"\"since\" could not be parsed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/namespaces":{"get":{"summary":"List namespaces","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Namespaces on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"namespaces":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"domain":{"type":"string"},"created_at":{"type":"string","format":"date-time"}},"required":["slug","domain","created_at"]}}},"required":["namespaces"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a namespace","security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","description":"Omit for a random slug."}}}}}},"responses":{"201":{"description":"Namespace created.","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"domain":{"type":"string"}},"required":["slug","domain"]}}}},"400":{"description":"Invalid slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Your plan's namespace limit is already used.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"That slug is already taken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/keys":{"get":{"summary":"List API keys","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Keys on this account (prefixes only; never the key itself).","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"prefix":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"revoked_at":{"type":["string","null"],"format":"date-time"}},"required":["id","prefix","created_at","revoked_at"]}}},"required":["keys"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create an API key","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Key created.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"api_key":{"type":"string","description":"Shown only once."},"prefix":{"type":"string"},"hint":{"type":"string"}},"required":["id","api_key","prefix","hint"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key hash collision (extremely rare); retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/keys/{id}":{"delete":{"summary":"Revoke an API key","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Key id, from GET /v1/keys.","schema":{"type":"string"}}],"responses":{"200":{"description":"Revoked (idempotent if already revoked).","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean","enum":[true]}},"required":["revoked"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Cannot revoke your only active key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage":{"get":{"summary":"Usage and plan limits","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current month usage and plan limits.","content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","enum":["free","dev","pro"]},"month":{"type":"string","description":"YYYY-MM"},"emails_received":{"type":"integer"},"limits":{"type":"object","properties":{"emails_per_month":{"type":"integer"},"namespaces":{"type":"integer"},"retention_days":{"type":"integer"}},"required":["emails_per_month","namespaces","retention_days"]}},"required":["plan","month","emails_received","limits"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/checkout":{"post":{"summary":"Start a Stripe Checkout session to upgrade plan","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","enum":["dev","pro"]},"email":{"type":"string","format":"email","description":"Required only if the account has no email on file yet."}},"required":["plan"]}}}},"responses":{"200":{"description":"Checkout session URL.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]}}}},"400":{"description":"Invalid plan, missing email, or a subscription already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Billing is not configured on this server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/portal":{"post":{"summary":"Open the Stripe billing portal","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Billing portal session URL.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]}}}},"400":{"description":"No Stripe customer yet; call /v1/billing/checkout first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Billing is not configured on this server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/stripe/webhook":{"post":{"summary":"Stripe webhook receiver (called by Stripe, not by API clients)","description":"Verifies the \"stripe-signature\" header against STRIPE_WEBHOOK_SECRET and applies plan changes. Not part of the public API surface.","security":[],"parameters":[{"name":"stripe-signature","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Acknowledged.","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean","enum":[true]}},"required":["received"]}}}},"400":{"description":"Invalid signature.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Webhook is not configured on this server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}