---
title: "Create Survey Response"
method: POST
path: "/survey_responses"
tags: ["Survey Responses"]
---

# Create Survey Response

`POST /survey_responses`

Create a new survey response

## Request body

- ResponseInput
  - `subscriber_id` string, required — The subscriber who submitted the response.
  - `survey_id` string, required — The survey being answered.
  - `email_id` string, required — The email ID, automation ID, or arbitrary source string where the survey was answered.
  - `answer` integer, required — The 1-based index of the selected answer in the survey's `answers` list.

## Response `201`

Created

- Response
  - `id` string, required — A unique TypeID associated with the object.
  - `creation_date` string, date-time, required — The date and time at which the object was first created.
  - `answer` string, required — The answer given to the survey.
  - `text` string, required — Optional text included by the subscriber with the response. Subscribers are only prompted to supply a text response if the `is_freeform_response_enabled` field is set to `true` on the survey.
  - `survey_id` string, required — The ID of the survey this response was submitted to.
  - `subscriber_id` string, required — The ID of the subscriber who submitted this response.
  - `email_id` string, nullable — The ID of the email where this response was submitted, if any.
  - `automation_id` string, nullable — The ID of the automation where this response was submitted, if any.
  - `source` string, nullable — For responses not tied to an email or automation, the origin the survey was answered from (e.g. a `transactional:*` template). Null otherwise.
  - `subscriber` Subscriber — Subscribers are the main way you collect email addresses and recipients on Buttondown. They're what you see on your [subscribers page](https://buttondown.com/subscribers). Relevant changes to the schema: - [2024-08-01](https://docs.buttondown.com/api-changelog-2024-08-01): renamed `subscriber_type` and `email` to `type` and `email_address` respectively. - [2024-07-13](https://docs.buttondown.com/api-changelog-2024-08-01): removed `external_url` in favor of `absolute_url`.
    - `id` string, required — A unique TypeID associated with the object.
    - `creation_date` string, date-time, required — The date and time at which the object was first created.
    - `avatar_url` string, nullable — URL of the subscriber's avatar image (e.g. a Gravatar URL), if available.
    - `bounce_date` string, date-time, nullable — The date of the subscriber's most recent bounce event. May be set even if the subscriber has not yet been marked as undeliverable.
    - `bounce_reason` 'access_denied' | 'authentication_issue' | 'delivery_expired' | 'domain_blocked' | 'email_blocked' | 'hard_bounce' | 'ip_blocked' | 'ip_undeliverable' | 'malformed' | 'on_esp_denylist' | 'other' | 'out_of_storage' | 'problematic_url' | 'rate_limited' | 'spam' | 'transient' | 'disabled' | 'does_not_exist' | 'spf_failed' | 'unreachable' — The reason Buttondown has marked the subscriber as undeliverable. Undeliverable subscribers are not sent emails, and may be periodically removed from the system (or restored, if the reason is no longer valid.) These reasons are grouped into three categories: - PermanentFailure ("Failed (recipient)"): Address-based issues where the recipient is truly unreachable. Includes: HARD_BOUNCE - MessageFailure ("Failed (message)"): Message/sender problems where future emails may succeed. Includes: ACCESS_DENIED, AUTHENTICATION_ISSUE, DELIVERY_EXPIRED, DOMAIN_BLOCKED, EMAIL_BLOCKED, IP_BLOCKED, ON_ESP_DENYLIST, OUT_OF_STORAGE, PROBLEMATIC_URL, SPAM - Deferral (not shown to customers): Transient delivery issues that will be retried. Includes: RATE_LIMITED, TRANSIENT
    - `churn_date` string, date-time, nullable — When the subscriber cancelled their paid subscription, if applicable.
    - `commenting_disabled` boolean — Whether this subscriber is prevented from commenting.
    - `country` string, nullable — The ISO 3166-1 alpha-2 country code inferred from the subscriber's IP address at signup, if available.
    - `email_address` string, required — The email address of the subscriber.
    - `gift_subscription_end_date` string, date-time, nullable — When the subscriber's gift subscription expires, if applicable.
    - `gift_subscription_message` string, nullable — A custom message that was sent to the subscriber when the gift subscription was created.
    - `ip_address` string, nullable — The IP address recorded when the subscriber signed up, if available.
    - `last_click_date` string, date-time, nullable — When the subscriber most recently clicked a link in an email.
    - `last_open_date` string, date-time, nullable — When the subscriber most recently opened an email.
    - `delivered_count` integer, nullable — The number of distinct emails — both broadcasts and automation sends — delivered to this subscriber. Cached and refreshed periodically, so it may lag recent activity.
    - `open_count` integer, nullable — The subscriber's open count.
    - `clicked_count` integer, nullable — The subscriber's clicked count.
    - `open_rate` number, nullable — The subscriber's open rate, computed from engagement counts. Null if delivered_count is 0 or null.
    - `click_rate` number, nullable — The subscriber's click rate, computed from engagement counts. Null if delivered_count is 0 or null.
    - `metadata` object — A structured key-value blob that you can use to store arbitrary data on the object. Metadata can be nested — you can store objects and arrays within your metadata. (You can [read more about metadata.](https://docs.buttondown.com/metadata))
    - `notes` string — Any notes you want to attach to the subscriber. These are not publicly visible.
    - `purchased_by` string, nullable — The email address of the individual who purchased this subscription on behalf of the subscriber.
    - `purchased_message` string, nullable — A custom message that was sent to the subscriber when the subscription was purchased on behalf of the subscriber.
    - `referral_code` string, required — The subscriber's unique referral code, used to attribute referred signups.
    - `referrer_url` string — The URL the subscriber was referred from (e.g. where they submitted the subscription form).
    - `risk_score` number, nullable — The risk score of the subscriber. Positive numbers represent a higher risk; negative numbers represent a lower risk.
    - `secondary_id` integer, required — A human-readable sequential identifier, unique within the newsletter.
    - `source` 'admin' | 'api' | 'carrd' | 'comment' | 'embedded_form' | 'form' | 'import' | 'memberful' | 'netlify' | 'organic' | 'patreon' | 'shopify' | 'stripe' | 'user' | 'zapier', required — Represents the original provenance of a subscriber. This value is not exposed to subscribers; it's only used for internal tracking purposes and governs some of the behavior of the subscriber (i.e. whether or not to require double opt-in.)
    - `stripe_coupon` StripeCoupon — Coupons let you offer discounts to subscribers who pay for your newsletter. Buttondown's coupons are backed by Stripe, so each coupon maps to a coupon on your connected Stripe account. Use them to run promotions—for example, a percentage off a paid subscription.
      - `coupon_id` string, required — The Stripe coupon ID (e.g. `coupon_...`).
      - `percent_off` string, nullable — The percentage discount applied by the coupon, if any.
      - `amount_off` integer, nullable — The fixed amount discount applied by the coupon, in the smallest currency unit (e.g. cents), if any.
      - `name` string, nullable — The display name of the coupon.
    - `stripe_customer_id` string, nullable — The Stripe customer ID associated with the subscriber, if any.
    - `subscriber_import_id` string, nullable — The ID of the [subscriber import](https://docs.buttondown.com/importing-subscribers) that created this subscriber, if any.
    - `tags` string[], required — A list of [tag](https://docs.buttondown.com/api-tags-introduction) names applied to the subscriber. Tags that don't already exist will be created, which requires a plan that includes tags (Basic or higher).
    - `transitions` Transition[] — The history of subscriber type transitions (e.g. `regular` → `premium`).
      - `date` string, date-time, required — When the subscriber transitioned to `type`.
      - `type` 'blocked' | 'complained' | 'churning' | 'churned' | 'gifted' | 'unactivated' | 'unpaid' | 'undeliverable' | 'premium' | 'past_due' | 'paused' | 'regular' | 'removed' | 'trialed' | 'unsubscribed' | 'upcoming', required — Represents the state of a subscriber and what emails they should or should not be receiving. This type is meant to be fully expressive so as to consolidate the logic of determining what emails a subscriber should receive into a single place. Note that the only types that can be set programmatically are REGULAR, UNSUBSCRIBED, GIFTED and UNPAID. All other types are meant to be user-visible and cannot be set programmatically.
    - `email_transitions` EmailTransition[] — The history of email address changes for this subscriber.
      - `date` string, date-time, required — When the email address change took effect.
      - `old_email_address` string, nullable — The subscriber's previous email address, or null for the initial address.
      - `new_email_address` string, required — The subscriber's email address after the transition.
    - `form_id` string, nullable — The ID of the [registration form](https://docs.buttondown.com/registration-forms) the subscriber signed up through, if any.
    - `firewall_reasons` FirewallReason[] — Information collected by Buttondown's firewall about this subscriber. See [the firewall](https://docs.buttondown.com/firewall) for more information.
      - `code` 'email_address_capital_letters' | 'email_address_cleantalk_score' | 'email_address_contains_prohibited_string' | 'email_address_domain_burst' | 'email_address_esp_suppression' | 'email_address_extant_subscriber_count' | 'email_address_gmail_word_numbers' | 'email_address_has_gravatar' | 'email_address_is_honeypot' | 'email_address_length' | 'email_address_local_part_has_many_periods' | 'email_address_many_consonants_in_a_row' | 'email_address_mx_record_is_valid' | 'email_address_noreply_local_part' | 'email_address_null_characters' | 'email_address_peaceful_domain' | 'email_address_plus_single_number' | 'email_address_plus_variant_accounts' | 'email_address_previous_evaluation' | 'email_address_prohibited_via_domain' | 'email_address_regex' | 'email_address_sandbox_test' | 'email_address_shannon_entropy' | 'email_address_tied_to_account' | 'email_address_typo' | 'embedded_form_honeypot' | 'fingerprint_missing' | 'ip_address_cleantalk_score' | 'ip_address_country_risk' | 'ip_address_datacenter' | 'ip_address_extant_subscriber_count' | 'ip_address_peaceful' | 'ip_address_previous_evaluation' | 'ip_address_prohibited' | 'metadata_has_garbage' | 'newsletter_age' | 'newsletter_has_customized_transactional_email' | 'newsletter_has_prohibited_string' | 'newsletter_status' | 'project_honeypot' | 'referrer_url_prohibited' | 'registration_without_prior_page_visit' | 'subscriber_import_provenance' | 'subscriber_import_source' | 'text_contains_malicious_url' | 'text_contains_prohibited_string' | 'turnstile_response_token_is_valid' | 'user_agent_known' | 'username_shannon_entropy', required — An enumeration.
      - `reason` string, required — Human-readable explanation for why we flagged the subscriber.
    - `type` 'blocked' | 'complained' | 'churning' | 'churned' | 'gifted' | 'unactivated' | 'unpaid' | 'undeliverable' | 'premium' | 'past_due' | 'paused' | 'regular' | 'removed' | 'trialed' | 'unsubscribed' | 'upcoming', required — Represents the state of a subscriber and what emails they should or should not be receiving. This type is meant to be fully expressive so as to consolidate the logic of determining what emails a subscriber should receive into a single place. Note that the only types that can be set programmatically are REGULAR, UNSUBSCRIBED, GIFTED and UNPAID. All other types are meant to be user-visible and cannot be set programmatically.
    - `undeliverability_date` string, date-time, nullable — When the subscriber was marked as undeliverable, if applicable.
    - `undeliverability_reason` 'access_denied' | 'authentication_issue' | 'delivery_expired' | 'domain_blocked' | 'email_blocked' | 'hard_bounce' | 'ip_blocked' | 'ip_undeliverable' | 'malformed' | 'on_esp_denylist' | 'other' | 'out_of_storage' | 'problematic_url' | 'rate_limited' | 'spam' | 'transient' | 'disabled' | 'does_not_exist' | 'spf_failed' | 'unreachable' — The reason Buttondown has marked the subscriber as undeliverable. Undeliverable subscribers are not sent emails, and may be periodically removed from the system (or restored, if the reason is no longer valid.) These reasons are grouped into three categories: - PermanentFailure ("Failed (recipient)"): Address-based issues where the recipient is truly unreachable. Includes: HARD_BOUNCE - MessageFailure ("Failed (message)"): Message/sender problems where future emails may succeed. Includes: ACCESS_DENIED, AUTHENTICATION_ISSUE, DELIVERY_EXPIRED, DOMAIN_BLOCKED, EMAIL_BLOCKED, IP_BLOCKED, ON_ESP_DENYLIST, OUT_OF_STORAGE, PROBLEMATIC_URL, SPAM - Deferral (not shown to customers): Transient delivery issues that will be retried. Includes: RATE_LIMITED, TRANSIENT
    - `unsubscription_date` string, date-time, nullable — When the subscriber unsubscribed, if applicable.
    - `unsubscription_reason` string, nullable — Free-text reason the subscriber unsubscribed, if provided.
    - `upgrade_date` string, date-time, nullable — When the subscriber upgraded to a paid subscription, if applicable.
    - `utm_campaign` string, required — The UTM campaign the subscriber was attributed to at signup.
    - `utm_medium` string, required — The UTM medium the subscriber was attributed to at signup.
    - `utm_source` string, required — The UTM source the subscriber was attributed to at signup.
    - `stripe_customer` object, nullable — If expanded, the Stripe customer associated with this subscriber.
    - `stripe_subscription` object, nullable — If expanded, the Stripe subscription backing this subscriber's paid subscription.
  - `survey` Survey — Surveys let you ask your subscribers a question—and personalize future emails based on their answers. You can attach a survey to any email and read back the responses via the API.
    - `id` string, required — A unique TypeID associated with the object.
    - `creation_date` string, date-time, required — The date and time at which the object was first created.
    - `identifier` string, required — A newsletter-scoped slug used to reference this survey when embedding it in emails.
    - `question` string, required — The survey question shown to subscribers.
    - `response_count` integer, required — The total number of responses this survey has received.
    - `answers` string[], required — The list of pre-defined answer choices. Order is preserved unless `randomize_answers` is true.
    - `notes` string, required — Internal notes about the survey. Not shown to subscribers.
    - `randomize_answers` boolean, required — If true, the order of `answers` is shuffled each time the survey is rendered.
    - `response_cadence` 'once' | 'once_per_email', required — An enumeration.
    - `status` 'active' | 'inactive', required — An enumeration.
    - `is_freeform_response_enabled` boolean, required — If true, subscribers can provide a freeform text response in addition to (or instead of) picking from `answers`.
    - `input_type` 'radio' | 'checkbox' | 'text', required — An enumeration.
  - `email` Email — Emails are why you're here on Buttondown, 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. Relevant changes to the schema: - [2024-08-15](https://docs.buttondown.com/api-changelog-2024-08-15): unshipped the `included_tags` and `excluded_tags` fields. - [2024-12-30](https://docs.buttondown.com/api-changelog-2024-12-30): unshipped the `is_comments_disabled` field, and replaced it with a more flexible `commenting_mode` field. - [2025-09-23](https://docs.buttondown.com/api-changelog-2025-09-23): increased the maximum length of the `subject` field from 1000 to 2000 characters.
    - `id` string, required — A unique TypeID associated with the object.
    - `creation_date` string, date-time, required — The date and time at which the object was first created.
    - `absolute_url` string, required — The canonical web URL of the email on the newsletter's archive.
    - `analytics` Analytics
      - `recipients` integer — The number of subscribers the email was dispatched to.
      - `deliveries` integer — The number of successful deliveries (recipients minus failures).
      - `opens` integer — The number of unique opens recorded.
      - `clicks` integer — The number of unique link clicks recorded.
      - `temporary_failures` integer — The number of temporary delivery failures (e.g. soft bounces).
      - `permanent_failures` integer — The number of permanent delivery failures (e.g. hard bounces).
      - `unsubscriptions` integer — The number of subscribers who unsubscribed after receiving this email.
      - `complaints` integer — The number of spam complaints recorded against this email.
      - `survey_responses` integer — The number of survey responses submitted from this email.
      - `webmentions` integer — The number of inbound webmentions received for this email.
      - `page_views_lifetime` integer — The total number of archive page views for this email since publication.
      - `page_views_30` integer — The number of archive page views in the last 30 days.
      - `page_views_7` integer — The number of archive page views in the last 7 days.
      - `subscriptions` integer — The number of new subscribers attributed to this email.
      - `paid_subscriptions` integer — The number of new paid subscribers attributed to this email.
      - `replies` integer — The number of reply emails received from subscribers.
      - `comments` integer — The number of comments posted on this email.
      - `social_mentions` integer — The number of social media mentions of this email.
      - `temporary_failure_breakdown` FailureBreakdownItem[] — Breakdown of temporary failures by reason code, sorted by count descending.
        - `code` string, required — The failure reason code (e.g. 'hard_bounce', 'spam')
        - `count` integer, required — Number of failures with this reason
      - `permanent_failure_breakdown` FailureBreakdownItem[] — Breakdown of permanent failures by reason code, sorted by count descending.
        - `code` string, required — The failure reason code (e.g. 'hard_bounce', 'spam')
        - `count` integer, required — Number of failures with this reason
    - `callouts` Callout[] — A list of callouts that apply to this email — surfaced in the UI alongside analytics to flag context the reader should know about (e.g., first send on a custom sending domain).
    - `attachments` string[], nullable — A list of attachment IDs present on the email. (See [Attachments](https://docs.buttondown.com/api-attachments-introduction) for more information.)
    - `body` string, required — The body of the email, in either HTML or markdown format. Buttondown attempts to intelligently detect the format of the body automatically, but you can also specify the format explicitly by prepending the text with the `buttondown-editor-mode` comment: `<!-- buttondown-editor-mode: fancy -->` or `<!-- buttondown-editor-mode: plaintext -->`.
    - `canonical_url` string, required — The URL of the original source of the content.
    - `commenting_mode` 'disabled' | 'enabled' | 'enabled_for_paid_subscribers', required — Governs who can comment on this email. This enum replaces the `is_comments_disabled` field, which has been deprecated. (Also note that this field may be superseded by newsletter-level settings; for instance, "enabled" is an invalid and inert value if the newsletter itself has comments disabled.)
    - `description` string, required — A human-readable description of the email, used for archives and SEO.
    - `archival_mode` 'archive_only' | 'disabled' | 'enabled' | 'enabled_for_paid_subscribers' | 'enabled_for_subscribers', required — Governs who can view this email in the archive. `ARCHIVE_ONLY` is the odd one out: the email is publicly archived but is not email content at all (e.g. an imported blog post), so it is excluded from email-rendering contexts like "recent issues" widgets.
    - `email_type` 'public' | 'private' | 'premium' | 'free' | 'churned' | 'archival' — The legacy single-axis representation of an email's audience and archive visibility. No longer stored: `filters` owns the audience axis and `archival_mode` owns the archive axis, and the deprecated API field is derived from those (see `email_type` below).
    - `featured` boolean, required — Designated whether or not this email should be highlighted within the archives.
    - `filters` FilterGroup, required — Buttondown's filtering schema can be used for multiple things: - Filtering [the audience of an email](/api-emails-create) to a specific subset - Creating [finely-tuned automations](/api-automation-introduction) Filters are fractal; they can be nested in groups, and groups can be nested in other groups. This is accomplished through a tree-like structure. Every "FilterGroup" has a "predicate" field, which is either "and" or "or", which determines how the filters and groups within the group are combined, a "groups" field, which is a list of "FilterGroup" objects (that's that recursive bit!), and a "filters" field, which are the leaf-level filters themselves. Let's say you want a simple filter: all subscribers who have a tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40j`. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}], "groups": [], "predicate": "and" } ``` Now, let's say you want to filter for subscribers who have that tag and a tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40k`. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}], "groups": [], "predicate": "and" } ``` If you wanted to change that `and` to an `or`, you can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}], "groups": [], "predicate": "or" } ``` Now, let's say you want to filter for subscribers who have the first tag _or_ both the second tag and a third tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40m`. This is where the whole nested thing comes in handy. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}], "groups": [ { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40m"}], "groups": [], "predicate": "and" } ], "predicate": "or" } ``` You can read more about the specific filter construction in the [Filter documentation](/api-emails-filter).
      - `filters` Filter[], required — The leaf-level filters to apply to the audience.
        - `field` string, required
        - `operator` 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_empty' | 'is_not_empty' | 'greater_than' | 'less_than', required — An enumeration.
        - `value` string, required
      - `groups` FilterGroup[], required — The nested groups to apply to the audience.
      - `predicate` 'and' | 'or', required — The logical operator to use when combining filters (either 'and' or 'or').
    - `image` string, required — A primary image URL used when previewing the email on the web or in other contexts.
    - `metadata` object — A structured key-value blob that you can use to store arbitrary data on the object. Metadata can be nested — you can store objects and arrays within your metadata. (You can [read more about metadata.](https://docs.buttondown.com/metadata))
    - `modification_date` string, date-time, required — The date and time at which the object was last modified.
    - `publish_date` string, date-time, nullable — The date and time at which the email should be published in the future (for scheduled emails), or the date and time at which the email was published (for sent emails).
    - `related_email_ids` string[], required — A list of email IDs that are related to this email. Related emails are shown at the bottom of the email and archive pages.
    - `secondary_id` integer, nullable — An informal 'number' for the email, used in some templates ('This was issue #123').
    - `should_trigger_pay_per_email_billing` boolean, required — Whether this email should trigger pay-per-email billing for paid subscribers. Use this to differentiate between free updates and premium newsletters.
    - `slug` string, nullable — A short, human-readable identifier for the email, used in the archive URL.
    - `source` 'api' | 'import' | 'app' | 'external_feed' | 'smtp', required — Represents the original provenance of an email. This value is not exposed to subscribers, but does determine some behavior of the email (e.g. whether or not analytics can be calculated.)
    - `status` 'draft' | 'managed_by_rss' | 'about_to_send' | 'scheduled' | 'in_flight' | 'paused' | 'deleted' | 'errored' | 'sent' | 'imported' | 'throttled' | 'resending' | 'transactional' | 'suppressed', required — 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.
    - `subject` string, required — The subject line for the email.
    - `suppression_reason` 'law_enforcement' | 'internal_auditing' — Represents the reason an email was suppressed.
    - `template` 'classic' | 'custom' | 'modern' | 'plaintext' | 'naked' — Represents the template of an email. Each template has a different layout/style; you can view screenshots and examples [in the docs](https://docs.buttondown.com/customizing-email-design#buttondowns-default-templates).
  - `automation` Automation — A rule that automatically performs actions in response to events.
    - `id` string, required — A unique TypeID associated with the object.
    - `creation_date` string, date-time, required — The date and time at which the object was first created.
    - `name` string, required — The name of the automation.
    - `status` 'active' | 'inactive', required — An enumeration.
    - `trigger` 'advertising_slot.inquiry' | 'advertising_slot.purchased' | 'automation.invoked' | 'date.day.started' | 'date.month.started' | 'date.week.started' | 'date.year.started' | 'bigcommerce.customer.created' | 'bigcommerce.customer.updated' | 'bigcommerce.order.created' | 'bigcommerce.order.updated' | 'email.created' | 'email.deleted' | 'email.sent' | 'email.status.changed' | 'email.updated' | 'external_feed_item.created' | 'export.completed' | 'export.created' | 'export.failed' | 'firewall.blocked' | 'mention.created' | 'memberful.member.updated' | 'memberful.subscription.created' | 'memberful.subscription.deleted' | 'note.created' | 'note.deleted' | 'patreon.member.updated' | 'patreon.membership.created' | 'patreon.membership.deleted' | 'shopify.customer.created' | 'shopify.customer.updated' | 'social_mention.created' | 'stripe.checkout.session.completed' | 'stripe.customer.updated' | 'stripe.invoice.upcoming' | 'stripe.subscription.activated' | 'stripe.subscription.churning' | 'stripe.subscription.deactivated' | 'subscriber.activation_bounced' | 'subscriber.activation_clicked' | 'subscriber.activation_complained' | 'subscriber.activation_deferred' | 'subscriber.activation_delivered' | 'subscriber.activation_opened' | 'subscriber.activation_rejected' | 'subscriber.bounced' | 'subscriber.changed_email' | 'subscriber.churned' | 'subscriber.clicked' | 'subscriber.commented' | 'subscriber.complained' | 'subscriber.confirmed' | 'subscriber.created' | 'subscriber.deferred' | 'subscriber.deleted' | 'subscriber.delivered' | 'subscriber.opened' | 'subscriber.paid' | 'subscriber.paused' | 'subscriber.resumed' | 'subscriber.referred' | 'subscriber.referred.paid' | 'subscriber.rejected' | 'subscriber.replied' | 'subscriber.sent' | 'subscriber.responded_to_survey' | 'subscriber.tags.changed' | 'subscriber.trial_ended' | 'subscriber.trial_started' | 'subscriber.type.changed' | 'subscriber.unsubscribed' | 'subscriber.updated' | 'subscriber.viewed_checkout_page' | 'survey.cleared_responses' | 'survey.created' | 'survey.deleted' | 'survey.updated' | 'form.created' | 'form.deleted' | 'form.updated', required — Various types of events that are recorded by Buttondown, both in terms of exogenous systems like Stripe and Memberful, and endogenous ones like email opens and clicks. (In general, if anything important ever happens that could be relevant to your newsletter, we have an event type for it!) These event types power lots of things within Buttondown. They're used to trigger automations, webhooks, and analytics. (Note that the `/v1/events` API speaks an older, shorter vocabulary for subscriber engagement — `clicked` rather than `subscriber.clicked` — a relic of a previous events system. Each of those names maps onto one of the `subscriber.*` types below.) In general, our event namespacing tries to hew to the following pattern: `<source>.<object>.<action>` When wondering which object we are referring to, default to the _more granular_ object. For instance, an email being sent to a subscriber is `subscriber.delivered`, not `email.sent`.
    - `actions` Action[], required — The actions to perform when the trigger fires.
      - `type` 'add_tags' | 'remove_tags' | 'send_email' | 'add_metadata' | 'remove_metadata' | 'change_email_address' | 'gift_premium_subscription' | 'ungift_premium_subscription' | 'send_discord_invitation' | 'send_github_invitation' | 'create_subscriber' | 'unsubscribe_subscriber' | 'shopify_unsubscribe' | 'shopify_resubscribe' | 'shopify_set_tags' | 'shopify_create_customer' | 'send_notification' | 'forward_reply' | 'create_arena_post' | 'create_bluesky_post' | 'create_linkedin_post' | 'create_mastodon_post' | 'create_tumblr_post' | 'create_twitter_post' | 'create_export' | 'create_gift_subscriber' | 'send_post_request' | 'send_confirmation_reminder' | 'update_email_type', required — The action that is triggered when the automation is successfully run.
      - `metadata` object, required — Configuration specific to the action type.
      - `timing` Timing — Controls when an automation's action executes after the trigger fires.
        - `time` 'immediate' | 'delay', required — Whether the action should execute immediately or after a delay.
        - `delay` Delay — Configuration for how long to wait before executing the automation's action.
          - `value` string, required — The number of time units to delay.
          - `unit` 'minutes' | 'hours' | 'days' | 'weeks', required — The unit of time for the delay.
          - `time_of_day` 'morning' | 'evening' | '', nullable — If set, the action will be executed at this time of day after the delay has passed.
    - `filters` FilterGroup, required — Buttondown's filtering schema can be used for multiple things: - Filtering [the audience of an email](/api-emails-create) to a specific subset - Creating [finely-tuned automations](/api-automation-introduction) Filters are fractal; they can be nested in groups, and groups can be nested in other groups. This is accomplished through a tree-like structure. Every "FilterGroup" has a "predicate" field, which is either "and" or "or", which determines how the filters and groups within the group are combined, a "groups" field, which is a list of "FilterGroup" objects (that's that recursive bit!), and a "filters" field, which are the leaf-level filters themselves. Let's say you want a simple filter: all subscribers who have a tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40j`. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}], "groups": [], "predicate": "and" } ``` Now, let's say you want to filter for subscribers who have that tag and a tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40k`. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}], "groups": [], "predicate": "and" } ``` If you wanted to change that `and` to an `or`, you can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}], "groups": [], "predicate": "or" } ``` Now, let's say you want to filter for subscribers who have the first tag _or_ both the second tag and a third tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40m`. This is where the whole nested thing comes in handy. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}], "groups": [ { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40m"}], "groups": [], "predicate": "and" } ], "predicate": "or" } ``` You can read more about the specific filter construction in the [Filter documentation](/api-emails-filter).
      - `filters` Filter[], required — The leaf-level filters to apply to the audience.
        - `field` string, required
        - `operator` 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_empty' | 'is_not_empty' | 'greater_than' | 'less_than', required — An enumeration.
        - `value` string, required
      - `groups` FilterGroup[], required — The nested groups to apply to the audience.
      - `predicate` 'and' | 'or', required — The logical operator to use when combining filters (either 'and' or 'or').
    - `metadata` object, required — Additional metadata for the automation.
    - `should_evaluate_filter_after_delay` boolean, required — If true, filters are re-evaluated after the delay has passed.

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `404` — Not Found
- `409` — Conflict
- `422` — Unprocessable Entity
- `429` — Too Many Requests

---

[API](https://skmtc.net/buttondown/apis/buttondown-api.md) · [All operations](https://skmtc.net/buttondown/apis/buttondown-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/buttondown/buttondown-api/versions/3a702c095d22/schema)
