Skip to content
PennyPost Docs

API

Send contacts and events to PennyPost from your server.

The API is for sending people and events to PennyPost from your server. Most apps only need one call: results_ready.

Authentication

Create a key on API keys and send it as a bearer token:

Authorization: Bearer mc_...

Keys start with mc_. PennyPost shows a key once and stores only a hash of it. A wrong or revoked key gets 401 Invalid API key. Revoke a key on the same page.

Every request and response body is JSON.

Send an event

POST https://usepennypost.com/api/v1/events

Field Type
app string Your app's ID, shown on Activation (older code may send it as newsletter; both work)
email string The user's email
event string 1 to 64 letters, digits, _, ., : or -. Use results_ready for results
properties object Optional, under 2 KB. For results_ready: url and headline
createContact boolean Add the person if PennyPost doesn't know them yet
firstName, lastName string Optional
curl -X POST https://usepennypost.com/api/v1/events \
  -H "Authorization: Bearer $PENNYPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"app": "your-app", "email": "jane@example.com", "event": "results_ready", "createContact": true,
       "properties": {"url": "https://yourapp.com/projects/42", "headline": "Your 12 headshots are ready."}}'

Returns 202 with {"ok": true, "contactId": "...", "created": true}.

Status Meaning
400 A field is missing or invalid; the body says which
404 App not found, or contact not found (send "createContact": true)
403 Your plan blocks new people this month
429 More than 6,000 events an hour on this key

Add or update a person

POST https://usepennypost.com/api/v1/contacts adds a person. Fields: newsletter (your app's ID), email, and optionally firstName, lastName, tags, fields (an object of your own values) and source. Returns 201 for a new person, 200 for one PennyPost already had. Limits: 600 an hour per key, and 5 every 10 minutes per visitor IP if you pass ip.

PATCH https://usepennypost.com/api/v1/contacts updates a person who already exists, with the same fields plus removeTags. It never creates anyone. 6,000 an hour per key.

curl -X PATCH https://usepennypost.com/api/v1/contacts \
  -H "Authorization: Bearer $PENNYPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"newsletter": "your-app", "email": "jane@example.com", "tags": ["activated"], "removeTags": ["trial"]}'

MCP

The same key works with the MCP server at https://usepennypost.com/mcp. See AI assistants (MCP).