{
  "openapi": "3.1.0",
  "info": {
    "title": "SMTPing Email Verification API",
    "version": "1.0.0",
    "summary": "Verify email addresses, clean lists up to 100,000 and detect spamtrap, disposable, spambot and complainer addresses.",
    "description": "Real-time and bulk email verification over a live SMTP handshake, plus fast list lookups for spamtrap, disposable, spambot and complainer addresses. One address verified costs one credit; unknown results, duplicates and rejected requests are free. Every account gets 25 free credits per day. Full guide: https://smtping.com/docs",
    "termsOfService": "https://smtping.com/terms",
    "contact": {
      "name": "SMTPing support",
      "url": "https://smtping.com/contact"
    },
    "x-logo": {
      "url": "https://smtping.com/favicon-512.png",
      "altText": "SMTPing"
    }
  },
  "externalDocs": {
    "description": "API documentation",
    "url": "https://smtping.com/docs"
  },
  "servers": [
    {
      "url": "https://api.smtping.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Verification",
      "description": "Full verification: syntax, DNS, MX and a live SMTP conversation with the mail server."
    },
    {
      "name": "Bulk verification",
      "description": "Submit a list, poll the job, fetch the results. Up to 100,000 addresses per job."
    },
    {
      "name": "Checks",
      "description": "List and pattern lookups (spamtrap, disposable, spambot, complainer). Milliseconds, no SMTP."
    },
    {
      "name": "Account",
      "description": "Credit balance and usage reporting."
    }
  ],
  "paths": {
    "/verify/single": {
      "post": {
        "tags": [
          "Verification"
        ],
        "operationId": "verifySingle",
        "summary": "Verify one email address",
        "description": "Typically 2 to 5 seconds; allow a client timeout of at least 10 seconds. Costs 1 credit, nothing when the status is unknown.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRequest"
              },
              "example": {
                "email": "someone@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResult"
                },
                "example": {
                  "email": "someone@example.com",
                  "status": "valid",
                  "statusDescription": "Mailbox exists and accepts mail",
                  "isDisposable": false,
                  "isFreeDomain": false,
                  "isRoleBasedDomain": false,
                  "isTypos": false,
                  "domain": "example.com"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/verify/bulk": {
      "post": {
        "tags": [
          "Bulk verification"
        ],
        "operationId": "createBulkJob",
        "summary": "Submit a list for verification",
        "description": "Maximum 100,000 addresses. Duplicates are removed case-insensitively and billed once. Credits are deducted as the job runs. Store the jobId.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailsRequest"
              },
              "example": {
                "emails": [
                  "first@example.com",
                  "second@example.org"
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobAccepted"
                },
                "example": {
                  "jobId": "0a710238-06a5-4e24-af2b-e8593fc644fc",
                  "status": "Queued"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/verify/bulk/{jobId}": {
      "get": {
        "tags": [
          "Bulk verification"
        ],
        "operationId": "getBulkJob",
        "summary": "Get bulk job progress",
        "description": "Poll every 20 to 30 seconds. Polling has its own budget of 60 requests per minute and costs no credits. Use processedEmails, not progress, for a progress bar.",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "description": "The jobId returned when the job was submitted.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkJob"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/verify/bulk/{jobId}/result": {
      "get": {
        "tags": [
          "Bulk verification"
        ],
        "operationId": "getBulkJobResult",
        "summary": "Fetch bulk job results",
        "description": "Available once status is Succeeded; earlier calls return 409. One entry per address, same shape as a single verification.",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "description": "The jobId returned when the job was submitted.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/VerifyResult"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/checks/{check}": {
      "post": {
        "tags": [
          "Checks"
        ],
        "operationId": "checkOne",
        "summary": "Check one address against a list",
        "description": "Answers in milliseconds. Costs 1 credit.",
        "parameters": [
          {
            "name": "check",
            "in": "path",
            "required": true,
            "description": "Which list to look the address up in.",
            "schema": {
              "$ref": "#/components/schemas/CheckType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRequest"
              },
              "example": {
                "email": "someone@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResult"
                },
                "example": {
                  "email": "someone@example.com",
                  "check": "spamtrap",
                  "matched": true,
                  "source": "recycled-list",
                  "creditsCharged": 1,
                  "remainingCredits": 8491109
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/checks/{check}/batch": {
      "post": {
        "tags": [
          "Checks"
        ],
        "operationId": "checkBatch",
        "summary": "Check up to 1,000 addresses",
        "description": "Maximum 1,000 per call; above that use /checks/{check}/jobs. Duplicates are removed and not billed.",
        "parameters": [
          {
            "name": "check",
            "in": "path",
            "required": true,
            "description": "Which list to look the address up in.",
            "schema": {
              "$ref": "#/components/schemas/CheckType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailsRequest"
              },
              "example": {
                "emails": [
                  "a@example.com",
                  "b@example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckBatchResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/checks/{check}/jobs": {
      "post": {
        "tags": [
          "Checks"
        ],
        "operationId": "createCheckJob",
        "summary": "Submit a large list for one check",
        "description": "Up to 100,000 addresses. Same submit, poll, fetch pattern as bulk verification.",
        "parameters": [
          {
            "name": "check",
            "in": "path",
            "required": true,
            "description": "Which list to look the address up in.",
            "schema": {
              "$ref": "#/components/schemas/CheckType"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailsRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobAccepted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/checks/jobs/{jobId}": {
      "get": {
        "tags": [
          "Checks"
        ],
        "operationId": "getCheckJob",
        "summary": "Get check job progress",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "description": "The jobId returned when the job was submitted.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkJob"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/checks/jobs/{jobId}/result": {
      "get": {
        "tags": [
          "Checks"
        ],
        "operationId": "getCheckJobResult",
        "summary": "Fetch check job results",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "description": "The jobId returned when the job was submitted.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CheckItem"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/checks/flags": {
      "post": {
        "tags": [
          "Checks"
        ],
        "operationId": "checkFlags",
        "summary": "Every flag for one address",
        "description": "Returns every check for one address in a single call, cheaper than separate requests.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRequest"
              },
              "example": {
                "email": "someone@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "All flags.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/credits": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getCredits",
        "summary": "Credit balance and plan",
        "description": "Free.",
        "responses": {
          "200": {
            "description": "Balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Credits"
                },
                "example": {
                  "remaining": 8491109,
                  "plan": "Free",
                  "dailyRemaining": null
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getUsage",
        "summary": "Usage over a date range",
        "description": "Totals plus a daily breakdown.",
        "responses": {
          "200": {
            "description": "Usage report.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Create a key in the dashboard at https://app.smtping.com. Keys do not expire; up to 10 active keys per account."
      }
    },
    "schemas": {
      "EmailRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "EmailsRequest": {
        "type": "object",
        "required": [
          "emails"
        ],
        "properties": {
          "emails": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100000,
            "items": {
              "type": "string",
              "format": "email"
            }
          }
        }
      },
      "Status": {
        "type": "string",
        "description": "The verdict. Safe: valid, alias. Do not send: invalid, spamtrap, disposable, blacklisted, complainer, spambot. Judgement: catchall, valid_catchall, inbox_full, unknown (never charged). New values may be added.",
        "examples": [
          "valid",
          "alias",
          "invalid",
          "spamtrap",
          "disposable",
          "blacklisted",
          "complainer",
          "spambot",
          "catchall",
          "valid_catchall",
          "inbox_full",
          "unknown"
        ]
      },
      "VerifyResult": {
        "type": "object",
        "required": [
          "email",
          "status"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "statusDescription": {
            "type": "string",
            "description": "Human-readable explanation, safe to show to a user."
          },
          "isDisposable": {
            "type": "boolean"
          },
          "isFreeDomain": {
            "type": "boolean",
            "description": "Consumer mailbox such as gmail.com."
          },
          "isRoleBasedDomain": {
            "type": "boolean",
            "description": "Shared inbox such as info@ or sales@."
          },
          "isTypos": {
            "type": "boolean",
            "description": "Looks like a misspelled popular domain."
          },
          "domain": {
            "type": "string"
          }
        }
      },
      "CheckType": {
        "type": "string",
        "enum": [
          "spamtrap",
          "disposable",
          "spambot",
          "complainer"
        ]
      },
      "CheckSource": {
        "type": [
          "string",
          "null"
        ],
        "description": "Why the address matched; null when matched is false.",
        "examples": [
          "recycled-list",
          "legacy-domain",
          "mx-pattern",
          "pattern",
          "in-memory-list"
        ]
      },
      "CheckItem": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "matched": {
            "type": "boolean"
          },
          "source": {
            "$ref": "#/components/schemas/CheckSource"
          }
        }
      },
      "CheckResult": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "check": {
            "$ref": "#/components/schemas/CheckType"
          },
          "matched": {
            "type": "boolean"
          },
          "source": {
            "$ref": "#/components/schemas/CheckSource"
          },
          "creditsCharged": {
            "type": "integer"
          },
          "remainingCredits": {
            "type": "integer"
          }
        }
      },
      "CheckBatchResult": {
        "type": "object",
        "properties": {
          "check": {
            "$ref": "#/components/schemas/CheckType"
          },
          "checked": {
            "type": "integer"
          },
          "matched": {
            "type": "integer"
          },
          "creditsCharged": {
            "type": "integer"
          },
          "remainingCredits": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckItem"
            }
          }
        }
      },
      "JobStatus": {
        "type": "string",
        "enum": [
          "Queued",
          "Processing",
          "Succeeded",
          "Failed",
          "Cancelled"
        ]
      },
      "JobAccepted": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "$ref": "#/components/schemas/JobStatus"
          }
        }
      },
      "BulkJob": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "$ref": "#/components/schemas/JobStatus"
          },
          "progress": {
            "type": "integer",
            "description": "Internal pipeline phase, 0 to 100. Not proportional to addresses processed."
          },
          "processedEmails": {
            "type": "integer"
          },
          "summary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": "integer"
              },
              "invalid": {
                "type": "integer"
              },
              "risky": {
                "type": "integer"
              },
              "unknown": {
                "type": "integer"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "finishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "errorMessage": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Credits": {
        "type": "object",
        "properties": {
          "remaining": {
            "type": "integer"
          },
          "plan": {
            "type": "string"
          },
          "dailyRemaining": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "totals": {
            "type": "object",
            "additionalProperties": true
          },
          "daily": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "requests": {
                  "type": "integer"
                },
                "emails": {
                  "type": "integer"
                },
                "credits": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "example": {
          "error": "Maximum 100000 emails are allowed per job."
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed request, empty list, bad JSON or list too large. Not charged.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, invalid or revoked API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Not enough credits. Nothing was charged.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Account not activated.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Job not found, or not owned by this account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Job has not finished yet. Keep polling.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limited. Free: 10 requests/min, 2 bulk jobs/hour. Paid: 120 requests/min, 30 bulk jobs/hour. Not charged.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "integer"
            }
          }
        }
      },
      "ServerError": {
        "description": "Server error. Retry with backoff.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}