Contacts and lists API reference
Every endpoint, with the two behaviours that surprise people.
Base URL https://www.inboxpenny.com/api/v1. Every request needs a key — see Create an API key. Bodies and responses are JSON.
The endpoints
| Method & path | Does |
|---|---|
POST /contacts | Create or update, matched on email |
PATCH /contacts/:id | Update fields you send |
DELETE /contacts/:id | Delete a contact |
POST /lists | Create a list |
PATCH /lists/:id | Rename or edit it |
DELETE /lists/:id | Delete it — contacts are kept |
POST /lists/:id/contacts | Add someone, by id or email |
DELETE /lists/:id/contacts/:contactId | Remove them from the list |
There are no read endpoints yet — no listing or searching. Export CSV for that.
POST /contacts is an upsert
Post the same address twice and you get one contact, not two. New returns 201; existing returns 200 and is updated.
That makes an integration much simpler: no need to check whether someone exists, and re-running a sync is safe. Custom fields merge, so a request that sends only plan doesn’t wipe the others.
POST /api/v1/contacts
{
"email": "sam@acme.com",
"firstName": "Sam",
"attributes": { "COMPANY": "Acme", "PLAN": "pro" }
}Nothing sends unless you ask
This is the important one
By default the API starts no welcome emails and no automations. A sync that pushes ten thousand existing customers should not email ten thousand people.
To opt in, send "sendWelcome": true when creating a contact or adding one to a list. For removals, which have no body, add ?runAutomations=true — and it must be exactly that string, so a client sending ?runAutomations=false can never be read as a yes.
Errors
One shape, always:
{
"error": {
"code": "validation_failed",
"message": "email must be a valid address",
"details": { "field": "email" }
}
}See errors and status codes for what each one means.
Worth knowing
- Deleting a list keeps its contacts. Only the grouping goes.
- Status is respected. You can create a contact with a status, but adding someone who unsubscribed won’t make them mailable again.
- Addresses aren’t deliverability-checked the way a CSV import is. If you’re piping in user-typed addresses, validate before posting.
- Keys are account-scoped. An id from another account simply isn’t found.
FAQs
Can I add a contact to several lists at once?+
One call per list. With no bulk endpoint yet, that matters at volume — see rate limits.
How do I find a contact's id?+
It comes back when you create or update one. Store it — there is no lookup endpoint, so an id you discard can’t be re-found through the API.
Is there a sandbox?+
No. Nothing here sends email on its own, so the API is safe to try against your real account — provided you leave the welcome and automation flags alone.

