{
  "openapi": "3.1.0",
  "info": {
    "title": "MailTester Ninja Email Verification API",
    "version": "1.0.0",
    "summary": "Check in real time whether an email address is valid and deliverable.",
    "description": "One GET request per address. MailTester Ninja checks the address against the recipient's live mail server (syntax, domain, MX records, then an SMTP conversation that stops before any message is sent) and returns a verdict. Nothing is stored.\n\nBranch your code on `code`:\n\n| code | Meaning | Typical `message` |\n|------|---------|-------------------|\n| `ok` | Valid and deliverable | Accepted |\n| `ko` | Invalid, will bounce | Rejected, No MX, Disposable, Limited |\n| `mb` | Uncertain: the domain accepts everything or could not be probed | Catch-All, MX Error, Timeout, SPAM Block, Greylisted, Abuse |\n| `--` | No verdict, the address was not checked | Invalid Key, Disabled Key, free limit message (HTTP 429) |\n\nA catch-all domain is never reported as valid. Never drop an address on a `--` answer: fix the key, or wait and retry.\n\n**Keys and limits.** Pass `key=free` to try the API with no signup (10 checks a day per IP), a free token `mtf_...` from https://mailtester.ninja/free-email-verification-api/ (50 checks a day, valid 7 days), or a subscription key `sub_...` from https://mailtester.ninja/verify-emails-unlimited/. The free tier allows one request every 30 seconds. A paid key allows its daily limit divided by 8640 requests per 10 seconds, for all connections together (Pro 11, Ultimate 23 per 10 seconds; buy a quantity to multiply it).\n\n**Content type.** Send `Accept: application/json` to receive `application/json`; without it the same JSON body is served as `text/plain`.\n\nCode examples for cURL, Python, Node.js, PHP, Go, Ruby, Java, C#, Google Sheets, n8n, Make, Zapier, Clay and AI agents: https://github.com/mailtester-ninja/mailtester-api-examples",
    "termsOfService": "https://mailtester.ninja/terms-of-use/",
    "contact": {
      "name": "MailTester Ninja",
      "url": "https://mailtester.ninja/contact/",
      "email": "contact@mailtester.ninja"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://mailtester.ninja/terms-of-use/"
    },
    "x-logo": {
      "url": "https://mailtester.ninja/favicon.svg",
      "altText": "MailTester Ninja"
    }
  },
  "externalDocs": {
    "description": "API documentation",
    "url": "https://mailtester.ninja/api/"
  },
  "servers": [
    {
      "url": "https://happy.mailtester.ninja",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Verification",
      "description": "Real-time email address verification."
    }
  ],
  "paths": {
    "/ninja": {
      "get": {
        "tags": [
          "Verification"
        ],
        "operationId": "verifyEmail",
        "summary": "Verify an email address",
        "description": "Checks one email address in real time and returns a verdict. Use `code` to decide (`ok` send, `ko` drop, `mb` decide by risk, `--` no verdict) and show `message` to people. A check usually takes one to a few seconds; allow up to 45 seconds for slow mail servers.",
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": true,
            "description": "The email address to verify, URL-encoded.",
            "schema": {
              "type": "string",
              "format": "email",
              "maxLength": 254
            },
            "example": "info@apple.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Verification result. Also returned with `code` set to `--` when the key is invalid or disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationResult"
                },
                "examples": {
                  "valid": {
                    "summary": "Valid and deliverable",
                    "value": {
                      "code": "ok",
                      "message": "Accepted",
                      "domain": "apple.com",
                      "mx": "mx-in.g.apple.com",
                      "connections": 1,
                      "limit": 100000,
                      "rate": 1,
                      "email": "info@apple.com",
                      "user": "Info"
                    }
                  },
                  "invalid": {
                    "summary": "Mailbox does not exist",
                    "value": {
                      "code": "ko",
                      "message": "Rejected",
                      "domain": "gmail.com",
                      "mx": "gmail-smtp-in.l.google.com",
                      "connections": 1,
                      "limit": 100000,
                      "rate": 1,
                      "email": "no.such.user.2026@gmail.com",
                      "user": "No Such User 2026"
                    }
                  },
                  "catchAll": {
                    "summary": "Domain accepts every address",
                    "value": {
                      "code": "mb",
                      "message": "Catch-All",
                      "domain": "stripe.com",
                      "mx": "aspmx.l.google.com",
                      "connections": 1,
                      "limit": 100000,
                      "rate": 1,
                      "email": "hello@stripe.com",
                      "user": "Hello"
                    }
                  },
                  "invalidKey": {
                    "summary": "Key not recognised",
                    "value": {
                      "code": "--",
                      "message": "Invalid Key",
                      "domain": null,
                      "mx": "",
                      "connections": 0,
                      "limit": 0,
                      "rate": 0,
                      "email": "info@apple.com",
                      "user": "Info"
                    }
                  }
                }
              },
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed key. The body is the subscription page URL.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "https://mailtester.ninja/subscribe"
              }
            }
          },
          "401": {
            "description": "Malformed email address, rejected before verification.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "description": "Missing or empty `email` or `key` parameter.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "missingKey": {
                    "value": "Missing key param"
                  },
                  "emptyKey": {
                    "value": "Empty key param"
                  },
                  "missingEmail": {
                    "value": "Missing email param"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Limit reached, the address was not checked. Not a verdict: wait and retry. On the free tier the body is a JSON result with `code` set to `--` and a `message` saying how long to wait; on a paid key the body is plain text describing the rate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationResult"
                },
                "example": {
                  "code": "--",
                  "message": "Free API: one request every 30 s, retry in 29 s. Unlimited speed: https://mailtester.ninja/verify-emails-unlimited/",
                  "domain": null,
                  "mx": "",
                  "connections": 0,
                  "limit": 10,
                  "rate": 0,
                  "email": "info@apple.com",
                  "user": "Info"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Too Many Requests - Your rate is now 25 - Using 3 connections - Your daily limit is 200000 - Your max rate per 10 secs for all connections is 23.148148148148 - Please Adapt your query rates https://mailtester.ninja/api"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "query",
        "name": "key",
        "description": "`free` (no signup, 10 checks a day per IP, one request every 30 s), a free token `mtf_...` (50 checks a day, one request every 30 s, valid 7 days: https://mailtester.ninja/free-email-verification-api/) or a subscription key `sub_...` without the braces (https://mailtester.ninja/verify-emails-unlimited/)."
      }
    },
    "schemas": {
      "VerificationResult": {
        "type": "object",
        "required": [
          "code",
          "message",
          "email"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "ok",
              "ko",
              "mb",
              "--"
            ],
            "description": "Machine-readable verdict: `ok` valid, `ko` invalid, `mb` uncertain, `--` no verdict (key problem or limit reached)."
          },
          "message": {
            "type": "string",
            "description": "Human-readable label for the verdict. Known values: Accepted; Rejected, No MX, Disposable, Limited; Catch-All, MX Error, Timeout, SPAM Block, Greylisted, Abuse; Invalid Key, Disabled Key, or a free limit message. Other labels may be added.",
            "examples": [
              "Accepted",
              "Rejected",
              "Catch-All"
            ]
          },
          "email": {
            "type": "string",
            "description": "The address that was checked."
          },
          "user": {
            "type": "string",
            "description": "A human-readable guess of the name, derived from the address."
          },
          "domain": {
            "type": [
              "string",
              "null"
            ],
            "description": "The domain part of the address."
          },
          "mx": {
            "type": "string",
            "description": "The mail server used for the check, when there is one."
          },
          "connections": {
            "type": "integer",
            "description": "Simultaneous connections currently used by the key."
          },
          "limit": {
            "type": "integer",
            "description": "Daily limit of the key (verifications per day)."
          },
          "rate": {
            "type": "integer",
            "description": "Requests made with the key over the last 10 seconds."
          }
        }
      }
    }
  }
}
