openapi: 3.0.3
info:
  title: EVA | Email Verification API
  description: |
    # Introduction

    EVA is a production-grade email verification API with 99% accuracy. One API call delivers complete verification, including syntax validation, SMTP verification, disposable detection, domain intelligence, and deliverability scoring.

    **Base URL:** `https://verifications.email`

    ## Quick Start

    Get your first verification result in three steps.

    ### 1. Create an account

    ```bash
    curl -X POST https://verifications.email/api/v1/auth/signup \
      -H "Content-Type: application/json" \
      -d '{"email": "you@company.com", "password": "your-secure-password"}'
    ```

    Response:
    ```json
    {"data": {"token": "eyJhbG..."}}
    ```

    ### 2. Create an API key

    Use the JWT token from step 1:

    ```bash
    curl -X POST https://verifications.email/api/v1/keys \
      -H "Authorization: Bearer eyJhbG..." \
      -H "Content-Type: application/json" \
      -d '{"name": "production"}'
    ```

    Response:
    ```json
    {"data": {"id": "...", "key": "eva_abc123...", "name": "production"}}
    ```

    Save this key securely. It will only be shown once.

    ### 3. Verify an email

    ```bash
    curl -H "X-API-Key: eva_abc123..." \
      "https://verifications.email/api/v1/verify?email=user@gmail.com"
    ```

    ## Authentication

    The API uses two authentication methods:

    **JWT Bearer Token** - used for account management, API key creation, usage stats. Header: `Authorization: Bearer <token>`. Tokens expire after 24 hours. Get a new one by calling POST `/api/v1/auth/login`.

    **API Key** - used for email verification (single and batch). Header: `X-API-Key: eva_your_key`. Keys use the format `eva_` followed by a 64-character hex string. Create them via the dashboard or the API.

    ## Rate Limits

    Verification endpoints return rate limit headers on every response:

    - `X-RateLimit-Limit` - Requests allowed per minute
    - `X-RateLimit-Remaining` - Requests remaining in current window
    - `X-RateLimit-Reset` - Seconds until the window resets

    When the rate limit is exceeded, the API returns HTTP 429 with a `Retry-After` header.

    ## Error Format

    All errors follow a consistent format:

    ```json
    {"error": "description of what went wrong", "code": "ERROR_CODE"}
    ```

    **Status codes:**

    - **200** - Success
    - **400** - Bad request. Missing or invalid parameters.
    - **401** - Unauthorized. Missing or invalid credentials.
    - **403** - Forbidden. Account suspended or insufficient permissions.
    - **429** - Rate limit exceeded.
    - **500** - Internal server error.

    ## SDKs

    Official client libraries:

    - **cURL** - Built-in. No installation required.
    - **JavaScript / TypeScript** - Coming soon
    - **Python** - Coming soon
    - **Go** - Coming soon

    For API support, contact [atak@verifications.email](mailto:atak@verifications.email) or visit [verifications.email](https://verifications.email).
  version: 1.0.0
  contact:
    name: EVA API Support
    url: https://verifications.email
    email: atak@verifications.email

servers:
  - url: https://verifications.email
    description: Production

tags:
  - name: Auth
    description: |
      Register a new account or log in to receive a JWT token.
      The token is required for API key management and usage statistics.
  - name: API Keys
    description: |
      Create, list, and revoke API keys. Keys are used to authenticate
      verification requests via the `X-API-Key` header.
  - name: Verification
    description: |
      Verify email addresses individually or in batches. Each verification
      performs a complete verification and returns a comprehensive result with deliverability
      scoring, domain intelligence, and risk assessment.
  - name: Usage
    description: |
      View verification usage statistics for your account, broken down by
      billing period.
  - name: Health
    description: Service health check for monitoring uptime and dependency status.

paths:
  /health:
    get:
      tags: [Health]
      summary: Health check
      description: |
        Returns the current health status of the API and its backing services
        (database, cache). Use this endpoint for uptime monitoring and
        load balancer health probes.
      responses:
        "200":
          description: Service healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: healthy
                  services:
                    type: object
                    properties:
                      database:
                        type: string
                        example: up
                      cache:
                        type: string
                        example: up

  /api/v1/auth/signup:
    post:
      tags: [Auth]
      summary: Register a new account
      description: |
        Create a new EVA account. Returns a JWT token that you can use
        immediately to create API keys and access account endpoints.

        The password must be at least 8 characters. The email must not
        already be registered.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                  format: email
                  example: user@example.com
                password:
                  type: string
                  minLength: 8
                  example: securepass123
      responses:
        "201":
          description: Account created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuthResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "409":
          description: Email already registered
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/v1/auth/login:
    post:
      tags: [Auth]
      summary: Login and receive JWT token
      description: |
        Authenticate with your email and password. Returns a JWT token
        valid for 24 hours. Use this token in the `Authorization: Bearer`
        header when calling account management endpoints.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
      responses:
        "200":
          description: Login successful
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuthResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /api/v1/keys:
    post:
      tags: [API Keys]
      summary: Create a new API key
      description: |
        Generate a new API key. The full key is returned only once in the response.
        Store it securely. It cannot be retrieved again.

        Use this key in the `X-API-Key` header when calling verification endpoints.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: production
      responses:
        "201":
          description: API key created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      key:
                        type: string
                        description: Full API key (shown only once)
                        example: eva_1f1bd2d4d994c0afdd2fd6726af848ab...
                      id:
                        type: string
                        format: uuid
                      name:
                        type: string
                      key_prefix:
                        type: string
                        example: eva_1f1bd2d4
        "401":
          $ref: "#/components/responses/Unauthorized"
    get:
      tags: [API Keys]
      summary: List all API keys
      description: |
        Returns all API keys associated with your account. For security,
        only the key prefix is returned (not the full key). Use the key
        name and prefix to identify keys for revocation.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of API keys (prefixes only)
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/APIKey"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /api/v1/keys/{id}:
    delete:
      tags: [API Keys]
      summary: Revoke an API key
      description: |
        Permanently revoke an API key. Any subsequent requests using this
        key will receive a 401 Unauthorized response. This action cannot
        be undone.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: UUID of the API key to revoke.
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Key revoked
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: Key not found

  /api/v1/verify:
    post:
      tags: [Verification]
      summary: Verify a single email address
      description: |
        Submit a single email address for verification via JSON body.
        The API performs a complete verification including syntax validation, MX record
        lookup, SMTP mailbox verification, disposable and role-based
        detection, catch-all scoring, deliverability assessment, and more.

        Results are cached for 6 hours. Repeated requests for the same
        email within that window do not count against your quota.
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email:
                  type: string
                  format: email
                  example: user@gmail.com
      responses:
        "200":
          description: Verification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/VerificationResult"
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Requests allowed per minute
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Requests remaining in current window
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
    get:
      tags: [Verification]
      summary: Verify a single email (query param)
      description: |
        Verify a single email address by passing it as a query parameter.
        This is a convenience alternative to the POST endpoint. Both
        endpoints return identical results and share the same rate limits.

        Results are cached for 6 hours. Repeated requests for the same
        email within that window do not count against your quota.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: email
          in: query
          required: true
          description: The email address to verify.
          schema:
            type: string
            format: email
      responses:
        "200":
          description: Verification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/VerificationResult"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /api/v1/verify/batch:
    post:
      tags: [Verification]
      summary: Verify a batch of emails
      description: |
        Verify up to 100 email addresses in a single request. Emails are
        processed concurrently for maximum throughput. Each email counts
        individually toward your monthly quota.

        The response includes a `total` count and an array of results in
        the same order as the input. Cached results (within the 6-hour
        window) do not count against your quota.
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [emails]
              properties:
                emails:
                  type: array
                  items:
                    type: string
                    format: email
                  minItems: 1
                  maxItems: 100
                  example: ["user@gmail.com", "test@company.com"]
      responses:
        "200":
          description: Batch verification results
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      total:
                        type: integer
                      results:
                        type: array
                        items:
                          $ref: "#/components/schemas/VerificationResult"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /api/v1/usage:
    get:
      tags: [Usage]
      summary: Get usage statistics
      description: |
        Returns verification counts for the current billing period,
        broken down by API key. Use this to monitor consumption against
        your plan limits and identify which keys are generating the
        most traffic.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Usage statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      plan:
                        type: string
                        example: free
                      period_start:
                        type: string
                        format: date
                      period_end:
                        type: string
                        format: date
                      monthly_limit:
                        type: integer
                      total_used:
                        type: integer
                      keys:
                        type: array
                        items:
                          type: object
                          properties:
                            key_prefix:
                              type: string
                            name:
                              type: string
                            verification_count:
                              type: integer
        "401":
          $ref: "#/components/responses/Unauthorized"

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token from /auth/login or /auth/signup
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key from /keys endpoint

  schemas:
    VerificationResult:
      type: object
      properties:
        email:
          type: string
          example: user@gmail.com
        score:
          type: integer
          minimum: 0
          maximum: 100
          description: "Composite deliverability score (0-100)"
          example: 75
        risk:
          type: string
          enum: [safe, risky, invalid]
          description: "safe (>=70), risky (40-69), invalid (<40)"
        syntax_valid:
          type: boolean
        mx_found:
          type: boolean
        smtp_check:
          type: string
          enum: [deliverable, undeliverable, risky, unknown]
        is_disposable:
          type: boolean
        is_role_account:
          type: boolean
        is_catch_all:
          type: boolean
        is_free_provider:
          type: boolean
        spam_trap_risk:
          type: string
          enum: [low, medium, high]
        suggested_correction:
          type: string
          nullable: true
          description: Suggested email if domain typo detected
        mx_records:
          type: array
          items:
            type: string
        is_security_gateway:
          type: boolean
          description: True if domain routes through a security gateway (Mimecast, Proofpoint, etc.)
        security_gateway:
          type: string
          description: Gateway name (mimecast, proofpoint) or empty
          enum: [mimecast, proofpoint, ""]
        has_gravatar:
          type: boolean
          description: True if email has a Gravatar profile image
        gravatar_url:
          type: string
          description: Gravatar profile image URL (only present if has_gravatar is true)
        catch_all_confidence:
          type: integer
          minimum: 0
          maximum: 100
          description: Confidence score for catch-all detection. 0 means definitively not catch-all, 100 means definitively catch-all.
          example: 15
        is_b2b:
          type: boolean
          description: Whether the email domain is a business (B2B) domain rather than a consumer provider.
          example: false
        smtp_provider:
          type: string
          description: Identified email service provider handling mail for this domain.
          example: "google"
        is_disabled:
          type: boolean
          description: Whether the mailbox appears to be disabled or suspended.
          example: false
        is_full_inbox:
          type: boolean
          description: Whether the mailbox is full and unable to receive new messages.
          example: false
        response_latency_ms:
          type: integer
          description: SMTP server response time in milliseconds. Higher values may indicate server issues.
          example: 245
        has_sub_addressing:
          type: boolean
          description: Whether the email uses sub-addressing (plus addressing, e.g. user+tag@domain.com).
          example: false
        sub_address_base:
          type: string
          nullable: true
          description: The base email address before any sub-address separator. Null if no sub-addressing detected.
          example: null
        domain_age:
          type: object
          nullable: true
          description: Domain registration age information from RDAP/WHOIS lookup.
          properties:
            domain_name:
              type: string
              description: The domain name that was looked up.
              example: "gmail.com"
            created_date:
              type: string
              nullable: true
              description: Domain registration date in ISO 8601 format.
              example: "1995-08-13T00:00:00Z"
            updated_date:
              type: string
              nullable: true
              description: Domain last updated date.
              example: "2024-06-13T00:00:00Z"
            expires_date:
              type: string
              nullable: true
              description: Domain expiration date.
              example: "2025-08-12T00:00:00Z"
            age_days:
              type: integer
              description: Domain age in days since registration.
              example: 11180
            registrar:
              type: string
              nullable: true
              description: Domain registrar name.
              example: "MarkMonitor Inc."
            risk_level:
              type: string
              enum: [low, medium, high]
              description: Risk level based on domain age. Domains under 30 days are high risk, under 90 days medium, otherwise low.
              example: "low"
            source:
              type: string
              enum: [rdap, whois]
              description: Data source used for the lookup.
              example: "rdap"
        deliverability:
          type: object
          nullable: true
          description: Composite deliverability assessment including authentication and blacklist checks.
          properties:
            grade:
              type: string
              enum: [A, B, C, D, F]
              description: Letter grade summarising overall deliverability quality.
              example: "A"
            score:
              type: integer
              minimum: 0
              maximum: 100
              description: Numeric deliverability score (0-100).
              example: 92
            authentication:
              type: object
              description: Email authentication record results.
              properties:
                spf:
                  type: boolean
                  description: Whether a valid SPF record is published for the domain.
                  example: true
                dkim:
                  type: boolean
                  description: Whether a DKIM public key record is published for the domain.
                  example: true
                dmarc:
                  type: boolean
                  description: Whether a DMARC policy record is published for the domain.
                  example: true
            blacklist:
              type: object
              description: Domain/IP blacklist check results.
              properties:
                listed:
                  type: boolean
                  description: Whether the domain or its mail server IPs appear on any checked blacklist.
                  example: false
                listed_count:
                  type: integer
                  description: Number of blacklists on which the domain is currently listed.
                  example: 0
                total_checks:
                  type: integer
                  description: Total number of blacklists checked.
                  example: 15

    APIKey:
      type: object
      properties:
        id:
          type: string
          format: uuid
        key_prefix:
          type: string
          example: eva_1f1bd2d4
        name:
          type: string
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time

    AuthResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            token:
              type: string
              description: JWT token (24h expiry)

    Error:
      type: object
      properties:
        error:
          type: string
        code:
          type: string

  responses:
    BadRequest:
      description: Invalid input
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Authentication required or invalid
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    RateLimited:
      description: Rate limit exceeded
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds until rate limit resets
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
