Email

Emails are what you're for here on Buttondown at the end of the day, right? Creating an email via the API is just like creating one in the interface; it will instantly trigger sending actual emails, based on the tags and email type you provide.

Basic email

{
"creation_date": "2019-08-24T14:15:22Z",
"publish_date": "2024-08-24T14:15:22Z",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"body": "Lorem ipsum yadda yadda",
"subject": "This is my first email on Buttondown!",
"excluded_tags": [],
"included_tags": [],
"email_type": "public",
"status": "sent",
"metadata": {},
"secondary_id": 3,
"external_url": "https://buttondown.email/jmduke/my-first-email"
}

Basic draft

{
"creation_date": "2019-08-24T14:15:22Z",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"body": "Lorem ipsum yadda yadda",
"subject": "This is my first email on Buttondown!",
"excluded_tags": [],
"included_tags": [],
"status": "draft",
"email_type": "public",
"metadata": {},
"secondary_id": 3,
"external_url": "https://buttondown.email/jmduke/my-first-email"
}

Basic scheduled email

{
"creation_date": "2019-08-24T14:15:22Z",
"publish_date": "2024-08-24T14:15:22Z",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"body": "Lorem ipsum yadda yadda",
"subject": "This is my first email on Buttondown!",
"excluded_tags": [],
"included_tags": [],
"status": "scheduled",
"email_type": "public",
"metadata": {},
"secondary_id": 3,
"external_url": "https://buttondown.email/jmduke/my-first-email"
}
fieldtypedescription
idstring
included_tagsarray
excluded_tagsarray
creation_datestring
modification_datestring
publish_datestring
attachmentsarray
subjectstring
canonical_urlstring
imagestring
descriptionstring
sourceEmailSource
bodystringCan be either HTML or markdown.
secondary_idinteger
email_typeEmailType
slugstring
external_urlstring
statusEmailStatus
metadataobject
should_send_teaserboolean
is_comments_disabledboolean
custom_teaserstring
absolute_urlstring
filtersarray
analyticsAnalytics

Status (EmailStatus)

Represents the state of an email. No action is required to move from one state or another; Buttondown internally handles the transitions, and exposing the status is for observability purposes only.


typeidentifierdescription
Draft
draftDraft emails are only visible to you and are not sent out to subscribers.
About to send
about_to_sendThis email has been queued to send out to subscribers, and will be sent automatically within a few minutes.
Scheduled
scheduledThis email has been scheduled to send out to subscribers at a specific time (stored in `publish_date`).
In flight
in_flightThis email is currently being sent out to subscribers, and is visible in your web archives if enabled.
Imported
importedThis email was imported from another service, and is visible in your web archives if enabled.
Managed by RSS
managed_by_rssThis email was created by an external feed, and has not yet been finalized and sent out by Buttondown.
Deleted
deletedThis email has been deleted, and is no longer visible in your web archives.
Paused
pausedThis email has been paused, and is not visible in your web archives.
Sent
sentThis email has been sent out to subscribers, and is visible in your web archives if enabled.
Errored
erroredThis email has encountered an error while sending out to subscribers, and is not visible in your web archives.

Type (EmailType)

Represents the audience of an email, and to whom it is visible both in the initial email and in online archives.


typeidentifierdescription
Public
publicPublic emails are sent out to all of your subscribers and are available in your web archives.
Private
privatePrivate emails are sent out to all of your subscribers but are not viewable in your web archives.
Premium
premiumPremium emails are sent out to only paying subscribers (including those with gift subscriptions or on a free trial), and only premium subscribers can view them in online archives.
Free
freeFree emails are sent out only to subscribers who are not paying for your newsletter (so you can send specific emails to convince them to pay, for instance!)

Create Email

curl
python
ruby
typescript
Copy to clipboard
import requests
headers = {
"Authorization": f"Token {BUTTONDOWN_API_KEY}",
}
BASE_URL = "https://api.buttondown.email"
ENDPOINT = "/v1/emails"
response = requests.post(f"{BASE_URL}{ENDPOINT}", headers=headers)

Parameters

parametertypedescriptionoptional
included_tagsarray
excluded_tagsarray
attachmentsarray
publish_datestring
subjectstring
slugstring
descriptionstring
canonical_urlstring
imagestring
bodystring

Can be either HTML or markdown.

email_type
status
metadataobject
should_send_teaserboolean
is_comments_disabledboolean
custom_teaserstring
secondary_idinteger
filtersarray

Responses

StatusDescriptionSample Response
201Created
{
"creation_date": "2019-08-24T14:15:22Z",
"publish_date": "2024-08-24T14:15:22Z",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"body": "Lorem ipsum yadda yadda",
"subject": "This is my first email on Buttondown!",
"excluded_tags": [],
"included_tags": [],
"email_type": "public",
"status": "sent",
"metadata": {},
"secondary_id": 3,
"external_url": "https://buttondown.email/jmduke/my-first-email"
}
400Bad Request
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
403Forbidden
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
409Conflict
{}

Error codes

typeidentifierdescription
Invalid subject
subject_invalid
Invalid tag
tag_invalid
Duplicate email
email_duplicate
Invalid email
email_invalid

List Emails

