{
  "openapi": "3.0.3",
  "info": {
    "title": "Scrubby Email Validation API",
    "version": "1.0.0",
    "description": "**Quick Verification** — Two modes:\n\n- **Single Email** — POST /validate_email. Result comes back immediately. No polling needed.\n- **Bulk Email** — Two steps: submit your list, then poll for results. Typically completes in 30–60 seconds.\n\n**Deep Verification** — Higher accuracy bulk verification. Same two-step flow as bulk. The first result for Deep Verification is shared in 24 hrs and the final result in 72 hrs.\n\n**Auth:** Every request needs the header `x-api-key: YOUR_KEY`.\n\n**Rate limit:** 25 requests per second (1500 requests per minute) per API key. Exceeding this returns 429."
  },
  "servers": [
    {
      "url": "https://api.scrubby.io",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Quick Verification",
      "description": "Two modes — **Single Email** for instant one-off results, and **Bulk Email** for batch processing.\n\n**Single Email:** POST /validate_email — result back immediately, no polling.\n\n**Bulk Email:** Two steps — POST /validate_bulk_emails to submit, then POST /fetch_bulk_results to poll until `status` is `completed`."
    },
    {
      "name": "Deep Verification",
      "description": "Higher-accuracy bulk verification. The first result for Deep Verification is shared in 24 hrs and the final result in 72 hrs.\n\nTwo steps — POST /validate_bulk_emails/deep to submit, then POST /fetch_bulk_results/deep to poll until `status` is `completed`."
    }
  ],
  "paths": {
    "/validate_email": {
      "post": {
        "tags": [
          "Quick Verification"
        ],
        "summary": "Single Email — Validate instantly",
        "description": "Send one email, get the result back immediately. No polling.\n\nServer timeout is 100 seconds. If it times out, you get a 408, and the credit is deducted. within 24 hours of the initial request, resending the same request is free and returns the same verification.",
        "operationId": "validateEmail",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SingleEmailRequest"
              },
              "example": {
                "email": "john.doe@company.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation complete. Read the `result` field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SingleEmailResponse"
                },
                "example": {
                  "email": "john.doe@company.com",
                  "status": "OK",
                  "result": "Valid",
                  "quick_status": "OK",
                  "credits_used": 1,
                  "remaining_credits": 99
                }
              }
            }
          },
          "400": {
            "description": "Bad request — invalid email format or insufficient credits.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Invalid email format or insufficient credits."
                }
              }
            }
          },
          "408": {
            "description": "Timed out after 100 seconds.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Single verification timed out after 100 seconds."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit hit (25 requests/second). Wait a moment and retry.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Rate limit exceeded. Maximum 25 requests per second per API key."
                }
              }
            }
          }
        }
      }
    },
    "/validate_bulk_emails": {
      "post": {
        "tags": [
          "Quick Verification"
        ],
        "summary": "Bulk Email — Submit batch (step 1 of 2)",
        "description": "Send a list of emails. The API queues them and returns an `identifier`.\n\nNext: save the `identifier`, wait `retry_after_seconds`, then call POST /fetch_bulk_results.",
        "operationId": "validateBulkEmails",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkEmailRequest"
              },
              "example": {
                "email": [
                  "john.doe@company.com",
                  "jane.smith@agency.com"
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch queued. Save the `identifier` and use it with /fetch_bulk_results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkEmailResponse"
                },
                "example": {
                  "status": "processing",
                  "identifier": "batch_sample_a1b2c3d4",
                  "fetch_result_endpoint": "/fetch_bulk_results",
                  "total": 2,
                  "credits_used": 2,
                  "remaining_credits": 98,
                  "retry_after_seconds": 30
                }
              }
            }
          },
          "400": {
            "description": "Bad request — invalid email format or insufficient credits.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Invalid email format or insufficient credits."
                }
              }
            }
          }
        }
      }
    },
    "/fetch_bulk_results": {
      "post": {
        "tags": [
          "Quick Verification"
        ],
        "summary": "Bulk Email — Fetch results (step 2 of 2)",
        "description": "Check results for a batch using its `identifier`.\n\nPoll every 30-60 seconds. When `status` is `completed`, all results are final — stop polling.",
        "operationId": "fetchBulkResults",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FetchBulkResultsRequest"
              },
              "example": {
                "identifier": "batch_sample_a1b2c3d4"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check the `status` field. `processing` = poll again in 30-60s. `completed` = done, stop polling.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FetchResultResponse"
                },
                "examples": {
                  "completed": {
                    "summary": "Done — stop polling",
                    "value": {
                      "status": "completed",
                      "identifier": "batch_sample_a1b2c3d4",
                      "results": {
                        "john.doe@company.com": {
                          "result": "Valid",
                          "status": "OK",
                          "quick_status": "OK"
                        },
                        "jane.smith@agency.com": {
                          "result": "Invalid",
                          "status": "HARD_BOUNCE",
                          "quick_status": "HARD_BOUNCE"
                        }
                      }
                    }
                  },
                  "processing": {
                    "summary": "Still running — poll again in 30-60s",
                    "value": {
                      "status": "processing",
                      "identifier": "batch_sample_a1b2c3d4",
                      "results": {
                        "john.doe@company.com": {
                          "result": "pending",
                          "status": "PROCESSING",
                          "quick_status": "PROCESSING"
                        },
                        "jane.smith@agency.com": {
                          "result": "pending",
                          "status": "PROCESSING",
                          "quick_status": "PROCESSING"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Identifier not found.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "No results found for identifier batch_sample_a1b2c3d4."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit hit (25 requests/second). Wait a moment and retry.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Rate limit exceeded. Maximum 25 requests per second per API key."
                }
              }
            }
          }
        }
      }
    },
    "/validate_bulk_emails/deep/": {
      "post": {
        "tags": [
          "Deep Verification"
        ],
        "summary": "Submit batch for deep verification (step 1 of 2)",
        "description": "Submit a list of emails for deep verification. More thorough than quick bulk.\n\nNext: save the `identifier`, wait `retry_after_seconds` (up to 86400s), then call POST /fetch_bulk_results/deep to poll for results.",
        "operationId": "validateBulkEmailsDeep",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkEmailRequest"
              },
              "example": {
                "email": [
                  "janedoe@company.com",
                  "john.doe@company.com"
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch accepted. Save the `identifier` and use it with /fetch_bulk_results/deep.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeepBulkEmailResponse"
                },
                "example": {
                  "status": "processing",
                  "identifier": "2fbf182d25594091a2ab66a37bbe9f4d",
                  "fetch_result_endpoint": "/fetch_bulk_results/deep",
                  "total": 2,
                  "credits_used": 6,
                  "remaining_credits": 9910353,
                  "retry_after_seconds": 86400,
                  "verification_type": "Deep"
                }
              }
            }
          },
          "400": {
            "description": "Bad request — invalid email format or insufficient credits.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Invalid email format or insufficient credits."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit hit (25 requests/second). Wait a moment and retry.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Rate limit exceeded. Maximum 25 requests per second per API key."
                }
              }
            }
          }
        }
      }
    },
    "/fetch_bulk_results/deep": {
      "post": {
        "tags": [
          "Deep Verification"
        ],
        "summary": "Fetch deep verification results (step 2 of 2)",
        "description": "Poll for results using the `identifier` from step 1.\n\nResults are returned in three time windows: `results_24` (24 hrs), `results_48` (48 hrs), and `results_72` (72 hrs). When `status` is `completed`, all windows are final — stop polling.",
        "operationId": "fetchBulkResultsDeep",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FetchBulkResultsRequest"
              },
              "example": {
                "identifier": "2fbf182d25594091a2ab66a37bbe9f4d"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check the `status` field. `processing` = still running. `completed` = all results final, stop polling.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FetchResultResponse"
                },
                "examples": {
                  "processing": {
                    "summary": "Still running — poll again later",
                    "value": {
                      "status": "processing",
                      "identifier": "84f957c1ade8487fa0bb6d6be42c038a",
                      "retry_after_seconds": 1199,
                      "results_24": {
                        "john.doe@company.com": {
                          "result": "pending",
                          "status": "pending",
                          "quick_status": "pending"
                        },
                        "jane.doe@agency.com": {
                          "result": "pending",
                          "status": "pending",
                          "quick_status": "pending"
                        }
                      },
                      "results_48": {
                        "john.doe@company.com": {
                          "result": "pending",
                          "status": "pending",
                          "quick_status": "pending"
                        },
                        "jane.doe@agency.com": {
                          "result": "pending",
                          "status": "pending",
                          "quick_status": "pending"
                        }
                      },
                      "results_72": {
                        "john.doe@company.com": {
                          "result": "pending",
                          "status": "pending",
                          "quick_status": "pending"
                        },
                        "jane.doe@agency.com": {
                          "result": "pending",
                          "status": "pending",
                          "quick_status": "pending"
                        }
                      }
                    }
                  },
                  "completed": {
                    "summary": "Done — stop polling",
                    "value": {
                      "status": "completed",
                      "identifier": "84f957c1ade8487fa0bb6d6be42c038a",
                      "results_24": {
                        "john.doe@company.com": {
                          "result": "Valid",
                          "status": "OK",
                          "quick_status": "OK"
                        },
                        "jane.doe@agency.com": {
                          "result": "Invalid",
                          "status": "HARD_BOUNCE",
                          "quick_status": "HARD_BOUNCE"
                        }
                      },
                      "results_48": {
                        "john.doe@company.com": {
                          "result": "Valid",
                          "status": "OK",
                          "quick_status": "OK"
                        },
                        "jane.doe@agency.com": {
                          "result": "Invalid",
                          "status": "HARD_BOUNCE",
                          "quick_status": "HARD_BOUNCE"
                        }
                      },
                      "results_72": {
                        "john.doe@company.com": {
                          "result": "Valid",
                          "status": "OK",
                          "quick_status": "OK"
                        },
                        "jane.doe@agency.com": {
                          "result": "Invalid",
                          "status": "HARD_BOUNCE",
                          "quick_status": "HARD_BOUNCE"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Identifier not found.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "No results found for the provided identifier."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit hit (25 requests/second). Wait a moment and retry.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Rate limit exceeded. Maximum 25 requests per second per API key."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Send as `x-api-key: YOUR_KEY`. Also accepted as `Authorization: Api-Key YOUR_KEY`."
      }
    },
    "schemas": {
      "SingleEmailRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "The email address to validate.",
            "example": "john.doe@company.com"
          }
        }
      },
      "BulkEmailRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "array",
            "minItems": 1,
            "description": "List of email addresses to validate.",
            "items": {
              "type": "string",
              "format": "email"
            },
            "example": [
              "john.doe@company.com",
              "jane.smith@agency.com"
            ]
          }
        }
      },
      "FetchBulkResultsRequest": {
        "type": "object",
        "required": [
          "identifier"
        ],
        "properties": {
          "identifier": {
            "type": "string",
            "description": "The identifier returned by the submit endpoint. The API generates this — you do not create it.",
            "example": "batch_sample_a1b2c3d4"
          }
        }
      },
      "SingleEmailResponse": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "The email that was validated.",
            "example": "john.doe@company.com"
          },
          "result": {
            "type": "string",
            "description": "`Valid` = safe to send. `Invalid` = do not send. `Risky` = deliverable but risky. `Unknown` = could not be determined.",
            "enum": [
              "Valid",
              "Invalid",
              "Risky",
              "Unknown"
            ],
            "example": "Valid"
          },
          "status": {
            "type": "string",
            "description": "Detailed status code (e.g. OK, HARD_BOUNCE, SOFT_BOUNCE).",
            "example": "OK"
          },
          "quick_status": {
            "type": "string",
            "description": "`OK` = safe. `HARD_BOUNCE` = invalid. `SOFT_BOUNCE` = temporarily undeliverable. `UNKNOWN` = undetermined.",
            "enum": [
              "OK",
              "HARD_BOUNCE",
              "SOFT_BOUNCE",
              "UNKNOWN"
            ],
            "example": "OK"
          },
          "credits_used": {
            "type": "integer",
            "description": "Credits consumed by this request.",
            "example": 1
          },
          "remaining_credits": {
            "type": "integer",
            "description": "Credits left in your account.",
            "example": 99
          },
          "retry_after_seconds": {
            "type": "integer",
            "description": "Seconds to wait before retrying. `0` means no retry needed.",
            "example": 0
          }
        }
      },
      "BulkEmailResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Always `processing` — the batch is queued, not done yet.",
            "example": "processing"
          },
          "identifier": {
            "type": "string",
            "description": "Unique batch ID. Save this to use with /fetch_bulk_results.",
            "example": "batch_sample_a1b2c3d4"
          },
          "fetch_result_endpoint": {
            "type": "string",
            "description": "The endpoint to call for results.",
            "example": "/fetch_bulk_results"
          },
          "total": {
            "type": "integer",
            "description": "Number of emails in this batch.",
            "example": 2
          },
          "credits_used": {
            "type": "integer",
            "description": "Credits consumed for this batch.",
            "example": 2
          },
          "remaining_credits": {
            "type": "integer",
            "description": "Credits left in your account.",
            "example": 98
          },
          "retry_after_seconds": {
            "type": "integer",
            "description": "Wait this many seconds before your first call to /fetch_bulk_results.",
            "example": 30
          }
        }
      },
      "DeepBulkEmailResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Always `processing` — the batch is queued.",
            "example": "processing"
          },
          "identifier": {
            "type": "string",
            "description": "Unique batch ID. Save this to use with /fetch_bulk_results/deep.",
            "example": "2fbf182d25594091a2ab66a37bbe9f4d"
          },
          "fetch_result_endpoint": {
            "type": "string",
            "description": "The endpoint to call for results.",
            "example": "/fetch_bulk_results/deep"
          },
          "total": {
            "type": "integer",
            "description": "Number of emails in this batch.",
            "example": 2
          },
          "credits_used": {
            "type": "integer",
            "description": "Credits consumed. Deep verification uses more credits per email.",
            "example": 6
          },
          "remaining_credits": {
            "type": "integer",
            "description": "Credits left in your account.",
            "example": 9910353
          },
          "retry_after_seconds": {
            "type": "integer",
            "description": "Max wait in seconds before polling. Deep verification can take up to 86400s (24 hours).",
            "example": 86400
          },
          "verification_type": {
            "type": "string",
            "description": "Always `Deep` for this endpoint.",
            "example": "Deep"
          }
        }
      },
      "BulkResultItem": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "description": "`pending` = still processing. Once completed: `Valid`, `Invalid`, `Risky`, or `Unknown`.",
            "enum": [
              "Valid",
              "Invalid",
              "Risky",
              "Unknown",
              "pending"
            ],
            "example": "Valid"
          },
          "status": {
            "type": "string",
            "description": "Detailed status code (e.g. OK, HARD_BOUNCE, PROCESSING).",
            "example": "OK"
          },
          "quick_status": {
            "type": "string",
            "description": "Simplified deliverability label. `PROCESSING` means still pending.",
            "example": "OK"
          }
        }
      },
      "FetchResultResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "`processing` = still running, poll again. `completed` = all results are final, stop polling.",
            "enum": [
              "completed",
              "processing"
            ],
            "example": "completed"
          },
          "identifier": {
            "type": "string",
            "description": "The batch identifier you submitted.",
            "example": "batch_sample_a1b2c3d4"
          },
          "retry_after_seconds": {
            "type": "integer",
            "description": "Suggested seconds to wait before polling again.",
            "example": 86400
          },
          "results": {
            "type": "object",
            "description": "Each email mapped to its result. Shows `pending` until the batch is `completed`.",
            "additionalProperties": {
              "$ref": "#/components/schemas/BulkResultItem"
            },
            "example": {
              "john.doe@company.com": {
                "result": "Valid",
                "status": "OK",
                "quick_status": "OK"
              },
              "jane.smith@agency.com": {
                "result": "Invalid",
                "status": "HARD_BOUNCE",
                "quick_status": "HARD_BOUNCE"
              }
            }
          }
        }
      }
    }
  },
  "x-rateLimit": {
    "limit": "25 requests per second per API key",
    "appliesTo": [
      "/validate_email",
      "/validate_bulk_emails",
      "/fetch_bulk_results",
      "/validate_bulk_emails/deep/",
      "/fetch_bulk_results/deep"
    ],
    "onLimitExceeded": {
      "httpCode": 429,
      "message": "Rate limit exceeded. Maximum 25 requests per second per API key."
    }
  }
}