SDKs & Libraries
PushMail is a standard REST API — you don't need an SDK. But these wrappers make it even easier.
No SDK needed
PushMail is designed to be simple enough to use with any HTTP client. Every endpoint accepts and returns JSON.
async function addContact(email: string, firstName?: string) {
const res = await fetch("https://pushmail.dev/api/v1/contacts", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.PUSHMAIL_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
siteId: 1,
email,
firstName,
tags: ["signup"],
}),
});
if (!res.ok) throw new Error(`PushMail error: ${res.status}`);
return res.json();
}import requests
PUSHMAIL_KEY = "pm_live_YOUR_KEY"
def add_contact(email: str, first_name: str = None):
res = requests.post(
"https://pushmail.dev/api/v1/contacts",
headers={"Authorization": f"Bearer {PUSHMAIL_KEY}"},
json={
"siteId": 1,
"email": email,
"firstName": first_name,
"tags": ["signup"],
},
)
res.raise_for_status()
return res.json()func addContact(email, firstName string) error {
body, _ := json.Marshal(map[string]interface{}{
"siteId": 1,
"email": email,
"firstName": firstName,
"tags": []string{"signup"},
})
req, _ := http.NewRequest("POST",
"https://pushmail.dev/api/v1/contacts",
bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PUSHMAIL_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return fmt.Errorf("pushmail: %d", resp.StatusCode)
}
return nil
}require "net/http"
require "json"
PUSHMAIL_KEY = ENV["PUSHMAIL_KEY"]
def add_contact(email, first_name: nil)
uri = URI("https://pushmail.dev/api/v1/contacts")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{PUSHMAIL_KEY}"
req["Content-Type"] = "application/json"
req.body = {
siteId: 1,
email: email,
firstName: first_name,
tags: ["signup"]
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http|
http.request(req)
}
JSON.parse(res.body)
end<?php
function addContact(string $email, ?string $firstName = null): array {
$ch = curl_init("https://pushmail.dev/api/v1/contacts");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("PUSHMAIL_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"siteId" => 1,
"email" => $email,
"firstName" => $firstName,
"tags" => ["signup"],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}TypeScript helper (copy-paste)
Drop this into your project for a typed PushMail client. No dependencies required.
const BASE = "https://pushmail.dev/api/v1";
class PushMail {
constructor(private key: string, private siteId: number) {}
private async request<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${BASE}${path}`, {
...options,
headers: {
"Authorization": `Bearer ${this.key}`,
"Content-Type": "application/json",
...options?.headers,
},
});
const json = await res.json();
if (!res.ok) throw new Error(json.error || `HTTP ${res.status}`);
return json.data;
}
// Contacts
async addContact(data: {
email: string;
firstName?: string;
lastName?: string;
tags?: string[];
customFields?: Record<string, string>;
}) {
return this.request("/contacts", {
method: "POST",
body: JSON.stringify({ siteId: this.siteId, ...data }),
});
}
async getContact(id: number) {
return this.request(`/contacts/${id}`);
}
async listContacts(params?: {
q?: string;
status?: string;
page?: number;
limit?: number;
}) {
const qs = new URLSearchParams({
siteId: String(this.siteId),
...Object.fromEntries(
Object.entries(params || {}).map(([k, v]) => [k, String(v)])
),
});
return this.request(`/contacts?${qs}`);
}
// Sequences
async enroll(sequenceId: number, contactId: number, startAtStep?: number) {
return this.request(
`/sequences/${sequenceId}/enroll`,
{
method: "POST",
body: JSON.stringify({ contactIds: [contactId], ...(startAtStep !== undefined && { startAtStep }) }),
}
);
}
// Campaigns
async createCampaign(data: {
name: string;
templateId: number;
listId?: number;
tagId?: number;
}) {
return this.request(`/campaigns`, {
method: "POST",
body: JSON.stringify({ siteId: this.siteId, ...data }),
});
}
async sendCampaign(campaignId: number) {
return this.request(
`/campaigns/${campaignId}/send`,
{ method: "POST" }
);
}
}
// Usage:
// const pm = new PushMail(process.env.PUSHMAIL_KEY!, 1);
// await pm.addContact({ email: "jane@example.com", tags: ["signup"] });
export { PushMail };Framework guides
Since PushMail is a REST API, it works with any language or framework that can make HTTP requests. See the quickstart for integration examples.
| Framework | Integration approach |
|---|---|
| Next.js | Server action or API route handler |
| Express / Node.js | Middleware or route handler |
| Django / Flask | View function with requests |
| Rails | Controller action with Net::HTTP |
Error handling
All errors return a consistent JSON format:
{
"error": "Human-readable error message"
}HTTP status codes
| Code | Description |
|---|---|
200 | Success |
201 | Created |
400 | Bad request — invalid parameters |
401 | Unauthorized — missing or invalid API key |
403 | Forbidden — insufficient permissions |
404 | Not found — resource doesn't exist |
409 | Conflict — duplicate (e.g., email already exists) |
500 | Server error — please retry or contact support |