{
  "openapi": "3.0.3",
  "info": {
    "title": "VeriMails API",
    "version": "1.0.0",
    "summary": "Email verification, bulk list verification, and an Email Finder.",
    "description": "VeriMails verifies email addresses with syntax validation, MX record lookup, DNS checks, and a live SMTP handshake where the receiving server allows it. It detects catch-all domains, disposable addresses, and role-based addresses, and returns an overall deliverability result.\n\nThe API also includes asynchronous bulk CSV verification and an Email Finder for missing business contact emails.\n\nAuthentication: every endpoint except the health check requires an API key sent as a Bearer token. Issue keys from your VeriMails dashboard.\n\nCredits: verification costs 1 credit per email address. The Email Finder costs 10 credits, charged only when a verified email is found. New accounts start with 100 free credits, and prepaid credits never expire.",
    "contact": {
      "name": "VeriMails Support",
      "email": "support@verimails.com",
      "url": "https://verimails.com/contact"
    },
    "termsOfService": "https://verimails.com/terms"
  },
  "externalDocs": {
    "description": "Full API documentation",
    "url": "https://verimails.com/docs"
  },
  "servers": [
    {
      "url": "https://verimails.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Verification",
      "description": "Verify whether a single email address is real and deliverable."
    },
    {
      "name": "Bulk Verification",
      "description": "Verify entire lists by uploading a CSV file and polling an asynchronous job."
    },
    {
      "name": "Email Finder",
      "description": "Find and verify missing business contact emails from first name, last name, and company domain."
    },
    {
      "name": "Health",
      "description": "Service status and availability."
    }
  ],
  "paths": {
    "/api/verify/single": {
      "post": {
        "tags": [
          "Verification"
        ],
        "summary": "Verify one email address",
        "description": "Runs syntax validation, MX record lookup, DNS checks, and a live SMTP handshake where the receiving server allows it. Catch-all domains are detected and flagged. Costs 1 credit.",
        "operationId": "verifySingle",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              },
              "example": {
                "email": "person@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SingleVerifyResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/bulk": {
      "post": {
        "tags": [
          "Bulk Verification"
        ],
        "summary": "Upload a CSV for bulk verification",
        "description": "Uploads a CSV file and starts an asynchronous bulk verification job. Provide `email_column` when the email field is not auto-detected. Recognised headers include email, Email, Email Address, emails, work_email, business_email, and contact_email. Headerless single-column files are also supported. Each address costs 1 credit.",
        "operationId": "createBulkJob",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV file of email addresses to verify."
                  },
                  "email_column": {
                    "type": "string",
                    "description": "Name of the column holding email addresses. Optional when the column can be auto-detected."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bulk verification job created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkJobResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/api/bulk/{job_id}": {
      "get": {
        "tags": [
          "Bulk Verification"
        ],
        "summary": "Get bulk job status",
        "description": "Returns the current status and running counts of a bulk verification job. Poll this endpoint until `status` is `completed`.",
        "operationId": "getBulkJob",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "The bulk job ID returned when the job was created.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current job status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkJobResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/bulk/{job_id}/download": {
      "get": {
        "tags": [
          "Bulk Verification"
        ],
        "summary": "Download bulk results as CSV",
        "description": "Downloads the completed verification results as a CSV file. Returns 409 if the job has not finished yet.",
        "operationId": "downloadBulkResults",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "The bulk job ID.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file of verification results.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/JobNotComplete"
          }
        }
      }
    },
    "/api/find-email": {
      "post": {
        "tags": [
          "Email Finder"
        ],
        "summary": "Find an email address",
        "description": "Finds and verifies a missing business contact email from first name, last name, and company domain. It does not return generic role inboxes. Costs 10 credits, charged only when a verified email is found.",
        "operationId": "findEmail",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindEmailRequest"
              },
              "example": {
                "first_name": "Jane",
                "last_name": "Doe",
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Finder result. `credits_used` is 10 on a verified find and 0 otherwise.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindEmailResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "403": {
            "$ref": "#/components/responses/FeatureNotEnabled"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/api/find-email/csv": {
      "post": {
        "tags": [
          "Email Finder"
        ],
        "summary": "Upload a CSV for bulk email finding",
        "description": "Uploads a CSV and starts an asynchronous Email Finder job. Map the required prospect columns in the dashboard or API request. Costs 10 credits per verified email found.",
        "operationId": "createFinderCsvJob",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV file of people to find emails for."
                  },
                  "first_name_column": {
                    "type": "string",
                    "description": "Name of the column holding first names."
                  },
                  "last_name_column": {
                    "type": "string",
                    "description": "Name of the column holding last names."
                  },
                  "domain_column": {
                    "type": "string",
                    "description": "Name of the column holding company domains."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email Finder job created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FinderCsvJob"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "403": {
            "$ref": "#/components/responses/FeatureNotEnabled"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/api/find-email/csv/{job_id}": {
      "get": {
        "tags": [
          "Email Finder"
        ],
        "summary": "Get Email Finder job status",
        "description": "Returns the current status of a bulk Email Finder job. Poll until the job is complete, then download the results.",
        "operationId": "getFinderCsvJob",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "The Email Finder job ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current job status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FinderCsvJob"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/find-email/csv/{job_id}/download": {
      "get": {
        "tags": [
          "Email Finder"
        ],
        "summary": "Download Email Finder results as CSV",
        "description": "Downloads the completed Email Finder results as a CSV file. Returns 409 if the job has not finished yet.",
        "operationId": "downloadFinderCsvResults",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "The Email Finder job ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file of Email Finder results.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/JobNotComplete"
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Service health check",
        "description": "Returns service status, version, and uptime. This endpoint does not require authentication.",
        "operationId": "healthCheck",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is reachable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key issued from your VeriMails dashboard, sent as `Authorization: Bearer YOUR_API_KEY`."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": "Invalid or missing API key."
            }
          }
        }
      },
      "InsufficientCredits": {
        "description": "The account does not have enough credits to complete the request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": "Insufficient credits."
            }
          }
        }
      },
      "FeatureNotEnabled": {
        "description": "The requested feature is not enabled for this account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": "The Email Finder is not enabled for this account."
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested job was not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": "Job not found."
            }
          }
        }
      },
      "JobNotComplete": {
        "description": "The job exists but has not finished processing yet.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": "Job is still processing."
            }
          }
        }
      },
      "ValidationError": {
        "description": "The request body is invalid, usually because a required field is missing.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Retry after the period indicated by the Retry-After header when present.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "VerifyRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "The email address to verify.",
            "example": "person@example.com"
          }
        }
      },
      "SingleVerifyResponse": {
        "type": "object",
        "description": "Result of verifying a single email address.",
        "properties": {
          "email": {
            "type": "string",
            "description": "The email address that was verified."
          },
          "safe_to_send": {
            "type": "boolean",
            "description": "Whether VeriMails recommends sending to this address. True only when the returned status is `valid`."
          },
          "status": {
            "type": "string",
            "description": "Verification status.",
            "enum": [
              "valid",
              "invalid",
              "disposable",
              "catchall",
              "unknown",
              "likely_valid",
              "risky"
            ]
          },
          "confidence_score": {
            "type": "number",
            "format": "float",
            "description": "Confidence score from 0.0 to 1.0.",
            "minimum": 0,
            "maximum": 1
          },
          "reason": {
            "type": "string",
            "description": "Human-readable explanation of the verification result."
          },
          "domain": {
            "type": "string",
            "description": "The email domain."
          },
          "is_disposable": {
            "type": "boolean",
            "description": "Whether the email is from a disposable email service."
          },
          "is_role_based": {
            "type": "boolean",
            "description": "Whether the email is a role-based address such as info@ or support@."
          },
          "is_free": {
            "type": "boolean",
            "description": "Whether the email is from a free email provider such as Gmail or Yahoo."
          },
          "is_catch_all": {
            "type": "boolean",
            "description": "Whether the domain is a catch-all domain that accepts mail to any address."
          },
          "mx_records": {
            "type": "array",
            "description": "MX records for the domain.",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "email",
          "safe_to_send",
          "status",
          "confidence_score",
          "reason",
          "domain",
          "is_disposable",
          "is_role_based",
          "is_free",
          "is_catch_all",
          "mx_records"
        ],
        "example": {
          "email": "jane.doe@example.com",
          "safe_to_send": true,
          "status": "valid",
          "confidence_score": 0.95,
          "reason": "Verification completed",
          "domain": "example.com",
          "is_disposable": false,
          "is_role_based": false,
          "is_free": false,
          "is_catch_all": false,
          "mx_records": [
            "mx1.example.com"
          ]
        }
      },
      "BulkJobResponse": {
        "type": "object",
        "description": "Status of a bulk verification job.",
        "properties": {
          "job_id": {
            "type": "integer",
            "description": "Unique job identifier."
          },
          "status": {
            "type": "string",
            "description": "Job status.",
            "enum": [
              "pending",
              "processing",
              "completed",
              "failed"
            ]
          },
          "total_emails": {
            "type": "integer",
            "description": "Total number of email addresses in the upload."
          },
          "processed_emails": {
            "type": "integer",
            "description": "Number of addresses processed so far."
          },
          "valid_count": {
            "type": "integer",
            "description": "Number of addresses verified as valid."
          },
          "invalid_count": {
            "type": "integer",
            "description": "Number of addresses verified as invalid."
          },
          "catch_all_count": {
            "type": "integer",
            "description": "Number of addresses on detected catch-all domains."
          },
          "disposable_count": {
            "type": "integer",
            "description": "Number of addresses on disposable email services."
          },
          "unknown_count": {
            "type": "integer",
            "description": "Number of addresses that could not be conclusively verified."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the job was created."
          }
        }
      },
      "FindEmailRequest": {
        "type": "object",
        "required": [
          "first_name",
          "last_name",
          "domain"
        ],
        "properties": {
          "first_name": {
            "type": "string",
            "minLength": 1,
            "description": "The person's first name.",
            "example": "Jane"
          },
          "last_name": {
            "type": "string",
            "minLength": 1,
            "description": "The person's last name.",
            "example": "Doe"
          },
          "domain": {
            "type": "string",
            "description": "The approved company identifier used for matching.",
            "example": "example.com"
          }
        }
      },
      "FindEmailResponse": {
        "type": "object",
        "description": "Result of an Email Finder lookup.",
        "properties": {
          "found": {
            "type": "boolean",
            "description": "Whether a verified email address was found."
          },
          "email": {
            "type": "string",
            "nullable": true,
            "description": "The found email address, or null when none was found."
          },
          "status": {
            "type": "string",
            "description": "Finder outcome.",
            "enum": [
              "found",
              "not_found",
              "catch_all"
            ]
          },
          "confidence": {
            "type": "number",
            "format": "float",
            "description": "Confidence score from 0.0 to 1.0.",
            "minimum": 0,
            "maximum": 1
          },
          "elapsed_ms": {
            "type": "integer",
            "description": "Time taken for the lookup, in milliseconds."
          },
          "credits_used": {
            "type": "integer",
            "description": "Credits charged. The Email Finder charges 10 credits only when a verified email is found, and 0 otherwise."
          }
        },
        "example": {
          "found": true,
          "email": "jane.doe@example.com",
          "status": "found",
          "confidence": 0.95,
          "elapsed_ms": 812,
          "credits_used": 10
        }
      },
      "FinderCsvJob": {
        "type": "object",
        "description": "Status of a bulk Email Finder job.",
        "properties": {
          "job_id": {
            "type": "string",
            "description": "Unique job identifier."
          },
          "status": {
            "type": "string",
            "description": "Job status."
          }
        },
        "additionalProperties": true
      },
      "HealthResponse": {
        "type": "object",
        "description": "Service health status.",
        "properties": {
          "status": {
            "type": "string",
            "description": "Service status: healthy or unhealthy."
          },
          "version": {
            "type": "string",
            "description": "API version."
          },
          "uptime_seconds": {
            "type": "number",
            "format": "float",
            "description": "Service uptime in seconds."
          },
          "database_connected": {
            "type": "boolean",
            "description": "Whether the database connection is healthy."
          },
          "verifier_ready": {
            "type": "boolean",
            "description": "Whether the email verifier is ready."
          },
          "verification_provider": {
            "type": "string",
            "description": "Verification service identifier."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Current server timestamp in ISO 8601 format."
          }
        }
      },
      "Error": {
        "type": "object",
        "description": "Standard error response.",
        "properties": {
          "detail": {
            "type": "string",
            "description": "Human-readable explanation of the error."
          }
        }
      }
    }
  }
}
