Authentication
Every request must say who you are. There are two ways: the API key alone (simple, works everywhere) or a signed request (more secure). Most people only need the first one.
Option 1: API key only recommended to start
Send two headers with every request:
Authorization: YOUR_API_KEY
Content-Type: application/json
Put only the key in Authorization. No Bearer , no Token , no quotes. Authorization: Bearer abc123 is rejected with a 401 error.
Example:
const response = await fetch("https://app.icypeas.com/api/email-verification", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "YOUR_API_KEY",
},
body: JSON.stringify({ email: "test@icypeas.com" }),
});
console.log(await response.json());
This is the method to use with no-code tools (Make, Zapier, n8n, Google Sheets).
Option 2: signed requests
If your key could be intercepted, or your security policy requires it, sign each request with your API secret (on the API page, Reveal the secret Key). A signature is valid for one URL, one method and one moment, so a captured request can't be replayed.
Send these headers:
| Header | Value |
|---|---|
Authorization | YOUR_API_KEY:SIGNATURE |
X-ROCK-TIMESTAMP | The current UTC time in ISO 8601, for example 2026-03-12T12:01:02.000Z |
Content-Type | application/json |
How to compute the signature
- Take the HTTP method, for example
POST. - Take the path of the URL, for example
/api/a/actions/subscription-informationforhttps://app.icypeas.com/api/a/actions/subscription-information. - Take the same timestamp you send in
X-ROCK-TIMESTAMP. - Join the three, in lower case:
post/api/a/actions/subscription-information2026-03-12t12:01:02.000z. - Compute the HMAC-SHA1 of that string with your API secret, as a hexadecimal string.
- JavaScript
- Python
- PHP
import crypto from "node:crypto";
function sign(url, method, secret, timestamp = new Date().toISOString()) {
const path = new URL(url).pathname;
const payload = `${method}${path}${timestamp}`.toLowerCase();
const signature = crypto.createHmac("sha1", secret).update(payload).digest("hex");
return { signature, timestamp };
}
const url = "https://app.icypeas.com/api/email-verification";
const { signature, timestamp } = sign(url, "POST", process.env.ICYPEAS_API_SECRET);
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `${process.env.ICYPEAS_API_KEY}:${signature}`,
"X-ROCK-TIMESTAMP": timestamp,
},
body: JSON.stringify({ email: "test@icypeas.com" }),
});
import hashlib, hmac, os
from datetime import datetime, timezone
from urllib.parse import urlparse
import requests
def sign(url, method, secret):
timestamp = datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace("+00:00", "Z")
payload = f"{method}{urlparse(url).path}{timestamp}".lower()
signature = hmac.new(secret.encode(), payload.encode(), hashlib.sha1).hexdigest()
return signature, timestamp
url = "https://app.icypeas.com/api/email-verification"
signature, timestamp = sign(url, "POST", os.environ["ICYPEAS_API_SECRET"])
response = requests.post(
url,
headers={
"Authorization": f"{os.environ['ICYPEAS_API_KEY']}:{signature}",
"X-ROCK-TIMESTAMP": timestamp,
},
json={"email": "test@icypeas.com"},
)
print(response.json())
<?php
$url = "https://app.icypeas.com/api/email-verification";
$timestamp = gmdate("Y-m-d\TH:i:s.000\Z");
$payload = strtolower("POST" . parse_url($url, PHP_URL_PATH) . $timestamp);
$signature = hash_hmac("sha1", $payload, getenv("ICYPEAS_API_SECRET"));
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => json_encode(["email" => "test@icypeas.com"]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Authorization: " . getenv("ICYPEAS_API_KEY") . ":" . $signature,
"X-ROCK-TIMESTAMP: " . $timestamp,
],
]);
print_r(json_decode(curl_exec($ch), true));
Examples in more languages (Go, Rust…) are available on the API page of the app.
Authentication errors
If authentication fails, you get an HTTP 401:
{
"message": "Unauthorized access.",
"error": "UnauthorizedAccessError",
"status": 401,
"code": "unauthorized_access_error"
}
Check, in this order: API access is activated, the key is complete and has no extra space, there's no Bearer prefix, and (for signed requests) your clock is on time and the path includes /api. See Errors for everything else.