openapi: 3.0.3
info:
  title: Mail.td API
  version: "2.0.0"
  description: |
    Temp mail platform for developer email testing. Create test inboxes, receive emails via REST API, and automate email testing in CI/CD pipelines.

    ## Quick Start

    1. `POST /api/accounts` — create a mailbox (returns an account ID)
    2. `GET /api/accounts/{account_id}/messages` — fetch emails

    ## Authentication

    All authenticated endpoints require: `Authorization: Bearer <token>`

    Use a **Pro API Token** (prefixed with `td_`) for all API requests. Sign in with Google or GitHub at [mail.td/pro/login](https://mail.td/pro/login) and create a token in the [Pro Dashboard](https://mail.td/pro/dashboard).

    Invalid tokens return `401` with `{"error": "invalid_or_expired_token"}`.

    ## Pagination

    List endpoints return up to 30 items per page. If fewer than 30 items are returned, you've reached the last page.

    ## Rate Limits

    - Mailbox creation: 1 request per second per authenticated user or anonymous IP.
    - All other API routes: 10 requests per second per authenticated user or anonymous IP.

    ## Full Documentation

    [docs.mail.td](https://docs.mail.td)

servers:
  - url: https://api.mail.td

tags:
  - name: Domains
    description: List available email domains
  - name: Accounts
    description: Create and manage email accounts
  - name: Pro User
    description: Pro user profile and account management
  - name: Pro Accounts
    description: Pro mailbox management
  - name: Pro Domains
    description: Pro custom domain management
  - name: Pro Webhooks
    description: Pro webhook management
  - name: Pro Tokens
    description: Pro API token management

paths:
  # ──────────────────────────────────────────────
  # Public API
  # ──────────────────────────────────────────────

  /api/domains:
    get:
      tags: [Domains]
      summary: List available domains
      operationId: listDomains
      responses:
        "200":
          description: List of available domains
          content:
            application/json:
              schema:
                type: object
                properties:
                  domains:
                    type: array
                    items:
                      $ref: "#/components/schemas/Domain"

  /api/accounts:
    post:
      tags: [Accounts]
      summary: Create a new email address
      operationId: createAccount
      description: |
        Create a new mailbox on any available system domain. Requires a valid API token.

        Pro users can create mailboxes on both system domains and verified custom domains.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [address, password]
              properties:
                address:
                  type: string
                  format: email
                  example: user@mail.td
                password:
                  type: string
                  description: Mailbox password (min 6 characters)
                  example: mypassword123
      responses:
        "201":
          description: Email address created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  address:
                    type: string
                    format: email
        "400":
          description: Validation error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: Mailbox limit reached or access denied
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "409":
          description: Address already taken
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "429":
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  # ──────────────────────────────────────────────
  # Account-Scoped API
  # ──────────────────────────────────────────────

  /api/accounts/{account_id}:
    get:
      tags: [Accounts]
      summary: Get mailbox info
      operationId: getAccount
      description: Returns mailbox details. Pro users can access any mailbox they own.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
      responses:
        "200":
          description: Mailbox details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccountInfo"
        "404":
          description: Account not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    delete:
      tags: [Accounts]
      summary: Delete email address
      operationId: deleteAccount
      description: Permanently deletes the mailbox and all emails. Pro users must have active subscription.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
      responses:
        "204":
          description: Email address and all messages deleted
        "402":
          description: Subscription expired (Pro users)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/accounts/{account_id}/reset-password:
    put:
      tags: [Accounts]
      summary: Reset mailbox password
      operationId: resetAccountPassword
      description: Resets the mailbox password and invalidates all existing tokens.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
                  description: New mailbox password
      responses:
        "200":
          description: Password reset
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: password_reset
        "400":
          description: Validation error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/accounts/{account_id}/messages:
    get:
      tags: [Accounts]
      summary: List messages
      operationId: listMessages
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
        - name: page
          in: query
          schema:
            type: integer
            default: 1
            minimum: 1
      responses:
        "200":
          description: Paginated message list
          content:
            application/json:
              schema:
                type: object
                properties:
                  messages:
                    type: array
                    items:
                      $ref: "#/components/schemas/EmailSummary"
                  page:
                    type: integer
    delete:
      tags: [Accounts]
      summary: Clear an inbox
      operationId: clearMessages
      description: Deletes all messages while keeping the mailbox active.
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
      responses:
        "200":
          description: Inbox cleared
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted:
                    type: integer
                    format: int64
                  reclaimed_bytes:
                    type: integer
                    format: int64

  /api/accounts/{account_id}/messages/read:
    put:
      tags: [Accounts]
      summary: Batch mark messages as read
      operationId: batchMarkAsRead
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: Message IDs to mark as read (max 200)
                all:
                  type: boolean
                  description: Mark all unread messages as read
      responses:
        "200":
          description: Messages marked as read
          content:
            application/json:
              schema:
                type: object
                properties:
                  updated:
                    type: integer
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/accounts/{account_id}/messages/{id}:
    get:
      tags: [Accounts]
      summary: Get a single message
      operationId: getMessage
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Full message detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailDetail"
        "404":
          description: Message not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "410":
          description: Message expired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    delete:
      tags: [Accounts]
      summary: Delete a message
      operationId: deleteMessage
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Message deleted
        "404":
          description: Message not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/accounts/{account_id}/messages/{id}/source:
    get:
      tags: [Accounts]
      summary: Download raw EML source
      operationId: getMessageSource
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Raw email source
          content:
            message/rfc822:
              schema:
                type: string
                format: binary
        "404":
          description: Message not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "410":
          description: Message expired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/accounts/{account_id}/messages/{id}/read:
    put:
      tags: [Accounts]
      summary: Mark message as read
      operationId: markAsRead
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Message marked as read (idempotent)

  /api/accounts/{account_id}/messages/{id}/attachments/{index}:
    get:
      tags: [Accounts]
      summary: Download an attachment
      operationId: getAttachment
      security:
        - BearerAuth: []
      parameters:
        - $ref: "#/components/parameters/AccountId"
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: index
          in: path
          required: true
          schema:
            type: integer
            minimum: 0
      responses:
        "200":
          description: Attachment binary
          headers:
            Content-Disposition:
              schema:
                type: string
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "410":
          description: Message expired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  # ──────────────────────────────────────────────
  # Pro User Management
  # ──────────────────────────────────────────────

  /api/user/me:
    get:
      tags: [Pro User]
      summary: Get Pro user profile
      operationId: proGetMe
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Pro user details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProUser"

  /api/user/accounts:
    get:
      tags: [Pro Accounts]
      summary: List mailboxes under Pro account
      operationId: proListAccounts
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of mailboxes
          content:
            application/json:
              schema:
                type: object
                properties:
                  accounts:
                    type: array
                    items:
                      $ref: "#/components/schemas/Account"
                  next_cursor:
                    type: string
                    description: Cursor for the next page. Empty string if no more results.

  /api/user/accounts/{id}:
    delete:
      tags: [Pro Accounts]
      summary: Delete a mailbox
      operationId: proDeleteAccount
      description: Requires active subscription status.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Mailbox and all its emails deleted

  /api/user/accounts/{id}/reset-password:
    put:
      tags: [Pro Accounts]
      summary: Reset a mailbox password
      operationId: proResetAccountPassword
      description: Requires active subscription status. Invalidates all existing tokens for the mailbox.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
                  description: New mailbox password
      responses:
        "200":
          description: Password reset
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: password_reset
        "400":
          description: Validation error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          description: Mailbox not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/user/accounts/{id}/messages:
    get:
      tags: [Pro Accounts]
      summary: List messages for a mailbox
      operationId: proListAccountMessages
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: page
          in: query
          schema:
            type: integer
            default: 1
            minimum: 1
      responses:
        "200":
          description: Paginated message list
          content:
            application/json:
              schema:
                type: object
                properties:
                  messages:
                    type: array
                    items:
                      $ref: "#/components/schemas/EmailSummary"
                  page:
                    type: integer
        "404":
          description: Account not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  # ──────────────────────────────────────────────
  # Pro Domains
  # ──────────────────────────────────────────────

  /api/user/domains:
    get:
      tags: [Pro Domains]
      summary: List custom domains
      operationId: proListDomains
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of custom domains
          content:
            application/json:
              schema:
                type: object
                properties:
                  domains:
                    type: array
                    items:
                      $ref: "#/components/schemas/ProDomain"
    post:
      tags: [Pro Domains]
      summary: Add a custom domain
      operationId: proCreateDomain
      description: Requires active subscription status.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [domain]
              properties:
                domain:
                  type: string
                  example: custom.com
      responses:
        "201":
          description: Domain added with DNS instructions
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  domain:
                    type: string
                  verify_token:
                    type: string
                  dns_records:
                    type: array
                    items:
                      $ref: "#/components/schemas/DNSRecord"
        "400":
          description: Validation error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: Domain limit reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "409":
          description: Domain already registered
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/user/domains/{id}/verify:
    post:
      tags: [Pro Domains]
      summary: Verify domain DNS configuration
      operationId: proVerifyDomain
      description: Requires active subscription status. Verification expires after 72 hours.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Verification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  verify_status:
                    type: string
                    enum: [verified, pending]
                  txt_record:
                    type: boolean
                  mx_record:
                    type: boolean
                  dns_records:
                    type: array
                    description: Present when status is pending
                    items:
                      allOf:
                        - $ref: "#/components/schemas/DNSRecord"
                        - type: object
                          properties:
                            ok:
                              type: boolean
        "404":
          description: Domain not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "410":
          description: Verification expired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/user/domains/{id}:
    delete:
      tags: [Pro Domains]
      summary: Delete a custom domain
      operationId: proDeleteDomain
      description: Requires active subscription status.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Domain deleted
        "404":
          description: Domain not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  # ──────────────────────────────────────────────
  # Pro Webhooks
  # ──────────────────────────────────────────────

  /api/user/webhooks:
    get:
      tags: [Pro Webhooks]
      summary: List webhooks
      operationId: proListWebhooks
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of webhooks
          content:
            application/json:
              schema:
                type: object
                properties:
                  webhooks:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        url:
                          type: string
                          format: uri
                        events:
                          type: array
                          items:
                            type: string
                        status:
                          type: string
                          enum: [active, disabled]
                        failure_count:
                          type: integer
                        last_triggered_at:
                          type: string
                          format: date-time
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
    post:
      tags: [Pro Webhooks]
      summary: Create a webhook
      operationId: proCreateWebhook
      description: |
        Requires active subscription status. Maximum 1 webhook per user.
        `email.received` includes the complete text and HTML bodies for normal-size
        messages plus attachment metadata and authenticated download paths. Attachment
        bytes, raw EML, and internal storage identifiers are never included. The final
        event is capped at 1,000,000 bytes; `content_truncated` and
        `attachments_omitted` describe any reduction. `content_status: ready`
        guarantees loaded body fields; `failed` and `pending_timeout` are explicit
        metadata-only fallbacks.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  format: uri
                  description: Must be HTTPS
                events:
                  type: array
                  items:
                    type: string
                  default: ["email.received"]
                  example: ["email.received"]
      callbacks:
        emailReceived:
          '{$request.body#/url}':
            post:
              summary: Receive an email.received event
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/EmailReceivedEvent"
              responses:
                "2XX":
                  description: Event accepted
      responses:
        "201":
          description: Webhook created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
        "400":
          description: Validation error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: Webhook limit reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/user/webhooks/{id}:
    delete:
      tags: [Pro Webhooks]
      summary: Delete a webhook
      operationId: proDeleteWebhook
      description: Requires active subscription status.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Webhook deleted
        "404":
          description: Webhook not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/user/webhooks/{id}/rotate:
    post:
      tags: [Pro Webhooks]
      summary: Rotate webhook secret
      operationId: proRotateWebhookSecret
      description: Requires active subscription status. Also resets failure count and sets status to active.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: New secret generated
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  secret:
                    type: string
                    example: whsec_new...
        "404":
          description: Webhook not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/user/webhooks/{id}/deliveries:
    get:
      tags: [Pro Webhooks]
      summary: List webhook deliveries
      operationId: proListWebhookDeliveries
      description: Returns the last 20 delivery attempts.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: List of delivery attempts
          content:
            application/json:
              schema:
                type: object
                properties:
                  deliveries:
                    type: array
                    items:
                      $ref: "#/components/schemas/WebhookDelivery"
        "404":
          description: Webhook not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  # ──────────────────────────────────────────────
  # Pro Tokens
  # ──────────────────────────────────────────────

  /api/user/tokens:
    get:
      tags: [Pro Tokens]
      summary: List API tokens
      operationId: proListTokens
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of API tokens
          content:
            application/json:
              schema:
                type: object
                properties:
                  tokens:
                    type: array
                    items:
                      $ref: "#/components/schemas/Token"
    post:
      tags: [Pro Tokens]
      summary: Create an API token
      operationId: proCreateToken
      description: Requires active subscription status.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  default: API Token
                  example: My Token
      responses:
        "201":
          description: Token created (secret shown only once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
                  token:
                    type: string
                    description: "Prefixed with td_. Only returned on creation."
                    example: td_...

  /api/user/tokens/{id}:
    delete:
      tags: [Pro Tokens]
      summary: Revoke an API token
      operationId: proDeleteToken
      description: Requires active subscription status.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Token revoked
        "404":
          description: Token not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

components:
  parameters:
    AccountId:
      name: account_id
      in: path
      required: true
      description: Account identifier. Accepts a UUID or the full email address (e.g. demo@mail.td).
      schema:
        type: string

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: Pro API token (td_...) for all API endpoints.

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Machine-readable error code

    AccountInfo:
      type: object
      properties:
        id:
          type: string
          format: uuid
        address:
          type: string
          format: email
        role:
          type: string
          example: user
        quota:
          type: integer
          example: 41943040
        used:
          type: integer
          example: 12345
        created_at:
          type: string
          format: date-time

    EmailSummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
        sender:
          type: string
          format: email
        from:
          type: string
          nullable: true
          description: "Display name and address, e.g. Name <a@b.com>"
        subject:
          type: string
          nullable: true
        preview_text:
          type: string
          nullable: true
        size:
          type: integer
        is_read:
          type: boolean
        created_at:
          type: string
          format: date-time

    EmailDetail:
      type: object
      properties:
        id:
          type: string
          format: uuid
        sender:
          type: string
        from:
          type: string
          nullable: true
        subject:
          type: string
          nullable: true
        address:
          type: string
          format: email
        size:
          type: integer
        created_at:
          type: string
          format: date-time
        text_body:
          type: string
          nullable: true
        html_body:
          type: string
          nullable: true
        attachments:
          type: array
          items:
            $ref: "#/components/schemas/Attachment"

    Attachment:
      type: object
      properties:
        index:
          type: integer
        filename:
          type: string
        content_type:
          type: string
        size:
          type: integer

    Account:
      type: object
      properties:
        id:
          type: string
          format: uuid
        address:
          type: string
          format: email
        quota:
          type: integer
          example: 52428800
        used:
          type: integer
        created_at:
          type: string
          format: date-time

    ProUser:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        plan:
          type: string
        role:
          type: string
        status:
          type: string
          enum: [pending, active, suspended]
        max_domains:
          type: integer
        ops_used:
          type: integer
          description: Operations used in the current billing month
        ops_limit:
          type: integer
          description: Maximum operations allowed per month
        domain_count:
          type: integer
        created_at:
          type: string
          format: date-time
        downgraded:
          type: boolean

    Domain:
      type: object
      properties:
        id:
          type: string
          format: uuid
        domain:
          type: string
        default:
          type: boolean
        sort_order:
          type: integer

    ProDomain:
      type: object
      properties:
        id:
          type: string
          format: uuid
        domain:
          type: string
        verify_status:
          type: string
          enum: [pending, verified, failed]
        verify_token:
          type: string
        verified_at:
          type: string
          format: date-time
          nullable: true
        mx_configured:
          type: boolean
        created_at:
          type: string
          format: date-time

    DNSRecord:
      type: object
      properties:
        type:
          type: string
          example: TXT
        host:
          type: string
        value:
          type: string
        priority:
          type: integer
          nullable: true

    Webhook:
      type: object
      properties:
        id:
          type: string
          format: uuid
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        secret:
          type: string
          description: "Prefixed with whsec_. Only returned on creation."
        status:
          type: string
          enum: [active, disabled]
        created_at:
          type: string
          format: date-time

    WebhookDelivery:
      type: object
      properties:
        id:
          type: string
          format: uuid
        event_type:
          type: string
          example: email.received
        event_id:
          type: string
        status_code:
          type: integer
          nullable: true
        error:
          type: string
          nullable: true
        attempt:
          type: integer
        duration_ms:
          type: integer
          nullable: true
        created_at:
          type: string
          format: date-time

    EmailReceivedEvent:
      type: object
      required: [id, type, created_at, data]
      properties:
        id:
          type: string
          description: Stable event identifier (`evt_` followed by the email ID). Use it for idempotency.
        type:
          type: string
          enum: [email.received]
        created_at:
          type: string
          format: date-time
        data:
          $ref: "#/components/schemas/EmailReceivedData"

    EmailReceivedData:
      type: object
      required: [email_id, account_id, address, from, to, sender, subject, preview_text, text_body, html_body, attachments, content_status, content_truncated, attachments_omitted, size, created_at]
      properties:
        email_id: { type: string, format: uuid }
        account_id: { type: string, format: uuid }
        address: { type: string, format: email }
        from: { type: string }
        to: { type: string }
        sender: { type: string }
        subject: { type: string }
        preview_text: { type: string }
        text_body: { type: string }
        html_body: { type: string }
        attachments:
          type: array
          items:
            type: object
            required: [index, filename, content_type, size, download_url]
            properties:
              index: { type: integer }
              filename: { type: string }
              content_type: { type: string }
              size: { type: integer }
              download_url: { type: string }
        content_status:
          type: string
          enum: [ready, failed, pending_timeout]
        content_truncated: { type: boolean }
        attachments_omitted: { type: integer }
        size: { type: integer }
        created_at: { type: string, format: date-time }

    Token:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        last_used_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
        revoked_at:
          type: string
          format: date-time
          nullable: true
