Developers

MyEmailProgram API Documentation

Connect your website, store, CRM, or AI tool to MyEmailProgram. Manage contacts, lists, suppression, and broadcasts, and pull campaign reports.

Overview

The MyEmailProgram API lets your own software, scripts, and AI tools work with your account: add and update contacts, manage lists and suppression, create and schedule broadcasts, and pull campaign reports.

It’s a JSON API over HTTPS. Every request goes to this base URL:

https://app.myemailprogram.com/api/

This page covers the endpoints our customers use most. If you need something you don’t see here, ask us. The API can do more than we’ve documented on this page.

Authentication

Every request must include an API key. Create one in your account under Settings → API Keys. Our guide, How to Create an API Key, walks through it step by step.

Send your key in the Authorization header as a Bearer token:

Authorization: Bearer YOUR_API_KEY

If your server or tool can’t send an Authorization header, you can pass the key as a query parameter instead:

https://app.myemailprogram.com/api/getLists?api_token=YOUR_API_KEY

The header method is preferred, because query strings can end up in server logs.

API key permissions

Each API key is assigned a role that controls what it can do:

  • Module permissions. Choose which areas the key can use, such as contacts, lists, broadcasts, or suppression. Give each key only what it needs.
  • Rate limit. Each role has a requests-per-minute limit (60 per minute by default).
  • Allowed IPs. Optionally restrict a key so it only works from specific IP addresses.

Treat API keys like passwords. Don’t put them in public code, front-end JavaScript, or shared documents. If a key is exposed, delete it and create a new one.

Requests and responses

Send request bodies as JSON with a Content-Type: application/json header. Every response is JSON with a status of success or error and a result that contains either your data or a message.

A successful response looks like this:

{
  "status": "success",
  "result": "Success: Contact has been successfully created."
}

An error looks like this:

{
  "status": "error",
  "result": "Error: Invalid or missing API token."
}

Many endpoints that create or update records accept response=1 to return the full record in a response object, which is handy when you need the new ID.

Paging through results

Endpoints that return lists of records use limit_start (the starting row, default 0) and limit_count (how many to return, default 25). To page through a large list, increase limit_start by your limit_count on each request until fewer records come back.

Endpoint quick reference

MethodEndpointWhat it does
GET/api/getListsList your contact lists
POST/api/addListCreate a contact list
POST/api/addContactAdd a contact to a list
GET/api/getContactsFind contacts
GET/api/getContact/{id}Get one contact
PUT/api/updateContactByEmail/{email}Update a contact by email address
PUT/api/markAsUnsubscribed/{id}Unsubscribe a contact
DELETE/api/deleteContactByEmail/{email}/{recursive}Delete a contact by email address
POST/api/suppressAdd an email, domain, or IP to suppression
GET/api/getSuppressedList suppressed entries
GET/api/getCustomFieldsList your custom fields
GET/api/getBroadcastsList broadcasts
POST/api/addBroadcastCreate a broadcast
POST/api/broadcastScheduleSchedule or send a broadcast
GET/api/getBroadcastStatsSummary/{schedule_id}Get a sent campaign’s stats

Contact lists

GET /api/getLists

Returns your contact lists, including each list’s ID and subscriber count. You’ll need a list’s ID to add contacts to it.

ParameterRequiredDescription
list_idNoReturn a single list by ID
limit_startNoStarting row (default 0)
limit_countNoNumber of lists to return (default 25)
curl "https://app.myemailprogram.com/api/getLists" \
  -H "Authorization: Bearer YOUR_API_KEY"

POST /api/addList

Creates a new contact list.

ParameterRequiredDescription
list_nameYesName of the list
owner_nameYesOwner name for the list
owner_emailYesOwner email address
reply_emailYesWhere replies should go
bounce_emailYesReturn-path address for bounce reports
group_nameNoGroup to put the list in
responseNo1 to return the new list’s details

Contacts

POST /api/addContact

Adds a contact to a list. Include custom fields, such as first and last name, by their field names.

ParameterRequiredDescription
emailYesThe contact’s email address
list_idYesID of the list to add the contact to
is_confirmedNo1 confirmed (default), 0 unconfirmed
is_activeNo1 active (default), 0 inactive
formatNoHTML (default) or TEXT
responseNo1 to return the new contact’s details

Adding an address that already exists on the list returns an error (“Email address already exists”). Use updateContactByEmail to change an existing contact. Call getCustomFields to see the exact names of your custom fields.

curl -X POST "https://app.myemailprogram.com/api/addContact" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "list_id": 12,
    "email": "[email protected]",
    "first_name": "Sam",
    "last_name": "Carter",
    "response": 1
  }'

GET /api/getContacts

Finds contacts. Combine filters to narrow the results.

ParameterRequiredDescription
list_idNoOnly contacts on this list
emailNoFind a contact by email address
is_unsubscribedNo1 unsubscribed, 0 subscribed
bouncedNosoft, hard, or no_process (not bounced)
full_detailsNo1 to include custom fields (default returns ID and email only)
limit_start / limit_countNoPaging (defaults 0 and 25)
curl "https://app.myemailprogram.com/api/getContacts?list_id=12&full_details=1&limit_count=100" \
  -H "Authorization: Bearer YOUR_API_KEY"

GET /api/getContact/{id}

Returns a single contact by contact ID, including subscription status and custom field values.

PUT /api/updateContactByEmail/{email}

Updates a contact using their email address, which is usually easier than looking up an ID first.

ParameterRequiredDescription
list_idNoOnly update the contact on this list (otherwise all lists)
is_unsubscribedNo1 to unsubscribe, 0 to resubscribe
is_activeNo1 active, 0 inactive
first_name, etc.NoAny custom field values to change
responseNo1 to return the updated contact

