openapi: 3.0.3
info:
  title: DataSea Customer API
  description: Customer-facing API surface for DataSea account, proxy, inventory, and billing workflows.
  version: 1.0.0
  contact:
    name: API Support
    email: support@datasea.io
  license:
    name: Proprietary

servers:
  - url: https://api.datasea.io
    description: Production API Gateway

security:
  - BearerAuth: []

tags:
  - name: Authentication
    description: Sign up, sign in, password recovery, and OAuth flows.
  - name: Account
    description: Current user profile, settings, proxy credentials, and API key management.
  - name: Inventory
    description: Public coverage data and authenticated IP inventory views.
  - name: Billing
    description: Customer billing, wallet, subscription, and payment actions.
  - name: Referrals
    description: Customer referral and affiliate payout settings.
  - name: System
    description: API gateway health and authenticated service status.

paths:
  /health:
    get:
      summary: Health check
      description: Return API gateway health and build metadata.
      tags: [System]
      security: []
      responses:
        '200':
          description: API gateway is healthy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'

  /coverage:
    get:
      summary: List coverage
      description: Return available proxy coverage grouped by region.
      tags: [Inventory]
      security: []
      responses:
        '200':
          description: Coverage data.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CoverageResponse'

  /coverage/{slug}:
    get:
      summary: Get coverage location
      description: Return coverage details for a region, country, state, or city slug.
      tags: [Inventory]
      security: []
      parameters:
        - $ref: '#/components/parameters/SlugPath'
      responses:
        '200':
          description: Coverage detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'

  /login:
    post:
      summary: Sign in
      description: Authenticate with account credentials and receive a bearer token.
      tags: [Authentication]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
      responses:
        '200':
          description: Authentication succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /register:
    post:
      summary: Create account
      description: Register a new account and receive an initial bearer token.
      tags: [Authentication]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterRequest'
      responses:
        '201':
          description: Registration succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'

  /auth/password/forgot:
    post:
      summary: Request password reset
      description: Start a password reset flow for an account email address.
      tags: [Authentication]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email:
                  type: string
                  format: email
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /auth/password/reset:
    post:
      summary: Complete password reset
      description: Set a new password with a valid password reset token.
      tags: [Authentication]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token, newPassword]
              properties:
                token:
                  type: string
                newPassword:
                  type: string
                  minLength: 8
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /auth/{provider}/login:
    get:
      summary: Start OAuth login
      description: Redirect to a supported OAuth provider consent screen.
      tags: [Authentication]
      security: []
      parameters:
        - $ref: '#/components/parameters/OAuthProvider'
        - name: redirect
          in: query
          schema:
            type: string
            format: uri
          description: Optional frontend callback URL.
      responses:
        '302':
          description: Redirect to the OAuth provider.
        '400':
          $ref: '#/components/responses/BadRequest'

  /auth/exchange:
    post:
      summary: Exchange OAuth login token
      description: Exchange a short-lived OAuth login token for an application bearer token.
      tags: [Authentication]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [loginToken]
              properties:
                loginToken:
                  type: string
      responses:
        '200':
          description: OAuth exchange succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
        '400':
          $ref: '#/components/responses/BadRequest'

  /auth/email/verify:
    get:
      summary: Verify email
      description: Verify an account email address with a token from email.
      tags: [Authentication]
      security: []
      parameters:
        - name: token
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          $ref: '#/components/responses/Conflict'

  /auth/email/verify/resend:
    post:
      summary: Resend verification email
      description: Send another verification email for the authenticated user.
      tags: [Authentication]
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /whoami:
    get:
      summary: Current authentication context
      description: Return the authenticated user identifier, username, and roles.
      tags: [Account]
      responses:
        '200':
          description: Current authentication context.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  userId:
                    type: string
                    format: uuid
                  username:
                    type: string
                  roles:
                    type: array
                    items:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/profile:
    get:
      summary: Get profile
      description: Return the authenticated user's account profile.
      tags: [Account]
      responses:
        '200':
          description: User profile.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserProfile'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/stats:
    get:
      summary: Get account stats
      description: Return high-level account and proxy usage stats for the authenticated user.
      tags: [Account]
      responses:
        '200':
          description: User stats.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/settings:
    get:
      summary: Get account settings
      description: Return profile, notification, security, and billing preferences.
      tags: [Account]
      responses:
        '200':
          description: Account settings.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/settings/profile:
    put:
      summary: Update profile settings
      tags: [Account]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/settings/notifications:
    put:
      summary: Update notification settings
      tags: [Account]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/settings/security:
    put:
      summary: Update security settings
      tags: [Account]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/settings/password:
    post:
      summary: Change account password
      tags: [Account]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [currentPassword, newPassword]
              properties:
                currentPassword:
                  type: string
                  format: password
                newPassword:
                  type: string
                  format: password
                  minLength: 8
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/api-keys:
    get:
      summary: List API keys
      description: Return API key metadata for the authenticated user. Plaintext key material is only returned on creation.
      tags: [Account]
      responses:
        '200':
          description: API key metadata.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      summary: Create API key
      description: Create an API key and return the plaintext key once.
      tags: [Account]
      responses:
        '201':
          description: API key created.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /user/api-keys/{tokenId}:
    delete:
      summary: Delete API key
      tags: [Account]
      parameters:
        - name: tokenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /user/proxy-credentials:
    post:
      summary: Reveal proxy credentials
      description: Verify account password and return proxy username plus current proxy password when available.
      tags: [Account]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [password]
              properties:
                password:
                  type: string
                  format: password
      responses:
        '200':
          description: Proxy credentials.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProxyCredentialResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /user/proxy-password/reset:
    post:
      summary: Reset proxy password
      description: Generate and return a new proxy password for the authenticated user.
      tags: [Account]
      responses:
        '200':
          description: New proxy password.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProxyCredentialResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /user/proxy-passwords:
    get:
      summary: List proxy passwords
      description: Return proxy password metadata. Plaintext password material is only returned on creation.
      tags: [Account]
      responses:
        '200':
          description: Proxy password metadata.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      summary: Create proxy password
      description: Create an additional proxy password and return the plaintext password once.
      tags: [Account]
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                label:
                  type: string
      responses:
        '201':
          description: Proxy password created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProxyCredentialResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /user/proxy-passwords/{id}/deactivate:
    post:
      summary: Deactivate proxy password
      tags: [Account]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /user/proxy-passwords/{id}/reactivate:
    post:
      summary: Reactivate proxy password
      tags: [Account]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /allocate-ip:
    post:
      summary: Allocate IP address
      description: Allocate an IP address for proxy use through the API gateway.
      tags: [Inventory]
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                country:
                  type: string
                  example: US
                protocol:
                  type: string
                  enum: [http, https, socks5]
      responses:
        '200':
          description: IP allocation result.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /ips:
    get:
      summary: List available IPs
      description: Return available IP inventory through the API gateway.
      tags: [Inventory]
      parameters:
        - name: country
          in: query
          schema:
            type: string
        - name: protocol
          in: query
          schema:
            type: string
            enum: [http, https, socks5]
        - name: limit
          in: query
          schema:
            type: integer
            maximum: 100
      responses:
        '200':
          description: Available IPs.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /ips/{id}:
    get:
      summary: Get IP details
      tags: [Inventory]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          description: IP details.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /accounting/products:
    get:
      summary: List products
      description: Return available billing products and pricing metadata.
      tags: [Billing]
      responses:
        '200':
          description: Product catalog.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /accounting/subscriptions:
    get:
      summary: List subscriptions
      tags: [Billing]
      responses:
        '200':
          description: User subscriptions.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      summary: Create subscription
      tags: [Billing]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '201':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/subscriptions/{id}:
    put:
      summary: Update subscription
      tags: [Billing]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      summary: Cancel subscription
      tags: [Billing]
      parameters:
        - $ref: '#/components/parameters/UuidId'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /accounting/billing:
    get:
      summary: Get billing summary
      tags: [Billing]
      responses:
        '200':
          description: Billing summary.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /accounting/billing/wallet:
    get:
      summary: Get wallet settings
      tags: [Billing]
      responses:
        '200':
          description: Wallet settings.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /accounting/billing/transactions:
    get:
      summary: List billing transactions
      tags: [Billing]
      responses:
        '200':
          description: Billing transactions.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /accounting/billing/auto-topup:
    put:
      summary: Update auto top-up settings
      tags: [Billing]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/billing/payment-methods/setup-intent:
    post:
      summary: Create payment method setup intent
      tags: [Billing]
      responses:
        '200':
          description: Setup intent.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/billing/payment-methods:
    get:
      summary: List payment methods
      tags: [Billing]
      responses:
        '200':
          description: Payment methods.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /accounting/billing/payment-methods/default:
    post:
      summary: Set default payment method
      tags: [Billing]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/billing/payment-methods/{id}:
    delete:
      summary: Delete payment method
      tags: [Billing]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /accounting/billing/payment-methods/charge:
    post:
      summary: Charge saved payment method
      tags: [Billing]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          description: Charge result.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/payments/intent:
    post:
      summary: Create payment intent or order
      description: Create a Stripe PaymentIntent or PayPal Order bound to the authenticated user.
      tags: [Billing]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentIntentRequest'
      responses:
        '200':
          description: Payment intent or order created.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/payments/finalize:
    post:
      summary: Finalize payment
      description: Finalize a provider payment after server-side verification.
      tags: [Billing]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [provider, providerPaymentId]
              properties:
                provider:
                  type: string
                  enum: [stripe, paypal]
                providerPaymentId:
                  type: string
      responses:
        '200':
          description: Finalized payment.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/balances/bandwidth:
    get:
      summary: Get bandwidth balance
      tags: [Billing]
      responses:
        '200':
          description: Bandwidth balance.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /accounting/bandwidth/purchase:
    post:
      summary: Purchase bandwidth with wallet balance
      tags: [Billing]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          description: Purchase result.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /accounting/coupons/preview:
    post:
      summary: Preview coupon
      tags: [Billing]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          description: Coupon preview.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/referrals:
    get:
      summary: Get referral summary
      tags: [Referrals]
      responses:
        '200':
          description: Referral summary.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/referrals/custom-code:
    patch:
      summary: Update custom referral code
      tags: [Referrals]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customCode]
              properties:
                customCode:
                  type: string
                  nullable: true
      responses:
        '200':
          description: Updated referral summary.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'

  /accounting/referrals/payout-settings:
    get:
      summary: Get referral payout settings
      tags: [Referrals]
      responses:
        '200':
          description: Payout settings.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
    put:
      summary: Update referral payout settings
      tags: [Referrals]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /accounting/referrals/payouts:
    get:
      summary: List referral payouts
      tags: [Referrals]
      responses:
        '200':
          description: Referral payouts.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      summary: Create referral payout request
      tags: [Referrals]
      requestBody:
        $ref: '#/components/requestBodies/JsonObject'
      responses:
        '200':
          $ref: '#/components/responses/Accepted'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /health/services:
    get:
      summary: Check backend services
      description: Return authenticated status checks for API dependencies.
      tags: [System]
      responses:
        '200':
          description: Service health details.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  parameters:
    SlugPath:
      name: slug
      in: path
      required: true
      schema:
        type: string
    UuidId:
      name: id
      in: path
      required: true
      schema:
        type: string
        format: uuid
    OAuthProvider:
      name: provider
      in: path
      required: true
      schema:
        type: string
        enum: [google, github]

  requestBodies:
    JsonObject:
      required: true
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true

  responses:
    Accepted:
      description: Request accepted.
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true
    BadRequest:
      description: Invalid request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Missing, invalid, or expired bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Authenticated user cannot perform this action.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Conflict:
      description: Request conflicts with existing state.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: Rate limit exceeded.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  schemas:
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
        detail:
          type: string
        details:
          type: string
        retryAfterSeconds:
          type: integer

    HealthResponse:
      type: object
      properties:
        service:
          type: string
          example: api-gateway
        status:
          type: string
          example: healthy
        timestamp:
          type: string
          format: date-time
        version:
          type: object
          additionalProperties: true

    CoverageResponse:
      type: object
      properties:
        generatedAt:
          type: string
          format: date-time
        regions:
          type: array
          items:
            type: object
            additionalProperties: true

    LoginRequest:
      type: object
      required: [username, password]
      properties:
        username:
          type: string
        password:
          type: string
          format: password

    RegisterRequest:
      type: object
      required: [username, email, password]
      properties:
        username:
          type: string
          minLength: 3
          maxLength: 30
        email:
          type: string
          format: email
        password:
          type: string
          format: password
          minLength: 8
        bio:
          type: string
          nullable: true
        referralCode:
          type: string
          nullable: true

    AuthResponse:
      type: object
      properties:
        success:
          type: boolean
        message:
          type: string
        token:
          type: string
          description: JWT bearer token.
        user:
          $ref: '#/components/schemas/User'

    User:
      type: object
      properties:
        userId:
          type: string
          format: uuid
        username:
          type: string
        email:
          type: string
          format: email
        status:
          type: string
        emailVerified:
          type: boolean
        emailVerifiedAt:
          type: string
          format: date-time
          nullable: true
        lastLoginAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    UserProfile:
      type: object
      additionalProperties: true
      properties:
        success:
          type: boolean
        userId:
          type: string
          format: uuid
        username:
          type: string
        email:
          type: string
          format: email

    ProxyCredentialResponse:
      type: object
      properties:
        success:
          type: boolean
        proxyUsername:
          type: string
        proxyPassword:
          type: string
          description: Returned only when plaintext credential material is intentionally revealed.

    PaymentIntentRequest:
      type: object
      required: [provider, amountCents]
      properties:
        provider:
          type: string
          enum: [stripe, paypal]
        amountCents:
          type: integer
          minimum: 1
        currency:
          type: string
          example: USD
        product:
          type: string
          example: residential_proxy
        idempotencyKey:
          type: string
        metadata:
          type: object
          additionalProperties: true
