openapi: 3.0.3
info:
  title: Bounceler Client Bulk Email API
  version: 1.0.0
  description: |
    Client-facing bulk email verification API.
    Authenticate every request with your API key in the `Authorization` header.
servers:
  - url: /
security:
  - apiKeyAuth: []
tags:
  - name: Bulk Email
paths:
  /api/email/bulk/verify:
    post:
      tags: [Bulk Email]
      summary: Verify up to 10,000 emails and return a request id
      description: |
        Submit a bulk verification job for up to 10,000 email addresses in a single request.
        The API validates the input, checks account credit availability, and creates an async job tied to your API key.
        Use the returned `request_id` to poll job status or fetch final results.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkVerifyRequest'
            examples:
              basic:
                value:
                  emails:
                    - first@example.com
                    - second@example.com
      responses:
        '200':
          description: Request accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkSubmitResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/MissingAuthorizationError'
        '402':
          $ref: '#/components/responses/InvalidAuthorizationError'
        '403':
          $ref: '#/components/responses/OldAuthorizationError'
        '405':
          $ref: '#/components/responses/NotEnoughCreditsError'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /api/email/bulk/{request_id}/status:
    get:
      tags: [Bulk Email]
      summary: Get bulk verification job status
      description: |
        Retrieve the current status of a previously submitted bulk verification job by `request_id`.
        Use this endpoint for polling while the async verification is still processing.
      parameters:
        - name: request_id
          in: path
          required: true
          description: Bulk verification request id returned by the verify endpoint.
          schema:
            type: string
      responses:
        '200':
          description: Current job status
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/BulkProgressResponse'
                  - $ref: '#/components/schemas/BulkDoneStatusResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/MissingAuthorizationError'
        '402':
          $ref: '#/components/responses/InvalidAuthorizationError'
        '403':
          $ref: '#/components/responses/OldAuthorizationError'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /api/email/bulk/results:
    post:
      tags: [Bulk Email]
      summary: Get completed bulk email verification results
      description: |
        Retrieve the final results of a previously submitted bulk verification job by `request_id`.
        While processing is still running, the API returns an in-progress response so the client can continue polling or switch to the dedicated status endpoint.
        Once the job finishes, this endpoint returns the completed verification results and summary data.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkResultsRequest'
            examples:
              basic:
                value:
                  request_id: upd_12345678-1234-1234-1234-123456789abc
      responses:
        '200':
          description: In-progress or completed response
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/BulkProgressResponse'
                  - $ref: '#/components/schemas/BulkDoneResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/MissingAuthorizationError'
        '402':
          $ref: '#/components/responses/InvalidAuthorizationError'
        '403':
          $ref: '#/components/responses/OldAuthorizationError'
        '500':
          $ref: '#/components/responses/InternalServerError'

components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization

  responses:
    BadRequestError:
      description: Invalid request payload or invalid input values.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/MessageError'
          examples:
            invalidPayload:
              value:
                message: request_id is required.
    MissingAuthorizationError:
      description: The `Authorization` header is missing.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/MessageError'
          examples:
            missingAuthorization:
              value:
                message: Missing authorization key
    InvalidAuthorizationError:
      description: The API key format is invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/MessageError'
          examples:
            invalidAuthorization:
              value:
                message: Invalid authorization key, make sure you copy the full key.
    OldAuthorizationError:
      description: The API key is deleted or no longer current.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/MessageError'
          examples:
            oldAuthorization:
              value:
                message: Old authorization key
    NotEnoughCreditsError:
      description: The account does not have enough credits to start the bulk request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/MessageError'
          examples:
            notEnoughCredits:
              value:
                message: You do not have enough credits for this operation
    InternalServerError:
      description: Unexpected server-side failure.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/MessageError'
          examples:
            internalServerError:
              value:
                message: Internal server error

  schemas:
    BulkVerifyRequest:
      type: object
      properties:
        emails:
          type: array
          minItems: 1
          maxItems: 10000
          items:
            type: string
      required: [emails]

    BulkResultsRequest:
      type: object
      properties:
        request_id:
          type: string
      required: [request_id]

    BulkEmailSummary:
      type: object
      properties:
        original_counter:
          type: integer
        duplication_counter:
          type: integer
        valid_counter:
          type: integer
        invalid_counter:
          type: integer
        valid_sample:
          type: array
          items:
            type: string
        invalid_sample:
          type: array
          items:
            type: string
        duplicated_sample:
          type: array
          items:
            type: string
      required:
        - original_counter
        - duplication_counter
        - valid_counter
        - invalid_counter
        - valid_sample
        - invalid_sample
        - duplicated_sample

    BulkSubmitResponse:
      type: object
      properties:
        request_id:
          type: string
        accepted:
          type: boolean
        email_summary:
          $ref: '#/components/schemas/BulkEmailSummary'
      required:
        - request_id
        - accepted
        - email_summary

    BulkProgressResponse:
      type: object
      properties:
        request_id:
          type: string
        status:
          type: string
          enum: [in_progress]
      required:
        - request_id
        - status

    BulkDoneResponse:
      type: object
      properties:
        request_id:
          type: string
        status:
          type: string
          enum: [done]
        summary:
          type: object
          additionalProperties: true
        results:
          type: array
          items:
            $ref: '#/components/schemas/EmailVerificationResult'
      required:
        - request_id
        - status
        - results

    BulkDoneStatusResponse:
      type: object
      properties:
        request_id:
          type: string
        status:
          type: string
          enum: [done]
      required:
        - request_id
        - status

    EmailVerificationResult:
      type: object
      properties:
        upload_uuid:
          type: string
          nullable: true
        email:
          type: string
          nullable: true
        email_index:
          type: integer
          nullable: true
        deliverable:
          type: string
          nullable: true
          enum: [DELIVERABLE, UNDELIVERABLE, TEMPORARILY_UNDELIVERABLE, RISKY, UNKNOWN, UNCHECKED]
        reason:
          type: string
          nullable: true
        format:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        dns:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        smtp_connect:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        smtp_verify:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        risk_domain_catch_all:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        risk_domain_disposable:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        risk_email_role:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        risk_email_gibberish:
          type: string
          enum: [VALID, INVALID, UNKNOWN, UNCHECKED]
        processed:
          type: boolean
        charged:
          type: boolean
      required:
        - upload_uuid
        - email
        - email_index
        - deliverable
        - reason
        - format
        - dns
        - smtp_connect
        - smtp_verify
        - risk_domain_catch_all
        - risk_domain_disposable
        - risk_email_role
        - risk_email_gibberish
        - processed
        - charged

    MessageError:
      type: object
      properties:
        message:
          type: string
      required: [message]