Only resubscribe someone who has asked to be resubscribed.

curl -X PUT "https://app.myemailprogram.com/api/updateContactByEmail/[email protected]" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "list_id": 12, "first_name": "Samantha" }'

PUT /api/markAsUnsubscribed/{id}

Marks a contact as unsubscribed by contact ID. Use this to honor opt-outs that come from another system, like a checkout page or CRM.

DELETE /api/deleteContactByEmail/{email}/{recursive}

Deletes a contact by email address. Set recursive to 1 to delete the address from every list, or 0 to delete only the first match.

Deleting a contact removes their record. To stop emailing someone who opted out, unsubscribe or suppress them instead, so they can’t be re-imported by accident.

Suppression

Suppressed addresses are never sent to, even if they’re on a list. Hard bounces, spam complaints, and unsubscribes are suppressed automatically. Use these endpoints to add your own. Read Bounces and Suppression Lists for the full picture.

POST /api/suppress

Adds an email address, a whole domain, or an IP address to suppression, either account-wide or for one list.

ParameterRequiredDescription
typeYes0 for account-wide (global), 1 for a single list
referenceYesA note explaining why, such as “Requested removal by phone”
email, domain, or ipYesThe value to suppress (send one of these)
list_idIf type is 1The list to suppress on
responseNo1 to return the new entry
curl -X POST "https://app.myemailprogram.com/api/suppress" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": 0,
    "reference": "Requested removal by phone",
    "email": "[email protected]"
  }'

GET /api/getSuppressed

Lists suppressed entries.

ParameterRequiredDescription
typeYesemail, domain, or ip
referenceNoOnly entries with this reference
limit_start / limit_countNoPaging (defaults 0 and 25)

Broadcasts and scheduling

GET /api/getBroadcasts

Lists your broadcasts (saved email campaigns), including subject lines and content.

ParameterRequiredDescription
idNoReturn a single broadcast
limit_start / limit_countNoPaging (defaults 0 and 25)

POST /api/addBroadcast

Creates a broadcast. This saves the email. It doesn’t send it.

The campaign editor’s Pre-header field isn’t available through the API, so build your preheader (inbox preview text) directly into content_html. Our preheader guide has a copy-and-paste snippet.

ParameterRequiredDescription
group_nameYesGroup to file the broadcast under
broadcast_nameYesInternal name for the broadcast
email_subjectYesSubject line
content_htmlYesHTML version of the email
content_textYesPlain-text version of the email
responseNo1 to return the new broadcast, including its ID
curl -X POST "https://app.myemailprogram.com/api/addBroadcast" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "group_name": "Newsletters",
    "broadcast_name": "November Newsletter",
    "email_subject": "New Class Dates Are Up",
    "content_html": "<p>Our winter class dates are posted.</p>",
    "content_text": "Our winter class dates are posted.",
    "response": 1
  }'

POST /api/broadcastSchedule

Schedules one or more broadcasts to one or more lists, either now or at a set time.

ParameterRequiredDescription
nameYesA name for this send
typeYessubscriber to send to lists, or segment to send to segments
broadcast_idsYesBroadcast ID(s), comma-separated
list_idsYes, for listsList ID(s), comma-separated
smtp_idsYesYour sending node ID. Every customer has their own sending node, so ask us for yours.
smtp_sequenceYesbatch or loop
sending_patternYesrandom or sequential
sending_timeYesnow or later
send_datetimeIf laterStart time as YYYY-MM-DD HH:MM:SS
sender_typeYeslist (use the list’s sender details), smtp, or custom
track_opens / track_clicksNo1 to turn on tracking
unsubscribe_headersNo1 to add List-Unsubscribe headers (recommended)
hourly_speedNoMaximum emails per hour

Always schedule a small test send to yourself before sending to a full list. Turning on unsubscribe_headers adds the one-click unsubscribe headers Gmail and Yahoo expect. Learn more in List-Unsubscribe Headers.

curl -X POST "https://app.myemailprogram.com/api/broadcastSchedule" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "November Newsletter - Main List",
    "type": "subscriber",
    "broadcast_ids": "45",
    "list_ids": "12",
    "smtp_ids": "3",
    "smtp_sequence": "batch",
    "sending_pattern": "sequential",
    "sending_time": "later",
    "send_datetime": "2026-11-05 09:00:00",
    "sender_type": "list",
    "track_opens": 1,
    "track_clicks": 1,
    "unsubscribe_headers": 1
  }'

Reporting

GET /api/getBroadcastStatsSummary/{schedule_id}

Returns the results of a scheduled send: total contacts, sent, opens, clicks, click-through rate, bounces, and unsubscribes, plus start and finish times.

The schedule_id is the ID returned when you schedule a broadcast, or the ID shown for that send in your account.

curl "https://app.myemailprogram.com/api/getBroadcastStatsSummary/195" \
  -H "Authorization: Bearer YOUR_API_KEY"

Using the API with AI tools

The API is how you connect MyEmailProgram to the AI tool of your choice to analyze campaign reports, summarize results, or help draft and build emails. A few tips:

  • Create a separate key for each tool. That way you can see what each one does and turn one off without affecting the others.
  • Give each key only what it needs. A key used for reporting and analysis doesn’t need permission to create or schedule broadcasts. Add permissions later if you need them.
  • Keep a human in the loop for sending. Let AI draft and build, then review before anything is scheduled to a real list.

See API & AI Integrations for more ideas.

Need help?

If you’re stuck on a request, send us the endpoint, the request body (with your API key removed), and the response you got back. That’s usually enough for us to spot the problem. Customers can reach Jacob directly. Everyone else can use our contact form.