Quick Start
Send your first email in 3 steps:
1. Get your API key
Go to Settings → API Keys and create a new key. Copy it — you'll only see it once.
2. Verify your domain
Add your sending domain in Settings → Domains and configure the DNS records.
3. Send an email
curl -X POST https://senderkit.hatched.digital/api/v1/email \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"from": "hello@yourdomain.com",
"to": "user@example.com",
"subject": "Hello from Senderkit!",
"html": "<h1>Welcome, {{name}}!</h1><p>Your account is ready.</p>",
"variables": {
"name": "Alex"
}
}'Response:
{
"id": "msg_a1b2c3d4-...",
"status": "queued"
}Authentication
All API requests require a valid API key sent in the Authorization header.
Authorization: Bearer sk_live_your_api_key_hereSecurity: Keep your API key secret. Never expose it in client-side code, public repositories, or browser requests. Use environment variables on your server.
Send Email
/api/v1/emailSend a single transactional email. Supports HTML, plain text, templates, and merge variables.
| Parameter | Type | Required | Description |
|---|---|---|---|
| from | string | Yes | Sender email address (must be a verified domain) |
| to | string | string[] | Yes | Recipient email(s), max 50 |
| subject | string | Yes | Email subject line |
| html | string | No | HTML body content |
| text | string | No | Plain text fallback |
| template_id | string | No | Use a saved template by UUID |
| variables | object | No | Merge variables for {{variable}} substitution |
| reply_to | string | No | Reply-to email address |
| tags | string[] | No | Tags for filtering in analytics (max 10) |
| track_opens | boolean | No | Track email opens (default: true) |
| track_clicks | boolean | No | Track link clicks (default: true) |
Example: Simple email
curl -X POST https://senderkit.hatched.digital/api/v1/email \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"from": "noreply@yourdomain.com",
"to": "user@example.com",
"subject": "Your password reset code",
"html": "<p>Your code is: <strong>{{code}}</strong></p>",
"variables": { "code": "483921" },
"tags": ["password-reset"]
}'Example: Using a template
curl -X POST https://senderkit.hatched.digital/api/v1/email \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"from": "orders@yourdomain.com",
"to": "customer@example.com",
"subject": "Order #{{order_id}} confirmed",
"template_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"variables": {
"name": "Sarah",
"order_id": "SK-1234",
"total": "$49.99"
}
}'Batch Send
/api/v1/email/batchSend up to 100 emails in a single API call. Each message can have different recipients, subjects, and variables.
curl -X POST https://senderkit.hatched.digital/api/v1/email/batch \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"from": "noreply@yourdomain.com",
"to": "alice@example.com",
"subject": "Welcome, Alice!",
"html": "<h1>Welcome, {{name}}!</h1>",
"variables": { "name": "Alice" }
},
{
"from": "noreply@yourdomain.com",
"to": "bob@example.com",
"subject": "Welcome, Bob!",
"html": "<h1>Welcome, {{name}}!</h1>",
"variables": { "name": "Bob" }
}
]
}'Templates
Create email templates in the Senderkit dashboard using the drag-and-drop builder, then reference them in API calls with template_id.
Templates support {{variable}} merge variables that get replaced at send time.
Tip: Design your transactional templates in the Senderkit builder, then use them via API. Your brand colors, logo, and fonts are applied automatically.
Merge Variables
Use double curly braces to insert dynamic content:
<!-- In your HTML or template -->
<h1>Hello, {{name}}!</h1>
<p>Your order #{{order_id}} has shipped.</p>
<p>Track at: {{tracking_url}}</p>
<!-- API call -->
{
"variables": {
"name": "Sarah",
"order_id": "1234",
"tracking_url": "https://track.example.com/1234"
}
}Webhooks
Senderkit tracks email events automatically. View them in the Analytics dashboard or the Activity log.
Events tracked:
Rate Limits
| Plan | Emails/month | Rate |
|---|---|---|
| Trial (7 days) | 200 emails | 50/min |
| Starter | 5,000 | 50/min |
| Growth | 50,000 | 200/min |
| Business | 200,000 | 500/min |
| Scale | 500,000 | 1,000/min |
Error Codes
| Status | Type | Description |
|---|---|---|
| 400 | validation_error | Invalid request body (check error.errors for details) |
| 401 | authentication_error | Missing or invalid API key |
| 403 | permission_error | API key lacks required permission |
| 404 | not_found | Resource not found (e.g. template_id) |
| 429 | rate_limit_error | Too many requests — slow down |
| 500 | server_error | Internal server error — contact support |
Error response format:
{
"error": {
"type": "validation_error",
"message": ""to" must be a valid email address",
"errors": [...]
}
}SDKs & Examples
Node.js
const response = await fetch("https://senderkit.hatched.digital/api/v1/email", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SENDERKIT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "noreply@yourdomain.com",
to: "user@example.com",
subject: "Welcome!",
html: "<h1>Hello, {{name}}!</h1>",
variables: { name: "World" },
}),
});
const { id, status } = await response.json();
console.log(`Email ${id}: ${status}`);Python
import requests
import os
response = requests.post(
"https://senderkit.hatched.digital/api/v1/email",
headers={
"Authorization": f"Bearer {os.environ['SENDERKIT_API_KEY']}",
"Content-Type": "application/json",
},
json={
"from": "noreply@yourdomain.com",
"to": "user@example.com",
"subject": "Welcome!",
"html": "<h1>Hello, {{name}}!</h1>",
"variables": {"name": "World"},
},
)
data = response.json()
print(f"Email {data['id']}: {data['status']}")PHP
$ch = curl_init("https://senderkit.hatched.digital/api/v1/email");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("SENDERKIT_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"from" => "noreply@yourdomain.com",
"to" => "user@example.com",
"subject" => "Welcome!",
"html" => "<h1>Hello, {{name}}!</h1>",
"variables" => ["name" => "World"],
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
echo "Email {$response['id']}: {$response['status']}";Ruby
require "net/http"
require "json"
uri = URI("https://senderkit.hatched.digital/api/v1/email")
req = Net::HTTP::Post.new(uri.path, {
"Authorization" => "Bearer #{ENV['SENDERKIT_API_KEY']}",
"Content-Type" => "application/json"
})
req.body = {
from: "noreply@yourdomain.com",
to: "user@example.com",
subject: "Welcome!",
html: "<h1>Hello, {{name}}!</h1>",
variables: { name: "World" }
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
puts "Email #{data['id']}: #{data['status']}"Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
payload, _ := json.Marshal(map[string]interface{}{
"from": "noreply@yourdomain.com",
"to": "user@example.com",
"subject": "Welcome!",
"html": "<h1>Hello, {{name}}!</h1>",
"variables": map[string]string{"name": "World"},
})
req, _ := http.NewRequest("POST",
"https://senderkit.hatched.digital/api/v1/email",
bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer "+os.Getenv("SENDERKIT_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var result map[string]string
json.NewDecoder(resp.Body).Decode(&result)
fmt.Printf("Email %s: %s\n", result["id"], result["status"])
}Questions? Email support@senderkit.com