Authentication

All API requests require authentication via an API key passed in the Authorization header.

API Key format

Keys use the format sk_live_ followed by 64 hex characters:

sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789...

Using your key

Include the key in the Authorization header with the Bearer scheme:

cURL

curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
  "https://emailkind.com/v1/[email protected]"

JavaScript

const response = await fetch(
  "https://emailkind.com/v1/[email protected]",
  {
    headers: {
      Authorization: "Bearer sk_live_YOUR_KEY",
    },
  }
);
const data = await response.json();

Python

import requests

response = requests.get(
    "https://emailkind.com/v1/classify",
    params={"email": "[email protected]"},
    headers={"Authorization": "Bearer sk_live_YOUR_KEY"}
)
data = response.json()

PHP

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => "https://emailkind.com/v1/[email protected]",
    CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_live_YOUR_KEY"],
    CURLOPT_RETURNTRANSFER => true,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);

Go

req, _ := http.NewRequest("GET", "https://emailkind.com/v1/[email protected]", nil)
req.Header.Set("Authorization", "Bearer sk_live_YOUR_KEY")
resp, err := http.DefaultClient.Do(req)

Ruby

uri = URI("https://emailkind.com/v1/[email protected]")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer sk_live_YOUR_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }

Key management

You can manage your API keys from the Dashboard:

  • Create new keys with descriptive names (e.g., "Production", "Staging")
  • Revoke keys that are compromised or no longer needed
  • View key prefixes and last usage timestamps

Security best practices

| Do | Don't | |---|---| | Store keys in environment variables | Commit keys to source control | | Use different keys per environment | Share keys between applications | | Revoke unused keys | Log full API keys | | Rotate keys periodically | Expose keys in client-side code |

Key limits by plan

| Plan | Max API keys | |---|---| | Free | 1 | | Starter | 3 | | Growth | 5 | | Scale | 10 |

IP Allowlisting

You can restrict each API key to specific IP addresses for added security. When configured, requests from non-allowed IPs will be rejected with a 403 Forbidden response.

How to configure

  1. Go to Dashboard > API Keys
  2. Click the IPs button next to your key
  3. Enter one IP address or CIDR range per line
  4. Click Save IP restrictions

Supported formats

| Format | Example | Description | |---|---|---| | IPv4 | 203.0.113.1 | Single IP address | | IPv6 | 2001:db8::1 | Single IPv6 address | | CIDR | 10.0.0.0/8 | IP range (all 10.x.x.x) | | CIDR v6 | 2001:db8::/32 | IPv6 range |

Leave the list empty to allow requests from any IP (default).

Error response

{
  "success": false,
  "error": {
    "code": "IP_NOT_ALLOWED",
    "message": "Your IP address is not in the allowlist for this API key"
  }
}

Webhooks

EmailKind can notify your application via webhooks when a domain's classification changes. This is useful for keeping your data up-to-date without polling.

Setup

  1. Go to Dashboard > Webhooks
  2. Enter your endpoint URL (HTTPS recommended)
  3. Copy and store the signing secret securely

Events

| Event | Description | |---|---| | domain.changed | A domain's provider type has changed since the last classification |

Payload format

{
  "event": "domain.changed",
  "timestamp": "2025-01-15T10:30:00Z",
  "data": {
    "domain": "example.com",
    "old_type": "business",
    "new_type": "disposable",
    "provider_id": "mailinator",
    "provider_name": "Mailinator"
  }
}

Verifying signatures

Each webhook request includes an X-EmailKind-Signature header containing an HMAC-SHA256 signature of the payload body:

X-EmailKind-Signature: sha256=5d41402abc4b2a76b9719d911017c592...

Verify the signature using your signing secret:

import hmac, hashlib

def verify_signature(payload, signature, secret):
    expected = "sha256=" + hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Error responses

If authentication fails, you'll receive a 401 Unauthorized response:

{
  "success": false,
  "request_id": "req_abc123",
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or missing API key"
  }
}