openapi: 3.1.0
info:
  title: Portal API (JWT)
  description: '# Portal API — JWT Authentication


    Manage your tenant resources via browser session or Cognito JWT token.


    > **This path (`/api/v1/portal`) requires a Cognito JWT Bearer token.**

    > For programmatic/API key access, use the **Portal API (HMAC)** at `/api/v1/portal-api`
    instead.


    ## Authentication


    **Required header:** `Authorization: Bearer <cognito-jwt-token>`


    Obtain a JWT token by authenticating via Cognito (email + password). The token
    is automatically

    scoped to the tenants associated with your user account.


    This path is enforced at the **API Gateway level** using the `cognito-customer-authorizer`.

    Requests without a valid JWT will receive `401 WWW-Authenticate: Bearer`.


    ## When to use this path


    | Use Case | Path to use |

    |----------|-------------|

    | Browser portal UI | `/api/v1/portal` (this spec) |

    | Interactive user sessions | `/api/v1/portal` (this spec) |

    | AI agents / programmatic access | `/api/v1/portal-api` (HMAC spec) |

    | Automation / CI/CD | `/api/v1/portal-api` (HMAC spec) |


    ## Base Path

    All routes are prefixed with `/api/v1/portal`

    '
  version: 1.0.0
  contact:
    name: API Support
    url: https://agentmailbox.to/apidocs/
servers:
- url: https://api.agentmailbox.to
  description: Production
tags:
- name: analytics
  description: Email analytics and metrics
- name: credentials
  description: API credential management
- name: domains
  description: Domain management and DNS verification
- name: email
  description: Email sending operations
- name: general
  description: General operations
- name: mailboxes
  description: Mailbox CRUD operations
- name: messages
  description: Email message retrieval and management
- name: subdomains
  description: Subdomain lifecycle management
- name: tenants
  description: Tenant management operations
- name: verification
  description: DNS verification operations
- name: webhooks
  description: Webhook management for real-time event delivery
