PushMail.dev

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
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"
  }'
Response
{
  "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
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" }'
Response
{
  "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
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"
  }'
Response
{
  "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
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"
  }'
Response
{
  "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
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

app/api/subscribe/route.ts
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

app.py
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)

index.html
<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

On this page