curl
python
ruby
typescript
Copy to clipboard
import requests
headers = {
"Authorization": f"Token {BUTTONDOWN_API_KEY}",
}
BASE_URL = "https://api.buttondown.email"
ENDPOINT = "/v1/emails"
response = requests.get(f"{BASE_URL}{ENDPOINT}", headers=headers)

Parameters

parametertypedescriptionoptional
statusarray

Note that for historical reasons, if status is not included in the query, the default is to only return emails with a status of about_to_send, in_flight, or sent. This is a legacy behavior and may change in the future.

If you want to include drafts, you must explicitly include draft in the status query parameter. (Same thing with imported emails.)

included_tagsarray
excluded_tagsarray
automationsarray
idsarray
orderingunknown
creation_date__startstring
creation_date__endstring
publish_date__startstring
publish_date__endstring
excluded_fieldsarray
sourcearray
email_typearray

Responses

StatusDescriptionSample Response
200OK
{
"results": [
{
"creation_date": "2019-08-24T14:15:22Z",
"publish_date": "2024-08-24T14:15:22Z",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"body": "Lorem ipsum yadda yadda",
"subject": "This is my first email on Buttondown!",
"excluded_tags": [],
"included_tags": [],
"email_type": "public",
"status": "sent",
"metadata": {},
"secondary_id": 3,
"external_url": "https://buttondown.email/jmduke/my-first-email"
}
],
"count": 1
}
400Bad Request
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
403Forbidden
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
404Not Found
{}
409Conflict
{}

Error codes

typeidentifierdescription

Update Email

curl
python
ruby
typescript
Copy to clipboard
import requests
headers = {
"Authorization": f"Token {BUTTONDOWN_API_KEY}",
}
BASE_URL = "https://api.buttondown.email"
ENDPOINT = "/v1/emails/{id}"
response = requests.patch(f"{BASE_URL}{ENDPOINT}", headers=headers)

Parameters

parametertypedescriptionoptional
included_tagsarray
excluded_tagsarray
attachmentsarray
publish_datestring
subjectstring
descriptionstring
canonical_urlstring
bodystring

Can be either HTML or markdown.

email_type
status
metadataobject
imagestring
should_send_teaserboolean
is_comments_disabledboolean
custom_teaserstring
slugstring
secondary_idinteger
filtersarray

Responses

StatusDescriptionSample Response
200OK
{
"creation_date": "2019-08-24T14:15:22Z",
"publish_date": "2024-08-24T14:15:22Z",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"body": "Lorem ipsum yadda yadda",
"subject": "This is my first email on Buttondown!",
"excluded_tags": [],
"included_tags": [],
"email_type": "public",
"status": "sent",
"metadata": {},
"secondary_id": 3,
"external_url": "https://buttondown.email/jmduke/my-first-email"
}
400Bad Request
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
403Forbidden
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
404Not Found
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
409Conflict
{}

Retrieve Email

curl
python
ruby
typescript
Copy to clipboard
import requests
headers = {
"Authorization": f"Token {BUTTONDOWN_API_KEY}",
}
BASE_URL = "https://api.buttondown.email"
ENDPOINT = "/v1/emails/{id}"
response = requests.get(f"{BASE_URL}{ENDPOINT}", headers=headers)

Responses

StatusDescriptionSample Response
200OK
{
"creation_date": "2019-08-24T14:15:22Z",
"publish_date": "2024-08-24T14:15:22Z",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"body": "Lorem ipsum yadda yadda",
"subject": "This is my first email on Buttondown!",
"excluded_tags": [],
"included_tags": [],
"email_type": "public",
"status": "sent",
"metadata": {},
"secondary_id": 3,
"external_url": "https://buttondown.email/jmduke/my-first-email"
}
403Forbidden
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
404Not Found
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
409Conflict
{}

Retrieve Email Analytics

curl
python
ruby
typescript
Copy to clipboard
import requests
headers = {
"Authorization": f"Token {BUTTONDOWN_API_KEY}",
}
BASE_URL = "https://api.buttondown.email"
ENDPOINT = "/v1/emails/{id}/analytics"
response = requests.get(f"{BASE_URL}{ENDPOINT}", headers=headers)

Responses

StatusDescriptionSample Response
200OK
{
"recipients": 100,
"deliveries": 99,
"opens": 50,
"clicks": 25,
"temporary_failures": 1,
"permanent_failures": 2,
"unsubscriptions": 3,
"complaints": 1
}
403Forbidden
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
404Not Found
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
409Conflict
{}

Send Draft

curl
python
ruby
typescript
Copy to clipboard
import requests
headers = {
"Authorization": f"Token {BUTTONDOWN_API_KEY}",
}
BASE_URL = "https://api.buttondown.email"
ENDPOINT = "/v1/emails/{id}/send-draft"
response = requests.post(f"{BASE_URL}{ENDPOINT}", headers=headers)

Parameters

parametertypedescriptionoptional
subscribersarray

A list of subscriber ids to which to send the email.

recipientsarray

A list of email addresses to send the email to.

Responses

StatusDescriptionSample Response
200OK
{}
400Bad Request
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
403Forbidden
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
404Not Found
{
"code": "something_went_wrong",
"detail": "Your call is very important to us."
}
409Conflict
{}