paths:
  /api/v1/portal/credential-status:
    get:
      operationId: listPortalCredentialStatus
      summary: Check if credentials are ready for retrieval (requires auth)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialList'
              example: &id009
                credentials:
                - id: 7c2d8b4a-3e1f-4a5b-9c6d-0e1f2a3b4c5d
                  api_key_id: MK-acme-support-a1b2c3d4
                  permissions: admin
                  description: Production API key
                  mailbox_id: null
                  created_at: '2026-03-04T10:30:00Z'
                  last_used_at: '2026-03-04T09:15:00Z'
                count: 1
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: &id001
                error: Invalid request format
                error_id: 550e8400-e29b-41d4-a716-446655440000
                code: VALIDATION_ERROR
                hint: Check the request body and query parameters for validation errors.
                support_url: https://agentmailbox.to/support
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: &id002
                error: Authentication required
                error_id: 550e8400-e29b-41d4-a716-446655440000
                code: AUTHENTICATION_REQUIRED
                message: Valid API credentials are required for this endpoint.
                hint: Include valid HMAC signature headers.
                support_url: https://agentmailbox.to/support
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: &id003
                error: Access denied
                error_id: 550e8400-e29b-41d4-a716-446655440000
                code: ACCESS_DENIED
                message: You do not have permission to access this resource.
                hint: Verify you have the correct permissions for this operation.
                support_url: https://agentmailbox.to/support
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: &id004
                error: Resource not found or access denied
                error_id: 550e8400-e29b-41d4-a716-446655440000
                code: NOT_FOUND
                hint: Verify the resource ID is correct and you have access to it.
                support_url: https://agentmailbox.to/support
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: &id005
                error: Failed to process request
                error_id: 550e8400-e29b-41d4-a716-446655440000
                message: An error occurred while processing your request. Please contact
                  support with the error ID if this persists.
                support_url: https://agentmailbox.to/support
  /api/v1/portal/login:
    post:
      operationId: createPortalLogin
      summary: Authenticate user with email/password (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/login/forgot-password:
    post:
      operationId: createPortalLoginForgotPassword
      summary: Initiate forgot password flow (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: 'User not found


            **When this occurs:** No pending user found for this email address. Ensure
            you''ve completed email verification first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: User not found or not confirmed
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/login/mfa:
    post:
      operationId: createPortalLoginMfa
      summary: Complete MFA challenge during login (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/login/reset-password:
    post:
      operationId: createPortalLoginResetPassword
      summary: Complete password reset with code (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: 'User not found


            **When this occurs:** No pending user found for this email address. Ensure
            you''ve completed email verification first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: User not found or not confirmed
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-analytics:
    get:
      operationId: listPortalMyAnalytics
      summary: Get combined analytics for all user
      tags:
      - analytics
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortalAnalytics'
              example: &id008
                period: 2026-03-01 to 2026-03-04
                summary:
                  sent: 1250
                  delivered: 1235
                  bounced: 15
                  complaints: 2
                  opened: 890
                  clicked: 234
                rates:
                  delivery_rate: 98.8
                  bounce_rate: 1.2
                  open_rate: 72.1
                  click_rate: 18.9
                daily_breakdown:
                - date: '2026-03-04'
                  sent: 320
                  delivered: 318
                  bounced: 2
                  opened: 210
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-custom-domains:
    post:
      operationId: createPortalMyCustomDomains
      summary: Create custom domain (user
      tags:
      - domains
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Domain'
              example: &id007
                id: c3d4e5f6-a7b8-9012-cdef-345678901234
                tenant_id: d4e5f6a7-b8c9-0123-def4-567890123456
                tenant_codename: newcorp
                full_domain: newcorp.agentmailbox.to
                subdomain: newcorp
                parent_domain: agentmailbox.to
                verification_status: pending
                dkim_status: pending
                dns_records:
                - type: CNAME
                  name: _dkim1.newcorp.agentmailbox.to
                  value: dkim1.amazonses.com
                  status: pending
                - type: CNAME
                  name: _dkim2.newcorp.agentmailbox.to
                  value: dkim2.amazonses.com
                  status: pending
                - type: CNAME
                  name: _dkim3.newcorp.agentmailbox.to
                  value: dkim3.amazonses.com
                  status: pending
                created_at: '2026-03-04T10:30:00Z'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Subdomain already taken


            **When this occurs:** The requested subdomain is already registered by
            another tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Subdomain 'acme' is already taken
                error_id: 550e8400-e29b-41d4-a716-446655440000
                suggestions:
                - acme1
                - acme2
                - acme-corp
    get:
      operationId: listPortalMyCustomDomains
      summary: List user
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainList'
              example: &id006
                domains:
                - id: 2ef739e0-dedb-49ef-beb9-86fa70d1b133
                  tenant_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  tenant_codename: acme
                  full_domain: acme.agentmailbox.to
                  subdomain: acme
                  parent_domain: agentmailbox.to
                  verification_status: verified
                  dkim_status: verified
                  sending_enabled: true
                  receiving_enabled: true
                  mailbox_count: 3
                  created_at: '2026-03-04T10:30:00Z'
                - id: e5f6a7b8-c9d0-1234-ef56-789012345678
                  tenant_id: b2c3d4e5-f6a7-8901-bcde-f23456789012
                  tenant_codename: beta-corp
                  full_domain: beta-corp.agentmailbox.to
                  subdomain: beta-corp
                  parent_domain: agentmailbox.to
                  verification_status: verified
                  dkim_status: verified
                  sending_enabled: true
                  receiving_enabled: true
                  mailbox_count: 2
                  created_at: '2026-02-15T08:00:00Z'
                pagination:
                  offset: 0
                  limit: 50
                  total: 2
                  has_more: false
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-custom-domains/{id}:
    get:
      operationId: getPortalMyCustomDomains
      summary: Get custom domain details (if user owns it)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Domain'
              example: *id006
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    delete:
      operationId: deletePortalMyCustomDomains
      summary: Delete custom domain (if user owns it)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '204':
          description: Resource deleted successfully
  /api/v1/portal/my-domains:
    post:
      operationId: createPortalMyDomains
      summary: Create domain and tenant - NOT NEEDED (use /my-subdomain or /my-custom-domains)
      tags:
      - domains
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Domain'
              example: *id007
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Subdomain already taken


            **When this occurs:** The requested subdomain is already registered by
            another tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Subdomain 'acme' is already taken
                error_id: 550e8400-e29b-41d4-a716-446655440000
                suggestions:
                - acme1
                - acme2
                - acme-corp
    get:
      operationId: listPortalMyDomains
      summary: List ALL user
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainList'
              example: *id006
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/analytics/daily:
    get:
      operationId: listPortalMyDomainsNameAnalyticsDaily
      summary: Get daily analytics (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortalAnalytics'
              example: *id008
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/analytics/monthly:
    get:
      operationId: listPortalMyDomainsNameAnalyticsMonthly
      summary: Get monthly analytics (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortalAnalytics'
              example: *id008
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/credentials:
    get:
      operationId: listPortalMyDomainsNameCredentials
      summary: List credentials by domain (if user owns domain)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialList'
              example: *id009
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    post:
      operationId: createPortalMyDomainsNameCredentials
      summary: Generate credentials for domain (if user owns domain)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                permissions:
                  type: string
                  enum:
                  - sending_only
                  - receiving_only
                  - admin
                  description: Permission level for the credential
                description:
                  type: string
                  description: Optional description for the credential
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialCreated'
              example: &id020
                id: 7c2d8b4a-3e1f-4a5b-9c6d-0e1f2a3b4c5d
                api_key_id: MK-acme-support-a1b2c3d4
                api_secret: '[REDACTED - shown only once at creation]'
                permissions: admin
                description: Production API key
                mailbox_id: null
                created_at: '2026-03-04T10:30:00Z'
                warning: Store the api_secret securely. It will not be shown again.
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Subdomain already taken


            **When this occurs:** The requested subdomain is already registered by
            another tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Subdomain 'acme' is already taken
                error_id: 550e8400-e29b-41d4-a716-446655440000
                suggestions:
                - acme1
                - acme2
                - acme-corp
  /api/v1/portal/my-domains/name/{domain_name}/credentials/{type}:
    delete:
      operationId: deletePortalMyDomainsNameCredentials
      summary: Revoke admin credentials by domain (sending_only/receiving_only are
        mailbox-scoped)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: type
        in: path
        required: true
        schema:
          type: string
        description: The type
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '204':
          description: Resource deleted successfully
  /api/v1/portal/my-domains/name/{domain_name}/dns:
    get:
      operationId: listPortalMyDomainsNameDns
      summary: Get DNS status (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DnsStatus'
              example:
                domain: acme.agentmailbox.to
                verification_status: verified
                dkim_status: verified
                spf_status: verified
                dmarc_status: verified
                required_records:
                - type: CNAME
                  name: _dkim1.acme.agentmailbox.to
                  value: dkim1.amazonses.com
                  status: verified
                  verified_at: '2026-03-04T10:35:00Z'
                - type: CNAME
                  name: _dkim2.acme.agentmailbox.to
                  value: dkim2.amazonses.com
                  status: verified
                  verified_at: '2026-03-04T10:35:00Z'
                - type: CNAME
                  name: _dkim3.acme.agentmailbox.to
                  value: dkim3.amazonses.com
                  status: verified
                  verified_at: '2026-03-04T10:35:00Z'
                sending_enabled: true
                receiving_enabled: true
                ai_explanation: All DNS records are properly configured. Your domain
                  is fully verified and ready for sending and receiving emails.
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/mailboxes:
    post:
      operationId: createPortalMyDomainsNameMailboxes
      summary: Create mailbox (if user owns domain)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - username
              properties:
                username:
                  type: string
                  description: Local part of email address
                  pattern: ^[a-z0-9][a-z0-9._-]{0,62}[a-z0-9]$
                display_name:
                  type: string
                  description: Display name for the mailbox
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: &id019
                id: 9f0e6e8e-5bf4-43f2-b7e7-53dfdd3a12a1
                domain_id: 2ef739e0-dedb-49ef-beb9-86fa70d1b133
                username: sales
                display_name: Sales Team
                email_address: sales@acme.agentmailbox.to
                created_at: '2026-03-04T10:30:00Z'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
    get:
      operationId: listPortalMyDomainsNameMailboxes
      summary: List mailboxes for domain (if user owns domain)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MailboxList'
              example: &id010
                mailboxes:
                - id: 9f0e6e8e-5bf4-43f2-b7e7-53dfdd3a12a1
                  domain_id: 2ef739e0-dedb-49ef-beb9-86fa70d1b133
                  username: support
                  display_name: Support Team
                  email_address: support@acme.agentmailbox.to
                  created_at: '2026-03-04T10:30:00Z'
                - id: 3a4b5c6d-7e8f-4a9b-8c1d-2e3f4a5b6c7d
                  domain_id: 2ef739e0-dedb-49ef-beb9-86fa70d1b133
                  username: sales
                  display_name: Sales Team
                  email_address: sales@acme.agentmailbox.to
                  created_at: '2026-03-04T10:30:00Z'
                pagination:
                  count: 2
                  limit: 50
                  offset: 0
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/mailboxes/{username}:
    get:
      operationId: getPortalMyDomainsNameMailboxes
      summary: Get mailbox by username with analytics (if user owns domain)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: username
        in: path
        required: true
        schema:
          type: string
        description: Mailbox username (local part of email)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/metrics/realtime:
    get:
      operationId: listPortalMyDomainsNameMetricsRealtime
      summary: Get realtime metrics (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RealtimeMetrics'
              example:
                domain: acme.agentmailbox.to
                period: last_hour
                metrics:
                  emails_sent: 45
                  emails_delivered: 44
                  emails_bounced: 1
                  emails_complained: 0
                  emails_received: 23
                  delivery_rate: 97.8
                  bounce_rate: 2.2
                last_updated: '2026-03-04T10:30:00Z'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/tenant:
    get:
      operationId: listPortalMyDomainsNameTenant
      summary: Get tenant by domain name (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
              example: &id015
                id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                codename: acme
                status: active
                tier: paid
                aws_ses_tenant_id: t-abc123def456
                aws_ses_tenant_name: SES-Tenant-acme
                configuration_set_name: agentmail-acme-config
                domains:
                - id: 2ef739e0-dedb-49ef-beb9-86fa70d1b133
                  full_domain: acme.agentmailbox.to
                  verification_status: verified
                  mailbox_count: 3
                statistics:
                  total_domains: 1
                  total_mailboxes: 3
                  total_messages_sent: 1250
                  total_messages_received: 890
                created_at: '2026-03-04T10:30:00Z'
                updated_at: '2026-03-04T10:35:00Z'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: &id016
                error: Tenant not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
                code: TENANT_NOT_FOUND
                hint: Verify the tenant codename is correct.
                support_url: https://agentmailbox.to/support
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    put:
      operationId: updatePortalMyDomainsNameTenant
      summary: Update tenant by domain name (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/tracking/config:
    get:
      operationId: listPortalMyDomainsNameTrackingConfig
      summary: Get tracking config (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrackingConfig'
              example: &id011
                domain: acme.agentmailbox.to
                open_tracking: true
                click_tracking: true
                custom_tracking_domain: null
                webhook_url: https://api.acme.com/webhooks/email
                webhook_events:
                - delivered
                - bounced
                - complained
                - opened
                - clicked
                updated_at: '2026-03-04T10:35:00Z'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    put:
      operationId: updatePortalMyDomainsNameTrackingConfig
      summary: Update tracking config (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                open_tracking_enabled:
                  type: boolean
                click_tracking_enabled:
                  type: boolean
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrackingConfig'
              example: *id011
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/name/{domain_name}/verify:
    post:
      operationId: createPortalMyDomainsNameVerify
      summary: Verify domain DNS (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainVerificationResult'
              example: &id012
                domain: acme.agentmailbox.to
                verification_triggered: true
                previous_status: pending
                current_status: verified
                verification_duration_ms: 2345
                dkim_verified: true
                message: Domain verification completed successfully.
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: &id013
                error: DNS records not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
                code: DOMAIN_VERIFICATION_FAILED
                message: Required DNS records were not found. Please configure DNS
                  and retry.
                missing_records:
                - _dkim1.newcorp.agentmailbox.to
                hint: Add the required CNAME records to your DNS provider before verification.
                support_url: https://agentmailbox.to/support
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Subdomain already taken


            **When this occurs:** The requested subdomain is already registered by
            another tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Subdomain 'acme' is already taken
                error_id: 550e8400-e29b-41d4-a716-446655440000
                suggestions:
                - acme1
                - acme2
                - acme-corp
  /api/v1/portal/my-domains/name/{domain}:
    get:
      operationId: getPortalMyDomainsName
      summary: Get domain details by name (if user owns domain)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: domain
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Domain'
              example:
                id: 2ef739e0-dedb-49ef-beb9-86fa70d1b133
                tenant_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                tenant_codename: acme
                full_domain: acme.agentmailbox.to
                subdomain: acme
                parent_domain: agentmailbox.to
                verification_status: verified
                dkim_status: verified
                sending_enabled: true
                receiving_enabled: true
                ses_identity_arn: arn:aws:ses:eu-west-2:123456789012:identity/acme.agentmailbox.to
                mailboxes:
                - id: 9f0e6e8e-5bf4-43f2-b7e7-53dfdd3a12a1
                  username: support
                  display_name: Support Team
                  email_address: support@acme.agentmailbox.to
                - id: 3a4b5c6d-7e8f-4a9b-8c1d-2e3f4a5b6c7d
                  username: sales
                  display_name: Sales Team
                  email_address: sales@acme.agentmailbox.to
                created_at: '2026-03-04T10:30:00Z'
                updated_at: '2026-03-04T10:35:00Z'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Domain not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
                code: DOMAIN_NOT_FOUND
                hint: Verify the domain name is correct and the domain exists.
                support_url: https://agentmailbox.to/support
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-domains/verify-batch:
    post:
      operationId: createPortalMyDomainsVerifyBatch
      summary: Batch verify DNS for user
      tags:
      - domains
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DnsVerifyBatchResponse'
              example: *id012
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id013
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Subdomain already taken


            **When this occurs:** The requested subdomain is already registered by
            another tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Subdomain 'acme' is already taken
                error_id: 550e8400-e29b-41d4-a716-446655440000
                suggestions:
                - acme1
                - acme2
                - acme-corp
  /api/v1/portal/my-domains/{id}/verify:
    post:
      operationId: createPortalMyDomainsVerify
      summary: Trigger DNS verification for domain (if user owns it)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainVerificationResult'
              example: *id012
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id013
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Subdomain already taken


            **When this occurs:** The requested subdomain is already registered by
            another tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Subdomain 'acme' is already taken
                error_id: 550e8400-e29b-41d4-a716-446655440000
                suggestions:
                - acme1
                - acme2
                - acme-corp
  /api/v1/portal/my-mailboxes:
    get:
      operationId: listPortalMyMailboxes
      summary: List all mailboxes across user
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MailboxList'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-mailboxes/{id}:
    get:
      operationId: getPortalMyMailboxes
      summary: Get mailbox details by ID (if user owns it)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    put:
      operationId: updatePortalMyMailboxes
      summary: Update mailbox by ID (if user owns it)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    delete:
      operationId: deletePortalMyMailboxes
      summary: Delete mailbox by ID (if user owns it)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '204':
          description: Resource deleted successfully
  /api/v1/portal/my-mailboxes/{mailbox_id}/credentials:
    get:
      operationId: listPortalMyMailboxesCredentials
      summary: List all API credentials for mailbox (if user owns mailbox)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialList'
              example: *id009
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    post:
      operationId: createPortalMyMailboxesCredentials
      summary: Generate API credentials for mailbox (if user owns mailbox)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                permissions:
                  type: string
                  enum:
                  - sending_only
                  - receiving_only
                  - admin
                  description: Permission level for the credential
                description:
                  type: string
                  description: Optional description for the credential
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialCreated'
              example: &id014
                id: 7c2d8b4a-3e1f-4a5b-9c6d-0e1f2a3b4c5d
                api_key_id: MK-acme-support-b2c3d4e5
                api_secret: '[REDACTED - shown only once at creation]'
                permissions: sending_only
                description: Support mailbox sender
                mailbox_id: 9f0e6e8e-5bf4-43f2-b7e7-53dfdd3a12a1
                mailbox_email: support@acme.agentmailbox.to
                created_at: '2026-03-04T10:30:00Z'
                warning: Store the api_secret securely. It will not be shown again.
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
  /api/v1/portal/my-mailboxes/{mailbox_id}/credentials/{credential_type}:
    post:
      operationId: createPortalMyMailboxesCredentials
      summary: Generate API credentials by type for mailbox (if user owns mailbox)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: credential_type
        in: path
        required: true
        schema:
          type: string
        description: The credential type
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                permissions:
                  type: string
                  enum:
                  - sending_only
                  - receiving_only
                  - admin
                  description: Permission level for the credential
                description:
                  type: string
                  description: Optional description for the credential
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialCreated'
              example: *id014
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
    delete:
      operationId: deletePortalMyMailboxesCredentials
      summary: Revoke API credentials by type for mailbox (if user owns mailbox)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: credential_type
        in: path
        required: true
        schema:
          type: string
        description: The credential type
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '204':
          description: Resource deleted successfully
  /api/v1/portal/my-mailboxes/{mailbox_id}/credentials/{permission_type}:
    get:
      operationId: getPortalMyMailboxesCredentials
      summary: List API credentials by type for mailbox (if user owns mailbox)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: permission_type
        in: path
        required: true
        schema:
          type: string
        description: The permission type
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialList'
              example: *id009
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-subdomains:
    post:
      operationId: createPortalMySubdomains
      summary: Create subdomain (creates tenant + associates user)
      tags:
      - subdomains
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - subdomain
              properties:
                subdomain:
                  type: string
                  description: Subdomain name (e.g., "acme" for acme.agentmailbox.to)
                  pattern: ^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$
                mailboxes:
                  type: array
                  description: Initial mailboxes to create
                  items:
                    type: object
                    required:
                    - username
                    properties:
                      username:
                        type: string
                      display_name:
                        type: string
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Subdomain already taken


            **When this occurs:** The requested subdomain is already registered by
            another tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Subdomain 'acme' is already taken
                error_id: 550e8400-e29b-41d4-a716-446655440000
                suggestions:
                - acme1
                - acme2
                - acme-corp
        '202':
          description: Accepted - async operation in progress
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubdomainCreated'
              example:
                status: pending_verification
                message: Subdomain created. DNS verification in progress.
                subdomain_details:
                  id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  subdomain: acme
                  full_domain: acme.agentmailbox.to
                  tenant_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  status: pending
                  verification_status: pending
                  sending_enabled: false
                  receiving_enabled: false
                dns_records:
                - type: CNAME
                  name: _dkim1.acme.agentmailbox.to
                  value: dkim1.amazonses.com
                  status: pending
                verification:
                  status: queued
                  estimated_time: 5-10 minutes
    get:
      operationId: listPortalMySubdomains
      summary: List user
      tags:
      - subdomains
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubdomainList'
              example:
                subdomains:
                - id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  subdomain: acme
                  full_domain: acme.agentmailbox.to
                  tenant_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  status: active
                  verification_status: verified
                  sending_enabled: true
                  receiving_enabled: true
                  mailbox_count: 2
                  created_at: '2026-03-04T10:30:00Z'
                count: 1
                limit: 50
                offset: 0
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-subdomains/{id}:
    get:
      operationId: getPortalMySubdomains
      summary: Get subdomain details (if user owns it)
      tags:
      - subdomains
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subdomain'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    patch:
      operationId: updatePortalMySubdomains
      summary: Update subdomain (if user owns it)
      tags:
      - subdomains
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subdomain'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    delete:
      operationId: deletePortalMySubdomains
      summary: Delete subdomain (if user owns it)
      tags:
      - subdomains
      security:
      - cognitoJwt: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the id
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '204':
          description: Resource deleted successfully
  /api/v1/portal/my-subdomains/{subdomain}/status:
    get:
      operationId: listPortalMySubdomainsStatus
      summary: Get complete subdomain status including mailboxes and credentials
      tags:
      - subdomains
      security:
      - cognitoJwt: []
      parameters:
      - name: subdomain
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subdomain'
              example:
                subdomain: acme
                full_domain: acme.agentmailbox.to
                status: active
                verification:
                  domain_status: verified
                  dkim_status: verified
                  spf_status: verified
                  dmarc_status: verified
                  sending_score: 100
                  receiving_score: 100
                sending_enabled: true
                receiving_enabled: true
                mailboxes:
                - id: 9f0e6e8e-5bf4-43f2-b7e7-53dfdd3a12a1
                  username: support
                  email_address: support@acme.agentmailbox.to
                  display_name: Support Team
                credentials:
                  admin_configured: true
                  mailbox_credentials: 1
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants:
    get:
      operationId: listPortalMyTenants
      summary: List user
      tags:
      - tenants
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantList'
              example:
                tenants:
                - id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  codename: acme
                  status: active
                  tier: paid
                  aws_ses_tenant_id: t-abc123def456
                  aws_ses_tenant_name: SES-Tenant-acme
                  configuration_set_name: agentmail-acme-config
                  domain_count: 2
                  mailbox_count: 5
                  created_at: '2026-03-04T10:30:00Z'
                  updated_at: '2026-03-04T10:35:00Z'
                - id: b2c3d4e5-f6a7-8901-bcde-f23456789012
                  codename: beta-corp
                  status: active
                  tier: free
                  aws_ses_tenant_id: t-def456ghi789
                  aws_ses_tenant_name: SES-Tenant-beta-corp
                  configuration_set_name: agentmail-beta-corp-config
                  domain_count: 1
                  mailbox_count: 2
                  created_at: '2026-02-15T08:00:00Z'
                  updated_at: '2026-03-01T14:30:00Z'
                pagination:
                  offset: 0
                  limit: 50
                  total: 2
                  has_more: false
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** Credential has no tenant associations. User must
            be associated with at least one tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{codename}/domains:
    get:
      operationId: listPortalMyTenantsDomains
      summary: List tenant
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainList'
              example: *id015
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id016
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{codename}/domains/{domain}:
    get:
      operationId: getPortalMyTenantsDomains
      summary: Get domain by tenant (if user owns tenant)
      tags:
      - domains
      security:
      - cognitoJwt: []
      parameters:
      - name: codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: domain
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
              example: *id015
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id016
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}:
    get:
      operationId: getPortalMyTenants
      summary: Get tenant details (if user owns it)
      tags:
      - tenants
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
              example: *id015
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** Credential has no tenant associations. User must
            be associated with at least one tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id016
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    put:
      operationId: updatePortalMyTenants
      summary: Update tenant details (if user owns it)
      tags:
      - tenants
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/analytics:
    get:
      operationId: listPortalMyTenantsAnalytics
      summary: Get tenant analytics (if user owns tenant)
      tags:
      - tenants
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortalAnalytics'
              example: &id018
                tenant_codename: acme
                period:
                  start: '2026-03-01T00:00:00Z'
                  end: '2026-03-04T23:59:59Z'
                summary:
                  total_sent: 1250
                  total_delivered: 1242
                  total_bounced: 8
                  total_complaints: 1
                  total_received: 600
                  delivery_rate: 99.4
                  bounce_rate: 0.6
                  complaint_rate: 0.08
                by_domain:
                - domain: acme.agentmailbox.to
                  sent: 1000
                  delivered: 995
                  bounced: 5
                  received: 450
                - domain: support.acme.com
                  sent: 250
                  delivered: 247
                  bounced: 3
                  received: 150
                by_mailbox:
                - mailbox: support@acme.agentmailbox.to
                  sent: 750
                  received: 400
                - mailbox: sales@acme.agentmailbox.to
                  sent: 500
                  received: 200
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** Credential has no tenant associations. User must
            be associated with at least one tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes:
    get:
      operationId: listPortalMyTenantsMailboxes
      summary: List tenant
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MailboxList'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/messages:
    get:
      operationId: listPortalMyTenantsMailboxesMessages
      summary: List mailbox messages with thread support (if user owns tenant)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      - name: is_read
        in: query
        schema:
          type: boolean
        description: Filter by read status
      - name: since
        in: query
        schema:
          type: string
          format: date-time
        description: Filter messages after this timestamp (ISO 8601)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageList'
              example: &id017
                messages:
                - id: 8b3f9c5e-f7f7-4fd2-91fa-187f20c3da36
                  mailbox_id: 9f0e6e8e-5bf4-43f2-b7e7-53dfdd3a12a1
                  message_id: <msg123@acme.agentmailbox.to>
                  thread_id: b7c8d9e0-1234-4567-89ab-cdef12345678
                  direction: inbound
                  from_address: customer@example.com
                  to_addresses:
                  - support@acme.agentmailbox.to
                  subject: Question about my order
                  timestamp: '2026-03-04T10:30:00Z'
                  is_read: false
                  is_archived: false
                  has_attachments: false
                total: 1
                limit: 10
                offset: 0
        '400':
          description: 'Missing required parameter


            **When this occurs:** The mailbox_id was not provided in the request.
            Either scope the credential to a mailbox or provide mailbox_id in the
            request.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Missing required parameter
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: mailbox_id
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Mailbox access denied


            **When this occurs:** Mailbox-scoped credential is attempting to access
            messages from a different mailbox.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox access denied
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: 'Message not found


            **When this occurs:** The requested message ID does not exist in the database
            or has been deleted.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Message not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/outbound-messages:
    get:
      operationId: listPortalMyTenantsMailboxesOutboundMessages
      summary: List mailbox outbound messages (if user owns tenant)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      - name: is_read
        in: query
        schema:
          type: boolean
        description: Filter by read status
      - name: since
        in: query
        schema:
          type: string
          format: date-time
        description: Filter messages after this timestamp (ISO 8601)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageList'
              example: *id017
        '400':
          description: 'Missing required parameter


            **When this occurs:** The mailbox_id was not provided in the request.
            Either scope the credential to a mailbox or provide mailbox_id in the
            request.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Missing required parameter
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: mailbox_id
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Mailbox access denied


            **When this occurs:** Mailbox-scoped credential is attempting to access
            messages from a different mailbox.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox access denied
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: 'Message not found


            **When this occurs:** The requested message ID does not exist in the database
            or has been deleted.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Message not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/outbound-messages/{message_id}/analytics:
    get:
      operationId: listPortalMyTenantsMailboxesOutboundMessagesAnalytics
      summary: Get message analytics (if user owns tenant)
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the message
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      - name: is_read
        in: query
        schema:
          type: boolean
        description: Filter by read status
      - name: since
        in: query
        schema:
          type: string
          format: date-time
        description: Filter messages after this timestamp (ISO 8601)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Message'
              example: *id018
        '400':
          description: 'Missing required parameter


            **When this occurs:** The mailbox_id was not provided in the request.
            Either scope the credential to a mailbox or provide mailbox_id in the
            request.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Missing required parameter
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: mailbox_id
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Mailbox access denied


            **When this occurs:** Mailbox-scoped credential is attempting to access
            messages from a different mailbox.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox access denied
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: 'Message not found


            **When this occurs:** The requested message ID does not exist in the database
            or has been deleted.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Message not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/webhooks:
    post:
      operationId: createPortalMyTenantsMailboxesWebhooks
      summary: Create mailbox-scoped webhook
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - username
              properties:
                username:
                  type: string
                  description: Local part of email address
                  pattern: ^[a-z0-9][a-z0-9._-]{0,62}[a-z0-9]$
                display_name:
                  type: string
                  description: Display name for the mailbox
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id019
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
    get:
      operationId: listPortalMyTenantsMailboxesWebhooks
      summary: List webhooks for mailbox (includes tenant-wide)
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MailboxList'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/webhooks/{webhook_id}:
    get:
      operationId: getPortalMyTenantsMailboxesWebhooks
      summary: Get mailbox webhook details
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    patch:
      operationId: updatePortalMyTenantsMailboxesWebhooks
      summary: Update mailbox webhook
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
        '400':
          description: 'Invalid tenant data


            **When this occurs:** Tenant data validation failed. Check required fields
            like codename format.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid tenant configuration
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: codename
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    delete:
      operationId: deletePortalMyTenantsMailboxesWebhooks
      summary: Delete mailbox webhook
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '204':
          description: Resource deleted successfully
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/webhooks/{webhook_id}/cloudformation:
    get:
      operationId: listPortalMyTenantsMailboxesWebhooksCloudformation
      summary: Get CloudFormation template for AWS webhook destination
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MailboxList'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/webhooks/{webhook_id}/deliveries:
    get:
      operationId: listPortalMyTenantsMailboxesWebhooksDeliveries
      summary: List webhook delivery history
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MailboxList'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/webhooks/{webhook_id}/rotate-secret:
    post:
      operationId: createPortalMyTenantsMailboxesWebhooksRotateSecret
      summary: Rotate HTTPS webhook signing secret
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - username
              properties:
                username:
                  type: string
                  description: Local part of email address
                  pattern: ^[a-z0-9][a-z0-9._-]{0,62}[a-z0-9]$
                display_name:
                  type: string
                  description: Display name for the mailbox
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id019
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/webhooks/{webhook_id}/test:
    post:
      operationId: createPortalMyTenantsMailboxesWebhooksTest
      summary: Send test event to mailbox webhook
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - username
              properties:
                username:
                  type: string
                  description: Local part of email address
                  pattern: ^[a-z0-9][a-z0-9._-]{0,62}[a-z0-9]$
                display_name:
                  type: string
                  description: Display name for the mailbox
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id019
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
  /api/v1/portal/my-tenants/{tenant_codename}/mailboxes/{mailbox_id}/webhooks/{webhook_id}/verify:
    post:
      operationId: createPortalMyTenantsMailboxesWebhooksVerify
      summary: Verify webhook endpoint connectivity (required before activation)
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: mailbox_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the mailbox
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - username
              properties:
                username:
                  type: string
                  description: Local part of email address
                  pattern: ^[a-z0-9][a-z0-9._-]{0,62}[a-z0-9]$
                display_name:
                  type: string
                  description: Display name for the mailbox
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id019
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
  /api/v1/portal/my-tenants/{tenant_codename}/outbound-messages:
    get:
      operationId: listPortalMyTenantsOutboundMessages
      summary: List tenant outbound messages - NOT IMPLEMENTED
      tags:
      - messages
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      - name: is_read
        in: query
        schema:
          type: boolean
        description: Filter by read status
      - name: since
        in: query
        schema:
          type: string
          format: date-time
        description: Filter messages after this timestamp (ISO 8601)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageList'
              example: *id017
        '400':
          description: 'Missing required parameter


            **When this occurs:** The mailbox_id was not provided in the request.
            Either scope the credential to a mailbox or provide mailbox_id in the
            request.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Missing required parameter
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: mailbox_id
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Mailbox access denied


            **When this occurs:** Mailbox-scoped credential is attempting to access
            messages from a different mailbox.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox access denied
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: 'Message not found


            **When this occurs:** The requested message ID does not exist in the database
            or has been deleted.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Message not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/outbound-messages/{message_id}/analytics:
    get:
      operationId: listPortalMyTenantsOutboundMessagesAnalytics
      summary: Get outbound message analytics - NOT IMPLEMENTED
      tags:
      - messages
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the message
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      - name: is_read
        in: query
        schema:
          type: boolean
        description: Filter by read status
      - name: since
        in: query
        schema:
          type: string
          format: date-time
        description: Filter messages after this timestamp (ISO 8601)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Message'
              example: *id018
        '400':
          description: 'Missing required parameter


            **When this occurs:** The mailbox_id was not provided in the request.
            Either scope the credential to a mailbox or provide mailbox_id in the
            request.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Missing required parameter
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: mailbox_id
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Mailbox access denied


            **When this occurs:** Mailbox-scoped credential is attempting to access
            messages from a different mailbox.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox access denied
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: 'Message not found


            **When this occurs:** The requested message ID does not exist in the database
            or has been deleted.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Message not found
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/webhooks:
    post:
      operationId: createPortalMyTenantsWebhooks
      summary: Create tenant-wide webhook (fires for all mailboxes)
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          description: 'Invalid tenant data


            **When this occurs:** Tenant data validation failed. Check required fields
            like codename format.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid tenant configuration
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: codename
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    get:
      operationId: listPortalMyTenantsWebhooks
      summary: List tenant-wide webhooks
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantList'
              example: *id015
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** Credential has no tenant associations. User must
            be associated with at least one tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id016
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/webhooks/{webhook_id}:
    get:
      operationId: getPortalMyTenantsWebhooks
      summary: Get tenant webhook details
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
              example: *id015
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** Credential has no tenant associations. User must
            be associated with at least one tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id016
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    patch:
      operationId: updatePortalMyTenantsWebhooks
      summary: Update tenant webhook
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          description: 'Invalid tenant data


            **When this occurs:** Tenant data validation failed. Check required fields
            like codename format.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid tenant configuration
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: codename
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
    delete:
      operationId: deletePortalMyTenantsWebhooks
      summary: Delete tenant webhook
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      responses:
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '204':
          description: Resource deleted successfully
  /api/v1/portal/my-tenants/{tenant_codename}/webhooks/{webhook_id}/cloudformation:
    get:
      operationId: listPortalMyTenantsWebhooksCloudformation
      summary: Get CloudFormation template for AWS webhook destination
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantList'
              example: *id015
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** Credential has no tenant associations. User must
            be associated with at least one tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id016
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/webhooks/{webhook_id}/deliveries:
    get:
      operationId: listPortalMyTenantsWebhooksDeliveries
      summary: List webhook delivery history
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantList'
              example: *id015
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** Credential has no tenant associations. User must
            be associated with at least one tenant.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id016
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/webhooks/{webhook_id}/rotate-secret:
    post:
      operationId: createPortalMyTenantsWebhooksRotateSecret
      summary: Rotate HTTPS webhook signing secret
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          description: 'Invalid tenant data


            **When this occurs:** Tenant data validation failed. Check required fields
            like codename format.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid tenant configuration
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: codename
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/webhooks/{webhook_id}/test:
    post:
      operationId: createPortalMyTenantsWebhooksTest
      summary: Send test event to tenant webhook
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          description: 'Invalid tenant data


            **When this occurs:** Tenant data validation failed. Check required fields
            like codename format.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid tenant configuration
                error_id: 550e8400-e29b-41d4-a716-446655440000
                field: codename
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_codename}/webhooks/{webhook_id}/verify:
    post:
      operationId: createPortalMyTenantsWebhooksVerify
      summary: Verify webhook endpoint connectivity (required before activation)
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_codename
        in: path
        required: true
        schema:
          type: string
        description: Tenant codename (e.g., 'acme')
      - name: webhook_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID of the webhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          description: 'User not found


            **When this occurs:** No pending user found for this email address. Ensure
            you''ve completed email verification first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: User not found or not confirmed
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_name}/domains/{domain_name}/mailboxes:
    post:
      operationId: createPortalMyTenantsDomainsMailboxes
      summary: Create mailbox (if user owns tenant) - NOT IMPLEMENTED
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_name
        in: path
        required: true
        schema:
          type: string
        description: The tenant name
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - username
              properties:
                username:
                  type: string
                  description: Local part of email address
                  pattern: ^[a-z0-9][a-z0-9._-]{0,62}[a-z0-9]$
                display_name:
                  type: string
                  description: Display name for the mailbox
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id019
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '409':
          description: 'Mailbox already exists


            **When this occurs:** A mailbox with this email address already exists
            for this domain.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Mailbox already exists
                error_id: 550e8400-e29b-41d4-a716-446655440000
    get:
      operationId: listPortalMyTenantsDomainsMailboxes
      summary: List mailboxes (if user owns tenant) - NOT IMPLEMENTED
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_name
        in: path
        required: true
        schema:
          type: string
        description: The tenant name
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MailboxList'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/my-tenants/{tenant_name}/domains/{domain_name}/mailboxes/{username}:
    get:
      operationId: getPortalMyTenantsDomainsMailboxes
      summary: Get mailbox (if user owns tenant) - NOT IMPLEMENTED
      tags:
      - mailboxes
      security:
      - cognitoJwt: []
      parameters:
      - name: tenant_name
        in: path
        required: true
        schema:
          type: string
        description: The tenant name
      - name: domain_name
        in: path
        required: true
        schema:
          type: string
        description: Full domain name (e.g., 'acme.agentmailbox.to')
      - name: username
        in: path
        required: true
        schema:
          type: string
        description: Mailbox username (local part of email)
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mailbox'
              example: *id010
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'No accessible tenants


            **When this occurs:** The credential has no tenant associations and cannot
            access mailbox data.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No accessible tenants
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/regenerate-initial-credentials:
    post:
      operationId: createPortalRegenerateInitialCredentials
      summary: Regenerate initial credentials for logged-in user (JWT auth)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                permissions:
                  type: string
                  enum:
                  - sending_only
                  - receiving_only
                  - admin
                  description: Permission level for the credential
                description:
                  type: string
                  description: Optional description for the credential
      responses:
        '400':
          description: 'Invalid or expired token


            **When this occurs:** The credential retrieval token has expired (48 hour
            limit) or has already been used. Request a new token.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Token expired or already used
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Authentication required


            **When this occurs:** First-time credential retrieval is allowed, but
            subsequent access requires Cognito authentication.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Login required for credential retrieval
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '201':
          description: Resource created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialCreated'
              example: *id020
  /api/v1/portal/request-password-token:
    post:
      operationId: createPortalRequestPasswordToken
      summary: Request password token after email verification (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: 'User not found


            **When this occurs:** No pending user found for this email address. Ensure
            you''ve completed email verification first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: User not found or not confirmed
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/resend-confirmation:
    post:
      operationId: createPortalResendConfirmation
      summary: Resend signup confirmation code to email (no auth)
      tags:
      - email
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendEmailResponse'
              example:
                message_id: 8b3f9c5e-f7f7-4fd2-91fa-187f20c3da36
                status: queued
                ses_message_id: 010001234567890a-12345678-1234-1234-1234-123456789012-000000
        '400':
          description: 'Validation error


            **When this occurs:** Attachment failed malware scan. The file has been
            quarantined and cannot be sent.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Malware detected in attachment
                error_id: 550e8400-e29b-41d4-a716-446655440000
                message: File 'document.pdf' contains malware and has been quarantined
                scan_status: quarantined
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Sending not enabled


            **When this occurs:** Domain does not have sending_enabled=true or domain
            verification is incomplete. Verify DNS records are configured correctly.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Sending not enabled for this domain
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
        '429':
          description: 'Rate limit exceeded


            **When this occurs:** Tenant has exceeded the hourly send limit (default:
            1000 emails/hour). Wait before sending more emails.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Hourly rate limit exceeded
                error_id: 550e8400-e29b-41d4-a716-446655440000
                message: Maximum 1000 emails per hour for this tenant
                current: 1000
                limit: 1000
                window: 1 hour
                retry_after: 1 hour
  /api/v1/portal/reset-credentials:
    post:
      operationId: createPortalResetCredentials
      summary: Reset API credentials for authenticated user (requires auth)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                permissions:
                  type: string
                  enum:
                  - sending_only
                  - receiving_only
                  - admin
                  description: Permission level for the credential
                description:
                  type: string
                  description: Optional description for the credential
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialCreated'
              example: *id020
        '400':
          description: 'Invalid reset request


            **When this occurs:** The specified credential does not exist or the reset
            has already been completed.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Credential not found or already reset
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Credential limit exceeded


            **When this occurs:** Maximum number of credentials for this tenant/mailbox
            has been reached. Delete unused credentials first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Credential limit exceeded
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/retrieve-initial-credentials:
    get:
      operationId: listPortalRetrieveInitialCredentials
      summary: Retrieve initial credentials for authenticated user (requires auth)
      tags:
      - credentials
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialList'
              example: *id009
        '400':
          description: 'Invalid or expired token


            **When this occurs:** The credential retrieval token has expired (48 hour
            limit) or has already been used. Request a new token.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Token expired or already used
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: 'Authentication required


            **When this occurs:** First-time credential retrieval is allowed, but
            subsequent access requires Cognito authentication.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Login required for credential retrieval
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/set-password:
    post:
      operationId: createPortalSetPassword
      summary: Set password using token from request-password-token (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: 'User not found


            **When this occurs:** No pending user found for this email address. Ensure
            you''ve completed email verification first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: User not found or not confirmed
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/setup-mfa/email:
    post:
      operationId: createPortalSetupMfaEmail
      summary: Setup Email MFA and return session tokens (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/setup-mfa/email/verify:
    post:
      operationId: createPortalSetupMfaEmailVerify
      summary: Verify Email MFA code and return session tokens (no auth)
      tags:
      - verification
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: 'User not found


            **When this occurs:** No pending user found for this email address. Ensure
            you''ve completed email verification first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: User not found or not confirmed
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/setup-mfa/totp:
    post:
      operationId: createPortalSetupMfaTotp
      summary: Setup TOTP MFA - initiate (get secret) or verify (no auth)
      tags:
      - general
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/verify-jwt:
    post:
      operationId: createPortalVerifyJwt
      summary: Verify JWT from email link, auto-verify user (no auth)
      tags:
      - verification
      security:
      - cognitoJwt: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Request body
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: 'User not found


            **When this occurs:** No pending user found for this email address. Ensure
            you''ve completed email verification first.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: User not found or not confirmed
                error_id: 550e8400-e29b-41d4-a716-446655440000
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
  /api/v1/portal/webhooks/event-types:
    get:
      operationId: listPortalWebhooksEventTypes
      summary: List all available webhook event types
      tags:
      - webhooks
      security:
      - cognitoJwt: []
      parameters:
      - name: offset
        in: query
        schema:
          type: integer
          default: 0
          minimum: 0
        description: Number of items to skip for pagination
      - name: limit
        in: query
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 250
        description: Maximum number of items to return
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
        '400':
          description: Error 400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id001
        '401':
          description: Error 401
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id002
        '403':
          description: Error 403
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id003
        '404':
          description: Error 404
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id004
        '500':
          description: Error 500
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example: *id005
components:
  securitySchemes:
    cognitoJwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: '**JWT (Customer Authenticated)** - Cognito JWT token for the customer
        portal web UI and user sessions. Obtain via Cognito authentication flow at
        the customer login page.'
  schemas:
    Error:
      type: object
      required:
      - error
      - error_id
      properties:
        error:
          type: string
          description: Error description (what failed)
        error_id:
          type: string
          format: uuid
          description: Unique error ID for support correlation
        code:
          type: string
          description: Machine-readable error code (e.g., DOMAIN_NOT_FOUND)
        message:
          type: string
          description: User-friendly error message
        hint:
          type: string
          description: Suggestion for resolving the error
        support_url:
          type: string
          format: uri
          description: URL for additional support
        field:
          type: string
          description: Field that caused validation error (400 errors only)
        missing_records:
          type: array
          items:
            type: string
          description: Missing DNS records (DNS verification errors only)
        suggestions:
          type: array
          items:
            type: string
          description: Alternative suggestions (409 Conflict only)
        allowed_methods:
          type: array
          items:
            type: string
          description: List of allowed HTTP methods (405 Method Not Allowed only)
    SuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
    ResourceDiscoveryResponse:
      type: object
      description: Response from tenant resource discovery
      properties:
        tenants:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              codename:
                type: string
              status:
                type: string
              domains:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      format: uuid
                    full_domain:
                      type: string
                    status:
                      type: string
                    mailboxes:
                      type: array
                      items:
                        type: object
                        properties:
                          id:
                            type: string
                            format: uuid
                          email:
                            type: string
                          status:
                            type: string
        summary:
          type: object
          properties:
            total_tenants:
              type: integer
            total_domains:
              type: integer
            total_mailboxes:
              type: integer
        discovered_at:
          type: string
          format: date-time
    DnsVerifyBatchResponse:
      type: object
      description: Response from batch DNS verification
      properties:
        batch_id:
          type: string
        total_domains:
          type: integer
        results:
          type: array
          items:
            type: object
            properties:
              domain_id:
                type: string
                format: uuid
              domain:
                type: string
              status:
                type: string
              dkim_status:
                type: string
              errors:
                type: array
                items:
                  type: string
        summary:
          type: object
          properties:
            verified:
              type: integer
            pending:
              type: integer
            failed:
              type: integer
    DeleteResponse:
      type: object
      properties:
        deleted:
          type: boolean
        id:
          type: string
          format: uuid
    Pagination:
      type: object
      properties:
        offset:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        has_more:
          type: boolean
    Tenant:
      type: object
      properties:
        id:
          type: string
          format: uuid
        codename:
          type: string
          description: Unique identifier (e.g., 'acme')
        status:
          type: string
          enum:
          - active
          - suspended
          - pending
        tier:
          type: string
          enum:
          - free
          - paid
        aws_ses_tenant_id:
          type: string
        aws_ses_tenant_name:
          type: string
        configuration_set_name:
          type: string
        domain_count:
          type: integer
        mailbox_count:
          type: integer
        domains:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              full_domain:
                type: string
              verification_status:
                type: string
              mailbox_count:
                type: integer
        statistics:
          type: object
          properties:
            total_domains:
              type: integer
            total_mailboxes:
              type: integer
            total_messages_sent:
              type: integer
            total_messages_received:
              type: integer
        previous_status:
          type: string
          description: Status before reactivation
        reactivated_at:
          type: string
          format: date-time
        reactivated_by:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    TenantList:
      type: object
      properties:
        tenants:
          type: array
          items:
            $ref: '#/components/schemas/Tenant'
        pagination:
          $ref: '#/components/schemas/Pagination'
    Domain:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
        tenant_codename:
          type: string
        full_domain:
          type: string
          description: e.g., 'acme.agentmailbox.to'
        subdomain:
          type: string
        parent_domain:
          type: string
        verification_status:
          type: string
          enum:
          - pending
          - verified
          - failed
        dkim_status:
          type: string
          enum:
          - pending
          - verified
          - failed
        sending_enabled:
          type: boolean
        receiving_enabled:
          type: boolean
        ses_identity_arn:
          type: string
        mailbox_count:
          type: integer
        mailboxes:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              email:
                type: string
                format: email
              display_name:
                type: string
              status:
                type: string
        dns_records:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
              name:
                type: string
              value:
                type: string
              status:
                type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    DomainList:
      type: object
      properties:
        domains:
          type: array
          items:
            $ref: '#/components/schemas/Domain'
        pagination:
          $ref: '#/components/schemas/Pagination'
    DnsStatus:
      type: object
      properties:
        domain:
          type: string
        verification_status:
          type: string
        dkim_status:
          type: string
        spf_status:
          type: string
        dmarc_status:
          type: string
        sending_enabled:
          type: boolean
        receiving_enabled:
          type: boolean
        required_records:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
              name:
                type: string
              value:
                type: string
              status:
                type: string
              verified_at:
                type: string
                format: date-time
        ai_explanation:
          type: string
          description: AI-generated setup guide
    Subdomain:
      type: object
      properties:
        id:
          type: string
          format: uuid
        subdomain:
          type: string
        full_domain:
          type: string
        tenant_id:
          type: string
          format: uuid
        tenant_codename:
          type: string
        status:
          type: string
          enum:
          - active
          - suspended
          - pending
        verification_status:
          type: string
        mailbox_count:
          type: integer
        created_at:
          type: string
          format: date-time
    SubdomainList:
      type: object
      properties:
        subdomains:
          type: array
          items:
            $ref: '#/components/schemas/Subdomain'
        pagination:
          $ref: '#/components/schemas/Pagination'
    SubdomainCreated:
      type: object
      properties:
        id:
          type: string
          format: uuid
        subdomain:
          type: string
        full_domain:
          type: string
        tenant_id:
          type: string
          format: uuid
        tenant_codename:
          type: string
        status:
          type: string
        mailboxes:
          type: array
          items:
            $ref: '#/components/schemas/Mailbox'
        dns_records:
          type: array
          items:
            type: object
        credential_retrieval_url:
          type: string
          format: uri
          description: One-time URL to retrieve API credentials
    Mailbox:
      type: object
      properties:
        id:
          type: string
          format: uuid
        domain_id:
          type: string
          format: uuid
        username:
          type: string
          description: Local part of email
        display_name:
          type: string
        email_address:
          type: string
          format: email
        created_at:
          type: string
          format: date-time
    MailboxList:
      type: object
      properties:
        mailboxes:
          type: array
          items:
            $ref: '#/components/schemas/Mailbox'
        pagination:
          $ref: '#/components/schemas/Pagination'
    CredentialCreated:
      type: object
      description: Only returned once at creation time
      properties:
        api_key_id:
          type: string
          description: Public API key (MK-xxx or AK-xxx)
        api_secret:
          type: string
          description: Secret key (shown only once)
        permissions:
          type: string
          enum:
          - sending_only
          - receiving_only
          - admin
        mailbox_id:
          type: string
          format: uuid
          nullable: true
        created_at:
          type: string
          format: date-time
    CredentialList:
      type: object
      properties:
        credentials:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              api_key_id:
                type: string
              permissions:
                type: string
              mailbox_id:
                type: string
                format: uuid
                nullable: true
              created_at:
                type: string
                format: date-time
              last_used_at:
                type: string
                format: date-time
                nullable: true
    Message:
      type: object
      properties:
        id:
          type: string
          format: uuid
        mailbox_id:
          type: string
          format: uuid
        message_id:
          type: string
          description: Email Message-ID header
        thread_id:
          type: string
          format: uuid
        direction:
          type: string
          enum:
          - inbound
          - outbound
        from_address:
          type: string
          format: email
        to_addresses:
          type: array
          items:
            type: string
            format: email
        subject:
          type: string
        body_text:
          type: string
        body_html:
          type: string
        timestamp:
          type: string
          format: date-time
        is_read:
          type: boolean
        is_archived:
          type: boolean
        has_attachments:
          type: boolean
        attachments:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              filename:
                type: string
              content_type:
                type: string
              size_bytes:
                type: integer
              download_url:
                type: string
                format: uri
    MessageList:
      type: object
      properties:
        messages:
          type: array
          items:
            $ref: '#/components/schemas/Message'
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer
    AttachmentDownload:
      type: object
      description: Attachment metadata with presigned download URL
      properties:
        id:
          type: string
          format: uuid
        filename:
          type: string
        content_type:
          type: string
        size_bytes:
          type: integer
        download_url:
          type: string
          format: uri
          description: Presigned URL for downloading the attachment (expires after
            1 hour)
        expires_at:
          type: string
          format: date-time
          description: When the download URL expires
      required:
      - id
      - filename
      - content_type
      - size_bytes
      - download_url
    SendEmailResponse:
      type: object
      properties:
        message_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - queued
          - sending
          - sent
          - held
        ses_message_id:
          type: string
          nullable: true
        held_reason:
          type: string
          nullable: true
          description: Reason if message was held (e.g., quota exceeded)
    Analytics:
      type: object
      description: Basic analytics data
      properties:
        period:
          type: string
        sent:
          type: integer
        delivered:
          type: integer
        bounced:
          type: integer
        complaints:
          type: integer
        opened:
          type: integer
        clicked:
          type: integer
        delivery_rate:
          type: number
        open_rate:
          type: number
        click_rate:
          type: number
    PortalAnalytics:
      type: object
      description: Analytics data for portal endpoints
      properties:
        period:
          type: string
        summary:
          type: object
          properties:
            sent:
              type: integer
            delivered:
              type: integer
            bounced:
              type: integer
            complaints:
              type: integer
            opened:
              type: integer
            clicked:
              type: integer
        rates:
          type: object
          properties:
            delivery_rate:
              type: number
            bounce_rate:
              type: number
            open_rate:
              type: number
            click_rate:
              type: number
        daily_breakdown:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              sent:
                type: integer
              delivered:
                type: integer
              bounced:
                type: integer
              opened:
                type: integer
    RealtimeMetrics:
      type: object
      description: Realtime metrics for a domain
      properties:
        domain:
          type: string
        period:
          type: string
        metrics:
          type: object
          properties:
            emails_sent:
              type: integer
            emails_delivered:
              type: integer
            emails_bounced:
              type: integer
            emails_complained:
              type: integer
            emails_received:
              type: integer
            delivery_rate:
              type: number
            bounce_rate:
              type: number
            complaint_rate:
              type: number
        last_updated:
          type: string
          format: date-time
    DailyMetrics:
      type: object
      description: Daily metrics breakdown
      properties:
        domain:
          type: string
        period:
          type: object
          properties:
            start:
              type: string
              format: date
            end:
              type: string
              format: date
        daily_stats:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              sent:
                type: integer
              delivered:
                type: integer
              bounced:
                type: integer
              complaints:
                type: integer
              received:
                type: integer
        totals:
          type: object
          properties:
            sent:
              type: integer
            delivered:
              type: integer
            bounced:
              type: integer
            complaints:
              type: integer
            received:
              type: integer
    MonthlyMetrics:
      type: object
      description: Monthly metrics summary
      properties:
        domain:
          type: string
        period:
          type: object
          properties:
            year:
              type: integer
            month:
              type: integer
        summary:
          type: object
          properties:
            total_sent:
              type: integer
            total_delivered:
              type: integer
            total_bounced:
              type: integer
            total_complaints:
              type: integer
            total_received:
              type: integer
            delivery_rate:
              type: number
            bounce_rate:
              type: number
            complaint_rate:
              type: number
        top_senders:
          type: array
          items:
            type: object
            properties:
              mailbox:
                type: string
              count:
                type: integer
    TrackingConfig:
      type: object
      description: Email tracking configuration for a domain
      properties:
        domain:
          type: string
        open_tracking:
          type: boolean
        click_tracking:
          type: boolean
        custom_tracking_domain:
          type: string
          nullable: true
        webhook_url:
          type: string
          format: uri
        webhook_events:
          type: array
          items:
            type: string
            enum:
            - delivered
            - bounced
            - complained
            - opened
            - clicked
        updated_at:
          type: string
          format: date-time
        message:
          type: string
    TenantAnalytics:
      type: object
      description: Tenant-wide analytics summary
      properties:
        tenant_codename:
          type: string
        period:
          type: object
          properties:
            start:
              type: string
              format: date-time
            end:
              type: string
              format: date-time
        summary:
          type: object
          properties:
            total_sent:
              type: integer
            total_delivered:
              type: integer
            total_bounced:
              type: integer
            total_complaints:
              type: integer
            total_received:
              type: integer
            delivery_rate:
              type: number
            bounce_rate:
              type: number
            complaint_rate:
              type: number
        by_domain:
          type: array
          items:
            type: object
            properties:
              domain:
                type: string
              sent:
                type: integer
              delivered:
                type: integer
              bounced:
                type: integer
              received:
                type: integer
        by_mailbox:
          type: array
          items:
            type: object
            properties:
              mailbox:
                type: string
              sent:
                type: integer
              received:
                type: integer
    DomainAnalytics:
      type: object
      description: Domain-specific analytics
      properties:
        domain:
          type: string
        period:
          type: string
        sent:
          type: integer
        delivered:
          type: integer
        bounced:
          type: integer
        complaints:
          type: integer
        received:
          type: integer
        delivery_rate:
          type: number
        bounce_rate:
          type: number
        complaint_rate:
          type: number
    DomainVerificationResult:
      type: object
      description: Result of domain verification operation
      properties:
        domain:
          type: string
        verification_triggered:
          type: boolean
        previous_status:
          type: string
          enum:
          - pending
          - verified
          - failed
        current_status:
          type: string
          enum:
          - pending
          - verified
          - failed
        verification_duration_ms:
          type: integer
        dkim_verified:
          type: boolean
        message:
          type: string
    OutboundMessageList:
      type: object
      description: List of outbound messages with pagination
      properties:
        messages:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              mailbox_id:
                type: string
                format: uuid
              from_address:
                type: string
                format: email
              to_addresses:
                type: array
                items:
                  type: string
                  format: email
              subject:
                type: string
              status:
                type: string
                enum:
                - queued
                - sent
                - delivered
                - bounced
              ses_message_id:
                type: string
              sent_at:
                type: string
                format: date-time
              delivered_at:
                type: string
                format: date-time
                nullable: true
              bounced_at:
                type: string
                format: date-time
                nullable: true
              bounce_type:
                type: string
                nullable: true
              bounce_subtype:
                type: string
                nullable: true
        pagination:
          type: object
          properties:
            offset:
              type: integer
            limit:
              type: integer
            total:
              type: integer
            has_more:
              type: boolean
    MessageAnalytics:
      type: object
      description: Analytics for a specific message
      properties:
        message_id:
          type: string
          format: uuid
        from_address:
          type: string
          format: email
        to_addresses:
          type: array
          items:
            type: string
            format: email
        subject:
          type: string
        status:
          type: string
        timeline:
          type: array
          items:
            type: object
            properties:
              event:
                type: string
              timestamp:
                type: string
                format: date-time
              user_agent:
                type: string
              url:
                type: string
        open_count:
          type: integer
        click_count:
          type: integer
        unique_opens:
          type: integer
        unique_clicks:
          type: integer
    UsageStatus:
      type: object
      properties:
        tenant_id:
          type: string
          format: uuid
        tier:
          type: string
          enum:
          - free
          - paid
        current_period:
          type: object
          properties:
            start:
              type: string
              format: date-time
            end:
              type: string
              format: date-time
            emails_sent:
              type: integer
            emails_received:
              type: integer
        limits:
          type: object
          properties:
            monthly_outbound:
              type: integer
            daily_outbound:
              type: integer
        held_messages:
          type: integer
          description: Messages held due to quota
  responses:
    BadRequest:
      description: 'Bad request - validation error


        **Common causes:**

        - Invalid email format in to/cc/bcc fields

        - Missing required fields (subject, recipients)

        - Invalid attachment format or base64 encoding

        - Attachment failed malware scan

        - Malware scan still pending (retry after a few seconds)


        **Resolution:** Check the `field` property in the response to identify which
        field caused the validation error.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Invalid email format
            error_id: 550e8400-e29b-41d4-a716-446655440000
            field: to
    Unauthorized:
      description: 'Authentication required


        **Common causes:**

        - Missing or malformed Authorization header

        - Invalid or expired JWT token

        - Token from wrong Cognito user pool


        **Resolution:** Obtain a fresh JWT token from the Engineer user pool and retry.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Authentication required
            error_id: 550e8400-e29b-41d4-a716-446655440001
            message: Invalid or expired authentication
    Forbidden:
      description: 'Insufficient permissions


        **Common causes:**

        - Credential has wrong permission type (e.g., receiving_only trying to send)

        - Mailbox-scoped credential accessing different mailbox

        - Cross-tenant access without proper authorization

        - Domain sending not enabled or verification incomplete

        - Unauthorized tenant access for admin operations


        **Resolution:** Check credential permissions match the operation. Verify domain
        is fully verified for sending.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Unauthorized send permission
            error_id: 550e8400-e29b-41d4-a716-446655440002
            message: This credential does not have permission to send emails
    NotFound:
      description: 'Resource not found


        **Common causes:**

        - Message ID does not exist

        - Mailbox does not exist or was deleted

        - Attachment reference not found in S3

        - Resource belongs to different tenant


        **Resolution:** Verify the resource ID is correct. Check you have access to
        the resource''s tenant.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Message not found
            error_id: 550e8400-e29b-41d4-a716-446655440003
    TooManyRequests:
      description: 'Rate limit exceeded


        **Rate limits (per tenant):**

        - Hourly: 1,000 emails/hour (default)

        - Daily: 1,000 emails/day (default, upgradeable)

        - Per recipient group: 100 emails/hour


        **Resolution:** Wait for the rate limit window to reset. Consider upgrading
        to paid tier for higher limits.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Hourly rate limit exceeded
            error_id: 550e8400-e29b-41d4-a716-446655440004
            message: Maximum 1000 emails per hour for this tenant
            current: 1000
            limit: 1000
            window: 1 hour
            retry_after: 1 hour
    Conflict:
      description: 'Resource conflict (duplicate, already exists)


        **Common causes:**

        - Subdomain is already taken by another tenant

        - Mailbox with same email address already exists

        - Duplicate credential name


        **Resolution:** Choose a different name. Check `suggestions` field for alternatives.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Subdomain 'acme' is already taken
            error_id: 550e8400-e29b-41d4-a716-446655440006
            suggestions:
            - acme1
            - acme2
            - acme-corp
    MethodNotAllowed:
      description: HTTP method not allowed for this endpoint
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Method not allowed
            error_id: 550e8400-e29b-41d4-a716-446655440007
            allowed_methods:
            - GET
            - POST
    InternalError:
      description: 'Internal server error


        **Common causes:**

        - Database connectivity issues

        - S3 presigned URL generation failed

        - Configuration set validation failed

        - Unexpected exception during processing


        **Resolution:** Retry the request. If error persists, contact support with
        the `error_id` for investigation.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Failed to process request
            error_id: 550e8400-e29b-41d4-a716-446655440005
            message: An error occurred while processing your request. Please contact
              support with the error ID if this persists.
  parameters:
    offsetParam:
      name: offset
      in: query
      schema:
        type: integer
        default: 0
        minimum: 0
      description: Number of items to skip
    limitParam:
      name: limit
      in: query
      schema:
        type: integer
        default: 50
        minimum: 1
        maximum: 250
      description: Maximum items to return
