Quickstart
Go from zero to capturing emails in 5 minutes. No SDK required — just HTTP requests.
Create your account
Sign up at pushmail.dev/dashboard or use the API directly. Every new account gets $5 in free sending credits.
curl -X POST https://pushmail.dev/api/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{
"email": "you@company.com",
"password": "your-secure-password",
"orgName": "My Company"
}'{
"data": {
"user": { "id": 1, "email": "you@company.com", "role": "owner" },
"org": { "id": 1, "name": "My Company", "slug": "my-company-1234567890" }
}
}Create an API key
Go to Settings → API Keys in the dashboard, or use the API. Your key starts with pm_live_ — save it securely, it's only shown once.
curl -X POST https://pushmail.dev/api/v1/api-keys \
-H "Cookie: session=YOUR_SESSION_ID" \
-H "Content-Type: application/json" \
-d '{ "name": "My App" }'{
"data": {
"id": 1,
"name": "My App",
"key": "pm_live_a1b2c3d4e5f6..."
}
}Create a site
Sites isolate contacts and sequences per project. Create one for each domain or app you manage.
curl -X POST https://pushmail.dev/api/v1/sites \
-H "Authorization: Bearer pm_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "My Blog",
"domain": "myblog.com"
}'{
"data": {
"id": 1,
"orgId": 1,
"name": "My Blog",
"domain": "myblog.com",
"createdAt": "2025-01-15T10:00:00.000Z"
}
}Add a contact
This is the call you'll wire up to your signup form. Tags are auto-created if they don't exist.
curl -X POST https://pushmail.dev/api/v1/contacts \
-H "Authorization: Bearer pm_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"siteId": 1,
"email": "jane@example.com",
"firstName": "Jane",
"lastName": "Doe",
"tags": ["signup", "blog-reader"],
"source": "landing-page"
}'{
"data": {
"id": 42,
"siteId": 1,
"email": "jane@example.com",
"firstName": "Jane",
"lastName": "Doe",
"status": "subscribed",
"source": "landing-page",
"createdAt": "2025-01-15T10:05:00.000Z"
}
}Enroll in a drip sequence
Create a sequence in the dashboard (or via API), then enroll contacts to start the drip.
curl -X POST https://pushmail.dev/api/v1/sequences/1/enroll \
-H "Authorization: Bearer pm_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "contactIds": [42] }'Done. PushMail handles the rest — sending each email at the right time, tracking opens and clicks, and stopping if the contact unsubscribes.
Common integrations
Next.js form handler
import { NextRequest, NextResponse } from "next/server";
const PUSHMAIL_KEY = process.env.PUSHMAIL_API_KEY!;
const SITE_ID = 1;
export async function POST(req: NextRequest) {
const { email, firstName } = await req.json();
const res = await fetch("https://pushmail.dev/api/v1/contacts", {
method: "POST",
headers: {
"Authorization": `Bearer ${PUSHMAIL_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
siteId: SITE_ID,
email,
firstName,
tags: ["newsletter"],
}),
});
if (!res.ok) {
const err = await res.json();
return NextResponse.json({ error: err.error }, { status: res.status });
}
return NextResponse.json({ success: true });
}Python / Flask
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
PUSHMAIL_KEY = "pm_live_YOUR_KEY"
SITE_ID = 1
@app.route("/subscribe", methods=["POST"])
def subscribe():
data = request.get_json()
res = requests.post(
"https://pushmail.dev/api/v1/contacts",
headers={"Authorization": f"Bearer {PUSHMAIL_KEY}"},
json={
"siteId": SITE_ID,
"email": data["email"],
"firstName": data.get("firstName"),
"tags": ["newsletter"],
},
)
if res.status_code == 409:
return jsonify({"message": "Already subscribed"}), 200
res.raise_for_status()
return jsonify({"success": True})HTML form (no backend)
<form id="signup-form">
<input type="email" name="email" placeholder="you@example.com" required />
<input type="text" name="firstName" placeholder="First name" />
<button type="submit">Subscribe</button>
</form>
<script>
document.getElementById("signup-form").addEventListener("submit", async (e) => {
e.preventDefault();
const form = new FormData(e.target);
const res = await fetch("https://pushmail.dev/api/v1/contacts", {
method: "POST",
headers: {
"Authorization": "Bearer pm_live_YOUR_PUBLIC_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
siteId: 1,
email: form.get("email"),
firstName: form.get("firstName"),
tags: ["website-signup"],
}),
});
if (res.ok) {
e.target.innerHTML = "<p>Thanks for subscribing!</p>";
}
});
</script>For client-side usage, create a site-scoped API key with write-only contact permissions.
Next steps
- Contacts — Tagging, custom fields, and bulk imports
- Website Tracking — Track page views and identify visitors with a JS snippet
- Sequences — Build multi-step drip campaigns
- Sending — Configure BYOK SendGrid keys and delivery settings
- Webhooks — Get real-time delivery, open, and click events