SimpleCold API reference
Verify email addresses from your own code. Every result comes back with a category, a reason code and a plain-English reason. Every example in these docs uses the real request and response shapes.
Endpoints
All endpoints use the same API key, sent as a Bearer token.
| Method | Path | What it does |
|---|---|---|
GET | /api/v1/api-validation/validate | Checks that your API key works. Uses no credits. |
GET | /api/v1/api-validation/single | Verifies one address in real time. |
GET | /api/v1/api-validation/single/result | Collects the final result of a check that came back as processing. Uses no credits. |
POST | /api/v1/api-validation/batch | Verifies up to 50 addresses in one request. |
POST | /api/v1/api-validation/bulk | Uploads a CSV file and starts a background job. |
GET | /api/v1/api-validation/bulk/:id/status | Reports a bulk job's status and progress. |
GET | /api/v1/api-validation/bulk/:id/download-result | Downloads a bulk job's results as CSV or JSON. |
Base URL
https://simplecold.com/api/v1The paths in these docs are relative to that base. For example, the single endpoint is https://simplecold.com/api/v1/api-validation/single.
Authentication
Send your API key in the Authorization header on every request:
Authorization: Bearer <your-api-key>There is no query-string key and no basic auth. See Using your API key for examples and the errors you can get back.
Response format
Successful JSON responses use one envelope. The result is always inside payload:
{
"code": "SUCCESS",
"message": "Successfully performed operation.",
"payload": { "...": "..." },
"requestId": "9b07c1d2-..."
}Errors raised by the API use a second shape:
{
"code": "FAILURE",
"message": "Invalid API key",
"data": null
}If a query parameter, path parameter or body field fails validation (for example a malformed email address), you get a 400 with the list of problems in data:
{
"success": false,
"message": "Please check your input and try again.",
"data": [
{
"validation": "email",
"code": "invalid_string",
"message": "Invalid email address",
"path": ["email"]
}
]
}Rate-limit responses use the same code and message fields, with details in data, plus status and error fields kept for older integrations (see Rate limits):
{
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Maximum 100 requests per minute per API key.",
"data": {
"policy": "api.single",
"retryAfterSeconds": 1,
"limit": 100,
"scope": "apiKey",
"blocked": false
},
"status": 429,
"error": "Rate limit exceeded. Maximum 100 requests per minute per API key."
}So branch on the HTTP status code, and read the error text as body.message ?? body.error. Server errors (5xx) return the message Internal Server Error.
Every response, success or error, also carries an X-Request-Id header with the same value as requestId.
Bulk downloads are the one exception: a successful download returns the file itself, not the JSON envelope.
Rate limits
Limits are counted per API key, per minute.
| Endpoint | Limit per key |
|---|---|
GET /api-validation/single and GET /api-validation/single/result | 100 requests per minute (shared) |
POST /api-validation/batch | 10 requests per minute |
POST /api-validation/bulk | 10 uploads per minute |
GET /api-validation/bulk/:id/status | 120 requests per minute |
GET /api-validation/bulk/:id/download-result | 30 requests per minute |
Each key has its own budget, and your organisation as a whole gets three keys' worth, so extra keys don't multiply the limit. Responses carry the standard RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset and RateLimit-Policy headers. When you go over, you get a 429 with a Retry-After header; wait that many seconds before trying again. Rate limits has every limit, the headers and retry code.
Credits
One credit verifies one address.
If your balance can't cover a request, it fails with a 400 and the message Insufficient credits. (or Please buy credits. when the balance is empty). Retrying won't help; top up in the dashboard.
Getting started
There are no official SDKs. Everything is plain HTTPS and JSON. Long-running work can be collected by polling, or pushed to you with webhooks.
Support
Questions about an integration? Contact support. Include the requestId from the response if you are asking about a specific result.