Base URL https://preping.com. Authenticate with Authorization: Bearer pp_live_… (or pp_test_…, which never emails real people). JSON in, JSON out.
Errors always tell you how to fix them
{
"error": {
"code": "domain_not_verified",
"message": "You can't send from acme.com yet because it isn't verified.",
"fix": "Finish adding the DNS records for acme.com. We check automatically every few minutes.",
"link": "https://preping.com/app/domains/dom_…"
}
}Status codes: 202 accepted · 401 bad key · 403 not allowed (with the reason) · 404 · 409 conflict · 422 invalid input · 429 limit reached (with when it resets) · 500 our fault (safe to retry with an Idempotency-Key).
/v1/emailsSend an emailsending-only keys allowed{
"from": "Acme <hello@acme.com>",
"to": [
"asha@example.com"
],
"subject": "Your receipt",
"html": "<p>Thanks!</p>",
"reply_to": "support@acme.com",
"tags": {
"order": "1042"
},
"scheduled_at": "in 1 hour",
"stream": "transactional"
}Or use a template: { "template": "welcome", "variables": { "first_name": "Asha" } }. Attachments: [{ filename, content (base64), content_type }]. Optional: cc, bcc, headers, track_opens, track_clicks. Header Idempotency-Key makes retries safe.
/v1/emails/batchSend up to 100 emailssending-only keys allowedBody: an array of email objects. Each succeeds or fails on its own; results come back in order.
/v1/emails/{id}Get an email, with its full event timeline/v1/emails?limit=20&before={id}List emails, newest first/v1/emails/{id}/cancelCancel a scheduled emailsending-only keys allowed/v1/contactsCreate or update a contact (by email){
"email": "asha@example.com",
"first_name": "Asha",
"attributes": {
"plan": "pro"
},
"lists": [
"lst_…"
]
}/v1/contacts/{id or email}Get a contact and their lists/v1/contacts/{id or email}Update a contact{
"attributes": {
"plan": "paid"
},
"subscribed": true
}/v1/contacts/{id or email}Delete a contact/v1/eventsTrack an event (starts automations)sending-only keys allowed{
"email": "asha@example.com",
"name": "signed_up",
"properties": {
"plan": "trial"
}
}/v1/validationsCheck an address before sending (free, sends nothing)sending-only keys allowed{
"email": "asha@gmial.com"
}Returns result (valid / risky / invalid), a plain-English reason, the checks (syntax, mail server, disposable, role address) and a typo suggestion like asha@gmail.com. Send { "emails": [...] } for up to 50 at once.
/v1/listsList your lists/v1/templatesList templates and the variables each one needs/v1/domainsList domains with DNS record status/v1/domainsAdd a domain{
"name": "acme.com"
}/v1/domains/{id}/verifyRe-check a domain's DNS now/v1/suppressionsList suppressed addresses/v1/suppressionsSuppress an address{
"email": "no@example.com",
"scope": "marketing"
}/v1/suppressions/{email}Remove a suppressionSigned with Standard Webhooks. Payload: { type, created_at, data }.
email.sentWe handed the email to the receiving serveremail.deliveredThe receiving server accepted itemail.delivery_delayedDelivery is being retried (temporary problem)email.bouncedIt couldn't be deliveredemail.complainedThe recipient marked it as spamemail.openedThe recipient opened itemail.clickedThe recipient clicked a linkemail.failedWe couldn't send it (see error)email.suppressedNot sent: recipient is on your suppression listcontact.createdA contact was addedcontact.unsubscribedA contact unsubscribeddomain.verifiedA domain finished verifyingdomain.driftedA domain's DNS records changed and need attentioncampaign.sentA campaign finished sendinginbound.receivedAn email arrived at one of your inbound addressesHost smtp.preping.com, port 587 (STARTTLS) or 465, username preping, password: any API key.