GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

No menu could be recovered. Follow the blue links in the page.

This view

  • Original page
  • New address

GeezerVison is showing developer.drip.com (truncated) — Drip API Reference

cURL Ruby JavaScript
  • Introduction
  • REST API

  • Authentication
    • OAuth
  • Rate Limiting
  • Batch API
    • Create or update a batch of subscribers
    • Unsubscribe a batch of subscribers
    • Record a batch of events
    • Create or update a batch of carts
    • Create or update a batch of orders (Legacy)
    • Create or update a batch of orders
    • Create or update a batch of products
  • Pagination
  • Errors
    • Validation Errors
    • Transition Errors
  • Accounts
    • List all accounts
    • Fetch an account
  • Single-Email Campaigns
    (aka Broadcasts)
    • Email Content
    • Sender
    • List all Single-Email Campaigns
    • Create a Single-Email Campaign
    • Fetch a Single-Email Campaign
    • Update a Single-Email Campaign
    • Delete a Single-Email Campaign
    • Send a test email
    • Set the audience
    • Fetch the audience
    • Schedule a Single-Email Campaign
    • Unschedule a Single-Email Campaign
  • Email Series Campaigns
    • List all Email Series Campaigns
    • Fetch an Email Series Campaign
    • Activate an Email Series Campaign
    • Pause an Email Series Campaign
    • List all subscribers subscribed to an Email Series Campaign
    • Subscribe someone to an Email Series Campaign
    • List all of a subscriber's Email Series Campaign subscriptions
  • Custom Fields
    • List all custom field identifiers used in an account
  • Conversions
    • List all conversions
    • Fetch a conversion
  • Events
    • Record an event
    • List all custom events actions used in an account
  • Forms
    • List all forms
    • Fetch a form
  • Metrics
    • Email Metrics
    • Fetch email metrics
  • Orders (Legacy)
    • Create or update an order
    • Create or update a refund
    • Order events
  • Segments
    • List all segments
    • Fetch a segment
  • Subscribers
    • Create or update a subscriber
    • List all subscribers
    • Fetch a subscriber
    • Remove a subscriber from one or all Email Series Campaigns
    • Unsubscribe from all mailings
    • Delete a subscriber
  • Tags
    • List all tags used in an account
    • Apply a tag to a subscriber
    • Remove a tag from a subscriber
  • Users
    • Fetch the authenticated user
  • Workflows
    • List all workflows
    • Fetch a workflow
    • Fetch a workflow's details
    • Fetch a workflow email
    • Activate a workflow
    • Pause a workflow
    • Start someone on a workflow
    • Remove a subscriber from a workflow
    • List all workflow triggers
    • Create a workflow trigger
    • Update a workflow trigger
  • Webhooks
    • List all webhooks
    • Fetch a webhook
    • Create a new webhook
    • Destroy a webhook
  • Webhook Events
    • Setting Up
    • Resources
    • subscriber.created
    • subscriber.deleted
    • subscriber.marked_as_deliverable
    • subscriber.marked_as_undeliverable
    • subscriber.subscribed_to_email_marketing
    • subscriber.subscribed_to_campaign
    • subscriber.removed_from_campaign
    • subscriber.unsubscribed_from_campaign
    • subscriber.unsubscribed_all
    • subscriber.reactivated
    • subscriber.completed_campaign
    • subscriber.applied_tag
    • subscriber.removed_tag
    • subscriber.updated_custom_field
    • subscriber.updated_email_address
    • subscriber.updated_lifetime_value
    • subscriber.updated_time_zone
    • subscriber.received_email
    • subscriber.opened_email
    • subscriber.clicked_email
    • subscriber.bounced
    • subscriber.complained
    • subscriber.clicked_trigger_link
    • subscriber.visited_page
    • subscriber.became_lead
    • subscriber.became_non_prospect
    • subscriber.updated_lead_score
    • subscriber.performed_custom_event
    • subscriber.updated_alias
  • Shopper Activity

  • Overview
  • Cart Activity
    • Create or update a cart
  • Order Activity
    • Create or update an order
  • Product Activity
    • Create or update a product
  • JS API

  • Getting Started
    • Installing Your JavaScript Snippet
    • How to Send a JS API Request
  • Identifying Visitors
    • Attach Identifying Data to Visitors
  • Tracking Events
    • Tracking Events and Conversions for subscribers
  • Tracking Product Views
    • Properties
    • Response
  • Tagging via Query String
  • Email Series Campaign Subscriptions
    • Subscribe to an Email Series Campaign
    • Unsubscribe a Subscriber
  • Handling Forms
    • Opening and closing a form
    • Form Submission Events
  • Custom Dynamic Content

  • Overview
    • How it works
  • API Requirements
    • Endpoint
    • Parameters
    • Response
    • General
  • Preview/Test Mode
  • Example
    • Need a Drip Account? Sign Up

    Drip API Documentation

    Introduction

    Welcome to the Drip API! The REST API communicates exclusively in JSON over SSL (HTTPS). All endpoint URLs begin with https://api.getdrip.com/. Additionally, the REST API requires the use of a client which supports SNI.

    Parameters must be serialized in JSON and passed in the request body (not in the query string or form parameters). You should use the media type designation of application/json.

    REST Section

    Authentication

    For private integrations, you will need to use your personal API Token (found here) via the api_key setting. The API Token is the username portion of the Basic Authentication scheme, with an empty password. (Note the trailing colon to indicate an empty password.)

    require 'drip-ruby'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR_API_KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')(
      {
        token: YOUR_API_KEY,
        accountId: YOUR_ACCOUNT_ID
      }
    );
    
    curl "api_endpoint_here" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -H 'Authorization: Basic $(echo YOUR_API_KEY: | base64)'
    
    curl "api_endpoint_here" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u 'YOUR_API_KEY:'
    

    For public integrations, for example, when allowing your customers within your application to authorize access directly to their Drip accounts, pass in the user's OAuth token via the access_token setting or pass the Bearer token type when using the JS wrapper:

    client = Drip::Client.new do |c|
      c.access_token = "YOUR_ACCESS_TOKEN"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')(
      {
        token: YOUR_API_KEY,
        tokenType: "Bearer",
        accountId: YOUR_ACCOUNT_ID
      }
    );
    
    curl "api_endpoint_here" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
    

    The REST API accepts both token-based authentication (intended for private integrations), and full OAuth 2 authentication (for public integrations).

    You must replace YOUR_API_KEY / YOUR_ACCESS_TOKEN with your actual token.

    OAuth

    For public integrations with Drip, you must use OAuth based authentication. Here's a quick overview of how to get going.

    1. Get your favorite OAuth Library
    2. Register your application with us. We will then supply you with an client id and client secret. Please be aware that you must also enter a valid callback url before you will be able to activate your application.
    3. Configure your OAuth client with the credentials supplied to you when you created your application. Request authorization at: https://www.getdrip.com/oauth/authorize. You should only have to do this once, as tokens do not expire.
    4. Activate your application and you're on your way!

    If you're not going to use a library and will be rolling your own OAuth 2 client, here's the long form of how you can get going.

    {
      "access_token": "822bbf7cd12243df...",
      "token_type": "bearer",
      "scope": "public"
    }
    
    1. First and foremost remember to register your app with us as outlined above.
    2. Once you have registered your app, it will then need to request authorization by redirecting your user to the following url:

      https://www.getdrip.com/oauth/authorize?response_type=code&client_id=<your_client_id>&redirect_uri=<your_redirect_uri>

    3. We will then authenticate their Drip account and ask if it's ok to give access to your app.
    4. The user will then be redirected back to your app with a verification code that will expire in 10 minutes.
    5. Your app will then need to make a request to trade that verification code for an access token:

      POST https://www.getdrip.com/oauth/token?response_type=token&client_id=<your_client_id>&client_secret=<your_client_secret>&code=<your_verification_code>&redirect_uri=<your_redirect_uri>&grant_type=authorization_code

    6. We will then authenticate your app and issue you an access token as shown on the right.
    7. You can now use that access token in the header of your API requests as follows:

      Authorization: Bearer 822bbf7cd12243df...

    Rate Limiting

    All API requests subject to rate limiting contain information regarding your current rate limit status in the response headers:

    HTTP/1.1 200 OK
    Status: 200 OK
    X-RateLimit-Limit: 3600
    X-RateLimit-Remaining: 3597
    

    If you exceed your rate limit, the API will returns a 429 status:

    HTTP/1.1 429 Too Many Requests
    Content-Type: application/json
    
    {
      "message": "API rate limit exceeded. Please try again in an hour.",
      "documentation": "https://www.getdrip.com/docs/rest-api#rate-limting"
    }
    

    You can make up to 50 requests per hour for batch endpoints and 3,600 individual requests per hour for other API endpoints. Each batch request accommodates up to 1,000 records in the payload for a total of 50,000 updates per hour.

    To minimize your API requests, use the Batch API.

    Batch API

    Create or update a batch of subscribers

    To create or update a batch of subscribers:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/batches" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "batches": [{
          "subscribers": [
            {
              "email": "[email protected]",
              "time_zone": "America/Los_Angeles",
              "tags": ["Customer", "SEO"],
              "custom_fields": {
                "shirt_size": "Medium"
              }
            },
            {
              "email": "[email protected]",
              "time_zone": "America/Los_Angeles",
              "tags": ["Prospect"],
              "custom_fields": {
                "shirt_size": "Medium"
              }
            }
          ]
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    # An array of subscribers
    subscribers = [
      {
        "email": "[email protected]"
      },
      {
        "email": "[email protected]"
      }
      # ...
    ]
    
    response = client.create_or_update_subscribers(subscribers)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const batch = {
      "batches": [{
        "subscribers": [
          {
            "email": "[email protected]",
            "tags": "Dog Person"
          },
          {
            "email": "[email protected]",
            "tags": "Cat Person"
          }
          // Lots more subscribers...
        ]
      }]
    };
    
    client.updateBatchSubscribers(batch, (errors, responses, bodies) => {
      // Do stuff
      }
    );
    

    Responds with a 201 Created response and an empty JSON response if successful:

    {}
    

    We recommend using this API endpoint when you need to create or update a collection of subscribers at once.

    Note: Since our batch APIs process requests in the background, there may be a delay between the time you submit your request and the time your data appears in the user interface.

    HTTP Endpoint

    POST /v2/:account_id/subscribers/batches

    Arguments

    Key Description
    subscribers Required. An Array with between 1 and 1000 objects containing subscriber data.

    Unsubscribe a batch of subscribers

    To globally unsubscribe a batch of subscribers:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/unsubscribes/batches" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "batches": [{
          "subscribers": [
            {
              "email": "[email protected]"
            },
            {
              "email": "[email protected]"
            }
          ]
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    # An array of subscribers
    subscribers = [
      {
        "email": "[email protected]"
      },
      {
        "email": "[email protected]"
      }
      # ...
    ]
    
    response = client.unsubscribe_subscribers(subscribers)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const payload = {
      batches:
      [
        {
          subscribers: [
            {
              email: "[email protected]"
            }
          ]
        }
      ]
    };
    
    client.unsubscribeBatchSubscribers(payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content response if successful.

    HTTP Endpoint

    POST /v2/:account_id/unsubscribes/batches

    Arguments

    Key Description
    subscribers Required. An Array with between 1 and 1000 objects containing subscriber data.

    Record a batch of events

    To record a batch of events:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/events/batches" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "batches": [{
          "events": [
            {
              "email": "[email protected]",
              "action": "Opened a door"
            },
            {
              "email": "[email protected]",
              "action": "Closed a door"
            }
          ]
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    # An array of events
    events = [
      {
        "email": "[email protected]",
        "action": "Opened a door"
      },
      {
        "email": "[email protected]",
        "action": "Closed a door"
      }
      # ...
    ]
    
    response = client.track_events(events)
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const payload = [{
        events: [
          {
            email: "[email protected]",
            action: "Opened a door"
          },
          {
            email: "[email protected]",
            action: "Closed a door"
          }
        ]
      }];
    
    client.recordBatchEvents(payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 201 Created response and an empty JSON response if successful:

    {}
    

    We recommend using this API endpoint when you need to record a collection of events at once that will likely exceed the regular rate limit of 3,600 requests per hour.

    Note: Since our batch APIs process requests in the background, there may be a delay between the time you submit your request and the time your data appears in the user interface.

    HTTP Endpoint

    POST /v2/:account_id/events/batches

    Arguments

    Key Description
    events Required. An Array with between 1 and 1000 objects containing event data.

    Create or update a batch of carts

    To create or update a batch of carts:

    curl -X POST "https://api.getdrip.com/v3/YOUR_ACCOUNT_ID/shopper_activity/cart/batch" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "carts": [
          {
            "provider": "my_custom_platform",
            "email": "[email protected]",
            "action": "created",
            "cart_id": "456445746",
            "occurred_at": "2019-01-17T20:50:00Z",
            "cart_public_id": "#5",
            "grand_total": 16.99,
            "total_discounts": 5.34,
            "currency": "USD",
            "cart_url": "https://mysuperstore.com/cart/456445746",
            "items": [
              {
                "product_id": "B01J4SWO1G",
                "product_variant_id": "B01J4SWO1G-CW-BOTT",
                "sku": "XHB-1234",
                "name": "The Coolest Water Bottle",
                "brand": "Drip",
                "categories": [
                  "Accessories"
                ],
                "price": 11.16,
                "quantity": 2,
                "discounts": 5.34,
                "total": 16.99,
                "product_url": "https://mysuperstore.com/dp/B01J4SWO1G",
                "image_url": "https://www.getdrip.com/images/example_products/water_bottle.png",
                "product_tag": "Best Seller"
              }
            ]
          },
          {
            "provider": "my_custom_platform",
            "email": "[email protected]",
            "action": "created",
            "occurred_at": "2019-03-12T15:31:58Z",
            "cart_id": "63754763",
            "cart_public_id": "#4",
            "grand_total": 54.00,
            "total_discounts": 1.00,
            "currency": "USD",
            "order_url": "http://myorders.com/orders/4",
            "items": [{
              "product_id": "B01F9AQ99M",
              "product_variant_id": "B01F9AQ99M-YEL-BT",
              "sku": "JDT-4321",
              "name": "Yellow Boots of Might",
              "brand": "Drip",
              "categories": [
                "Of Might",
                "Outdoors"
              ],
              "price": 55.00,
              "quantity": 1,
              "discounts": 1.00,
              "total": 54.00,
              "color": "black",
              "product_url": "https://mysuperstore.com/dp/B01F9AQ99M",
              "image_url": "https://www.getdrip.com/images/example_products/boots.png"
            }]
          }
        ]
      }
    EOF
    

    Responds with a 202 Accepted if successful. That means the server accepted the request and queued it for processing. The response includes a list of unique request_ids that can be used to check the status of the request later on:

    {
      "request_ids": [
        "db8a7b16-32dd-4863-8b6e-818e3eaab99a",
        "002048e9-3692-4f0a-8bbf-80a077acf642"
      ]
    }
    

    We recommend using this API endpoint when you need to import a collection of carts that will likely exceed the regular rate limit of 3,600 requests per hour.

    Note: Since our batch APIs process requests in the background, there may be a delay between the time you submit your request and the time your data appears in the user interface.

    HTTP Endpoint

    POST /v3/:account_id/shopper_activity/cart/batch

    Arguments

    Key Description
    carts Required. An Array with between 1 and 1000 objects containing cart activity.

    Create or update a batch of orders (Legacy)

    To create or update a batch of orders:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/orders/batches" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "batches": [{
          "orders": [
            {
              "email": "[email protected]",
              "provider": "shopify",
              "upstream_id": "abcdef",
              "identifier": "Order_123456",
              "amount": 4900,
              "tax": 100,
              "fees": 0,
              "discount": 0,
              "permalink": "http://myorders.com/orders/123456",
              "currency_code": "USD",
              "properties": {
                "shirt_size": "Medium",
                "color": "red"
              },
              "occurred_at": "2013-06-21T10:31:58Z",
              "closed_at": "2013-06-21T10:35:58Z",
              "cancelled_at": null,
              "financial_state": "paid",
              "fulfillment_state": "fulfilled",
              "billing_address": {
                "name": "Bill Billington",
                "first_name": "Bill",
                "last_name": "Billington",
                "company": "Bills R US",
                "address_1": "123 Bill St.",
                "address_2": "Apt. B",
                "city": "Billtown",
                "state": "CA",
                "zip": "01234",
                "country": "United States",
                "phone": "555-555-5555",
                "email": "[email protected]"
              },
              "shipping_address": {
                "name": "Ship Shippington",
                "first_name": "Ship",
                "last_name": "Shipington",
                "company": "Shipping 4 Less",
                "address_1": "123 Ship St.",
                "address_2": "null",
                "city": "Shipville",
                "state": "CA",
                "zip": "01234",
                "country": "United States",
                "phone": "555-555-5555",
                "email": "[email protected]"
              },
              "items": [{
                "id": "8888888",
                "product_id": "765432",
                "sku": "4444",
                "amount": 4900,
                "name": "Canoe",
                "quantity": 1,
                "upstream_id": "hijkl",
                "upstream_product_id": "opqrs",
                "upstream_product_variant_id": "zyxwv",
                "price": 4900,
                "tax": 100,
                "fees": 0,
                "discount": 100,
                "taxable": true,
                "properties": {
                  "color": "black"
                }
              }]
            },
            {
              "email": "[email protected]",
              "provider": "shopify",
              "upstream_id": "fedcba",
              "identifier": "Order_654321",
              "amount": 4900,
              "tax": 100,
              "fees": 0,
              "discount": 0,
              "permalink": "http://myorders.com/orders/654321",
              "currency_code": "USD",
              "properties": {
                "size": "small",
                "color": "blue"
              },
              "occurred_at": "2013-05-18T10:31:58Z",
              "closed_at": "2013-05-18T10:35:58Z",
              "cancelled_at": null,
              "financial_state": "paid",
              "fulfillment_state": "fulfilled",
              "billing_address": {
                "name": "Bill Billington",
                "first_name": "Bill",
                "last_name": "Billington",
                "company": "Bills R US",
                "address_1": "123 Bill St.",
                "address_2": "Apt. B",
                "city": "Billtown",
                "state": "CA",
                "zip": "01234",
                "country": "United States",
                "phone": "555-555-5555",
                "email": "[email protected]"
              },
              "shipping_address": {
                "name": "Ship Shippington",
                "first_name": "Ship",
                "last_name": "Shipington",
                "company": "Shipping 4 Less",
                "address_1": "123 Ship St.",
                "address_2": "null",
                "city": "Shipville",
                "state": "CA",
                "zip": "01234",
                "country": "United States",
                "phone": "555-555-5555",
                "email": "[email protected]"
              },
              "items": [{
                "id": "8888888",
                "product_id": "765432",
                "sku": "4444",
                "amount": 4900,
                "name": "Canoe",
                "quantity": 1,
                "upstream_id": "hijkl",
                "upstream_product_id": "opqrs",
                "upstream_product_variant_id": "zyxwv",
                "price": 4900,
                "tax": 100,
                "fees": 0,
                "discount": 100,
                "taxable": true,
                "properties": {
                  "color": "black"
                }
              }]
            }
          ]
        }]
      }
    EOF
    

    Responds with a 202 Accepted response and an empty JSON response:

    {}
    
    We’ve released a new and improved batch endpoint for Orders functionality! Check it out here.

    Note that the legacy Orders endpoint will continue to function. We will give fair notice before we retire it in the future.

    We recommend using this API endpoint when you need to create a collection of orders and subscribers at once that will likely exceed the regular rate limit of 3,600 requests per hour.

    Note: Since our batch APIs process requests in the background, there may be a delay between the time you submit your request and the time your data appears in the user interface.

    HTTP Endpoint

    POST /v2/:account_id/orders/batches

    Arguments

    Key Description
    orders Required. An Array with between 1 and 1000 objects containing order data.

    Create or update a batch of orders

    To create or update a batch of orders:

    curl -X POST "https://api.getdrip.com/v3/YOUR_ACCOUNT_ID/shopper_activity/order/batch" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "orders": [
          {
            "provider": "my_custom_platform",
            "email": "[email protected]",
            "action": "placed",
            "occurred_at": "2019-03-12T15:31:58Z",
            "order_id": "63754763",
            "order_public_id": "#4",
            "grand_total": 54.00,
            "total_discounts": 1.00,
            "total_taxes": 1.00,
            "total_fees": 0,
            "total_shipping": 5.00,
            "currency": "USD",
            "order_url": "http://myorders.com/orders/4",
            "items": [{
              "product_id": "B01F9AQ99M",
              "product_variant_id": "B01F9AQ99M-YEL-BT",
              "sku": "JDT-4321",
              "name": "Yellow Boots of Might",
              "brand": "Drip",
              "categories": [
                "Of Might",
                "Outdoors"
              ],
              "price": 49.00,
              "quantity": 1,
              "discounts": 1.00,
              "taxes": 1.00,
              "fees": 0,
              "shipping": 5.00,
              "total": 54.00,
              "color": "black",
              "product_url": "https://mysuperstore.com/dp/B01F9AQ99M",
              "image_url": "https://www.getdrip.com/images/example_products/boots.png"
            }],
            "billing_address": {
              "label": "Primary Billing",
              "first_name": "Bill",
              "last_name": "Billington",
              "company": "Bills R US",
              "address_1": "123 Bill St.",
              "address_2": "Apt. B",
              "city": "Billtown",
              "state": "CA",
              "postal_code": "01234",
              "country": "United States",
              "phone": "555-555-5555"
            },
            "shipping_address": {
              "label": "Downtown Office",
              "first_name": "Ship",
              "last_name": "Shipington",
              "company": "Shipping 4 Less",
              "address_1": "123 Ship St.",
              "address_2": "null",
              "city": "Shipville",
              "state": "CA",
              "postal_code": "01234",
              "country": "United States",
              "phone": "555-555-5555"
            }
          },
          {
            "provider": "my_custom_platform",
            "email": "[email protected]",
            "action": "updated",
            "occurred_at": "2019-03-12T15:27:16Z",
            "order_id": "456445746",
            "order_public_id": "#5",
            "grand_total": 21.48,
            "total_discounts": 5.34,
            "total_taxes": 1.00,
            "total_fees": 2.00,
            "total_shipping": 5.00,
            "currency": "USD",
            "order_url": "https://mysuperstore.com/order/5",
            "items": [
              {
                "product_id": "B01J4SWO1G",
                "product_variant_id": "B01J4SWO1G-CW-BOTT",
                "sku": "XHB-1234",
                "name": "The Coolest Water Bottle",
                "brand": "Drip",
                "categories": [
                  "Accessories"
                ],
                "price": 11.16,
                "sale_price": 10.16,
                "quantity": 2,
                "discounts": 5.34,
                "taxes": 1.00,
                "fees": 0.50,
                "shipping": 5.00,
                "total": 21.48,
                "product_url": "https://mysuperstore.com/dp/B01J4SWO1G",
                "image_url": "https://www.getdrip.com/images/example_products/water_bottle.png",
                "product_tag": "Best Seller"
              }
            ],
            "billing_address": {
              "label": "Primary Billing",
              "first_name": "Bill",
              "last_name": "Billington",
              "company": "Bills R US",
              "address_1": "123 Bill St.",
              "address_2": "Apt. B",
              "city": "Billtown",
              "state": "CA",
              "postal_code": "01234",
              "country": "United States",
              "phone": "555-555-5555"
            },
            "shipping_address": {
              "label": "Downtown Office",
              "first_name": "Ship",
              "last_name": "Shipington",
              "company": "Shipping 4 Less",
              "address_1": "123 Ship St.",
              "city": "Shipville",
              "state": "CA",
              "postal_code": "01234",
              "country": "United States",
              "phone": "555-555-5555"
            }
          }
        ]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.create_order_activity_events(
      [
        {
          provider: "my_custom_platform",
          email: "[email protected]",
          action: "placed",
          occurred_at: "2019-03-12T15:31:58Z",
          order_id: "63754763",
          order_public_id: "#4",
          grand_total: 54.00,
          total_discounts: 1.00,
          total_taxes: 1.00,
          total_fees: 0,
          total_shipping: 5.00,
          currency: "USD",
          order_url: "http://myorders.com/orders/4",
          items: [{
            product_id: "B01F9AQ99M",
            product_variant_id: "B01F9AQ99M-YEL-BT",
            sku: "JDT-4321",
            name: "Yellow Boots of Might",
            brand: "Drip",
            categories: [
              "Of Might",
              "Outdoors"
            ],
            price: 49.00,
            quantity: 1,
            discounts: 1.00,
            taxes: 1.00,
            fees: 0,
            shipping: 5.00,
            total: 54.00,
            color: "black",
            product_url: "https://mysuperstore.com/dp/B01F9AQ99M",
            image_url: "https://www.getdrip.com/images/example_products/boots.png"
          }],
          billing_address: {
            label: "Primary Billing",
            first_name: "Bill",
            last_name: "Billington",
            company: "Bills R US",
            address_1: "123 Bill St.",
            address_2: "Apt. B",
            city: "Billtown",
            state: "CA",
            postal_code: "01234",
            country: "United States",
            phone: "555-555-5555"
          },
          shipping_address: {
            label: "Downtown Office",
            first_name: "Ship",
            last_name: "Shipington",
            company: "Shipping 4 Less",
            address_1: "123 Ship St.",
            address_2: "null",
            city: "Shipville",
            state: "CA",
            postal_code: "01234",
            country: "United States",
            phone: "555-555-5555"
          }
        },
        {
          provider: "my_custom_platform",
          email: "[email protected]",
          action: "updated",
          occurred_at: "2019-03-12T15:27:16Z",
          order_id: "456445746",
          order_public_id: "#5",
          grand_total: 21.48,
          total_discounts: 5.34,
          total_taxes: 1.00,
          total_fees: 2.00,
          total_shipping: 5.00,
          currency: "USD",
          order_url: "https://mysuperstore.com/order/5",
          items: [
            {
              product_id: "B01J4SWO1G",
              product_variant_id: "B01J4SWO1G-CW-BOTT",
              sku: "XHB-1234",
              name: "The Coolest Water Bottle",
              brand: "Drip",
              categories: [
                "Accessories"
              ],
              price: 11.16,
              sale_price: 10.16,
              quantity: 2,
              discounts: 5.34,
              taxes: 1.00,
              fees: 0.50,
              shipping: 5.00,
              total: 21.48,
              product_url: "https://mysuperstore.com/dp/B01J4SWO1G",
              image_url: "https://www.getdrip.com/images/example_products/water_bottle.png",
              product_tag: "Best Seller"
            }
          ],
          billing_address: {
            label: "Primary Billing",
            first_name: "Bill",
            last_name: "Billington",
            company: "Bills R US",
            address_1: "123 Bill St.",
            address_2: "Apt. B",
            city: "Billtown",
            state: "CA",
            postal_code: "01234",
            country: "United States",
            phone: "555-555-5555"
          },
          shipping_address: {
            label: "Downtown Office",
            first_name: "Ship",
            last_name: "Shipington",
            company: "Shipping 4 Less",
            address_1: "123 Ship St.",
            city: "Shipville",
            state: "CA",
            postal_code: "01234",
            country: "United States",
            phone: "555-555-5555"
          }
        }
      ]
    )
    
    if response.success?
      puts "Request accepted"
    else
      puts "Error occurred"
    end
    

    Responds with a 202 Accepted if successful. That means the server accepted the request and queued it for processing. The response includes a list of unique request_ids that can be used to check the status of the request later on:

    {
      "request_ids": [
        "db8a7b16-32dd-4863-8b6e-818e3eaab99a",
        "002048e9-3692-4f0a-8bbf-80a077acf642"
      ]
    }
    

    We recommend using this API endpoint when you need to import a collection of orders that will likely exceed the regular rate limit of 3,600 requests per hour.

    Note: Since our batch APIs process requests in the background, there may be a delay between the time you submit your request and the time your data appears in the user interface.

    HTTP Endpoint

    POST /v3/:account_id/shopper_activity/order/batch

    Arguments

    Key Description
    orders Required. An Array with between 1 and 1000 objects containing order activity.

    Create or update a batch of products

    To create or update a batch of products:

    curl -X POST "https://api.getdrip.com/v3/YOUR_ACCOUNT_ID/shopper_activity/product/batch" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "products": [
          {
            "provider": "my_custom_platform",
            "action": "created",
            "occurred_at": "2019-01-28T12:15:23Z",
            "product_id": "B01J4SWO1G",
            "product_variant_id": "B01J4SWO1G-CW-BOTT",
            "sku": "XHB-1234",
            "name": "The Coolest Water Bottle",
            "brand": "Drip",
            "categories": [
              "Accessories"
            ],
            "price": 11.16,
            "inventory": 42,
            "product_url": "https://mysuperstore.com/dp/B01J4SWO1G",
            "image_url": "https://www.getdrip.com/images/example_products/water_bottle.png"
          },
          {
            "provider": "my_custom_platform",
            "action": "created",
            "occurred_at": "2019-01-28T12:15:23Z",
            "product_id": "B01J4SWO1G2",
            "product_variant_id": "B01J4SWO1G-CW-BOTT2",
            "sku": "XHB-1235",
            "name": "The Coolest Water Bottle",
            "brand": "Drip",
            "categories": [
              "Accessories"
            ],
            "price": 11.16,
            "inventory": 42,
            "product_url": "https://mysuperstore.com/dp/B01J4SWO1G2",
            "image_url": "https://www.getdrip.com/images/example_products/water_bottle.png"
          },
          {
            "provider": "my_custom_platform",
            "action": "created",
            "occurred_at": "2019-01-28T12:15:23Z",
            "product_id": "B01J4SWO1G3",
            "product_variant_id": "B01J4SWO1G-CW-BOTT3",
            "sku": "XHB-1236",
            "name": "The Coolest Water Bottle",
            "brand": "Drip",
            "categories": [
              "Accessories"
            ],
            "price": 11.16,
            "inventory": 42,
            "product_url": "https://mysuperstore.com/dp/B01J4SWO1G3",
            "image_url": "https://www.getdrip.com/images/example_products/water_bottle.png"
          }
        ]
      }
    EOF
    

    Responds with a 202 Accepted if successful. That means the server accepted the request and queued it for processing. The response includes a list of unique request_ids that can be used to check the status of the request later on:

    {
      "request_ids": [
        "db8a7b16-32dd-4863-8b6e-818e3eaab99a",
        "002048e9-3692-4f0a-8bbf-80a077acf642"
      ]
    }
    

    We recommend using this API endpoint when you need to import a collection of products that will likely exceed the regular rate limit of 3,600 requests per hour.

    Note: Since our batch APIs process requests in the background, there may be a delay between the time you submit your request and the time your data appears in the user interface.

    HTTP Endpoint

    POST /v3/:account_id/shopper_activity/product/batch

    Arguments

    Key Description
    products Required. An Array with between 1 and 1000 products containing product activity.

    Pagination

    An example meta payload:

    {
      "page": 1,
      "count": 100,
      "total_pages": 3,
      "total_count": 300
    }
    

    Some endpoints that return collections are paginated. For these endpoints, the meta object will tell you the current page, count, total number of pages, and total count of the collection.

    By default, the API will return the first page of results. Each page contains a maximum of 100 items, unless otherwise noted below. To fetch a particular page, use the page query parameter.

    Errors

    If you are authenticated but attempt to access a resource for which you do not have sufficient permissions, you will receive a 403 Forbidden response.

    {
      "errors": [{
        "code": "authorization_error",
        "message": "You are not authorized to access this resource"
      }]
    }
    

    If the resource is not found, you will receive a 404 Not Found response.

    {
      "errors": [{
        "code": "not_found_error",
        "message": "The resource you requested was not found"
      }]
    }
    

    Drip responds to invalid requests in a number of different ways. Exceptions to these rules will be noted for any applicable endpoints. Assume authentication is required on all endpoints unless otherwise noted.

    If you attempt to anonymously access a resource that requires authentication, you will receive a 401 Unauthorized response.

    Validation Errors

    An example response:

    {
      "errors": [
        {
          "code": "presence_error",
          "attribute": "email",
          "message": "Email is required"
        },
        {
          "code": "length_error",
          "attribute": "name",
          "message": "Name must be between 2 and 20 characters"
        }
      ]
    }
    

    If validation errors occur while attempting to create or update a resource, you will receive a 422 Unprocessable Entity response with an errors object detailing which attributes are invalid. One of the following codes will assigned to each error object:

    Code Description
    presence_error The attribute is required.
    length_error The length of the attribute is out of bounds.
    uniqueness_error The attribute must be unique.
    email_error The attribute must be a valid email address.
    sms_error The attribute must be a valid US mobile number with E.164 formatting. E.g. "+16125551212".
    url_error The attribute must be a valid URL.
    domain_error The attribute must be a valid domain name.
    time_error The attribute must be a valid time in ISO-8601 format.
    email_address_list_error The attribute must be a valid comma-separated list of email addresses.
    days_of_the_week_error The attribute must be a valid days of the week mask of the format
    /\A(0|1){7}\z/ (excluding 0000000).
    unavailable_error A resource has been disabled or deleted.
    format_error A resource identifier or object is not formatted correctly.
    range_error A numeric value is out of range.

    Transition Errors

    An example response:

    {
      "errors": [
        {
          "code": "no_postal_address_error"
        }
      ]
    }
    

    State transition endpoints will respond with a 403 Forbidden and an errors object if the transition is not allowed.

    Accounts

    Accounts are represented as follows:

    {
      "id": "9999999",
      "name": "Acme, Inc.",
      "url": "www.acme.com",
      "default_from_name": "John Doe",
      "default_from_email": "[email protected]",
      "default_postal_address": "123 Anywhere St\nFresno, CA 99999",
      "primary_email": "[email protected]",
      "enable_third_party_cookies": false,
      "phone_number": "999-999-9999",
      "created_at": "2013-06-21T10:31:58Z",
      "href": "https://api.getdrip.com/v2/accounts/9999999"
    }
    

    All responses containing account data also include the following top-level link data:

    {
      "links": {
        "accounts.broadcasts": "https://api.getdrip.com/v2/{accounts.id}/broadcasts",
        "accounts.campaigns": "https://api.getdrip.com/v2/{accounts.id}/campaigns",
        "accounts.goals": "https://api.getdrip.com/v2/{accounts.id}/goals"
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each subscriber record.
    name The name assigned to each account. Defaults to the account's website URL.
    url The account's website URL.
    default_from_name A default "from name" that appears in your sent emails and can be changed on a per email basis.
    default_from_email A default "from email" that appears in your sent emails and can be changed on a per email basis.
    default_postal_address As required by the CAN-SPAM Act, this is a default postal address used for all sent emails and can be changed on a per email basis.
    primary_email The account owner's email address.
    enable_third_party_cookies When enabled allows tracking visitors across multiple domains (e.g. you use a shopping cart system hosted on a different site).
    phone_number The account's primary contact number.
    created_at A read-only Drip generated timestamp for when the account was first created.
    href The url designated for retrieving the account record via the REST API.
    default_email_address_id A read-only id of the account's default From address in sending_addresses. Returns null if the account has no default From address or its default address has been deleted; default_from_email still shows the address emails are sent from when they have no From address of their own. Only returned when fetching an account.
    sending_addresses A read-only list of the account's email addresses, including unverified ones. Only returned when fetching an account. Refer to Sending addresses for an overview of the properties returned here.
    links An object containing URLs for campaign and conversion resources. Note, conversions are represented as "Goals".

    List all accounts

    To list all accounts the authenticated user has access to:

    curl "https://api.getdrip.com/v2/accounts" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.accounts
    
    if response.success?
      puts response.body["accounts"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    
    client.listAccounts()
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The accounts property is an array of account objects.
    {
      "links": { ... },
      "accounts": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/accounts

    Arguments

    None.

    Fetch an account

    To fetch a specific account:

    curl "https://api.getdrip.com/v2/accounts/ACCOUNT_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    account_id = 9999999
    response = client.account(account_id)
    
    if response.success?
      puts response.body
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    
    client.fetchAccount(accountId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The accounts property is an array of one account object,
    # which also includes the account's sending addresses.
    {
      "links": { ... },
      "accounts": [{
        "id": "9999999",
        "name": "Acme, Inc.",
        ...
        "default_email_address_id": "1234567",
        "sending_addresses": [
          {
            "id": "1234569",
            "email": "[email protected]",
            "is_default": false,
            "verified": true,
            "auto_generated": false
          },
          {
            "id": "1234568",
            "email": "[email protected]",
            "is_default": false,
            "verified": true,
            "auto_generated": false
          },
          {
            "id": "1234567",
            "email": "[email protected]",
            "is_default": true,
            "verified": true,
            "auto_generated": false
          }
        ]
      }]
    }
    

    Sending addresses

    Fetching a single account also returns the account's email addresses, newest first. Only those with verified: true can be used as a From address. Deleted addresses are not included. Listing accounts does not return them.

    Property Description
    id A read-only Drip generated id used to identify the address.
    email The email address.
    is_default Returns true for the account's default From address, which emails without their own From address are sent from.
    verified Returns true if Drip can send from this address: it is on a sending domain you have authenticated in Drip, or it is an address Drip generated for the account. Unverified addresses are listed, but cannot be used as a From address until their domain is authenticated.
    auto_generated Returns true for the no-reply address Drip creates for new accounts.

    HTTP Endpoint

    GET /v2/accounts/:account_id

    Arguments

    None.

    Single-Email Campaigns
    (aka Broadcasts)

    Single-Email Campaigns (Broadcasts) are one-time emails sent to a segment of your subscribers. The API allows you to list, fetch, create, update, and delete Single-Email Campaigns, send test emails, set and read a campaign's audience, and schedule or unschedule it.

    A Single-Email Campaign's status cannot be set directly. It changes as the campaign moves through its lifecycle: scheduling moves a draft to scheduled, and unscheduling moves it back. Possible statuses are:

    Status Description
    draft Not yet scheduled. Drafts are the only Single-Email Campaigns that can be edited via the API.
    scheduled Scheduled for a future send. Read-only.
    sending Currently being sent. Read-only and cannot be deleted.
    sent Completed. Read-only.
    canceled Canceled before sending. Read-only.
    deleted Deleted. Hidden from default listings.

    send_at and localize_sending_time are read-only on this resource. Set them with Schedule a Single-Email Campaign, and set who receives it with Set the audience.

    Single-Email Campaigns are represented as follows:

    {
      "id": "123456",
      "status": "sent",
      "name": "4 Marketing Automation Trends for 2015",
      "from_name": "John Doe",
      "from_email": "[email protected]",
      "from_email_address_id": "1234567",
      "reply_to": "[email protected]",
      "reply_to_email_address_id": "1234569",
      "postal_address": "123 Anywhere St\nFresno, CA 99999",
      "localize_sending_time": true,
      "send_at": "2015-07-01T10:00:00Z",
      "bcc": null,
      "created_at": "2015-06-21T10:31:58Z",
      "href": "https://api.getdrip.com/v2/9999999/broadcast/123456",
      "preview_url": "https://www.getdrip.com/broadcasts/123456/2d83a64861f23b1c35a3b8d6ee3b54f7",
      "subject": "4 Marketing Automation Trends for 2015",
      "html_body": "HTML body",
      "text_body": "Text body",
      "links": {
        "account": "9999999"
      }
    }
    

    All responses containing Single-Email Campaign data also include the following top-level link data:

    {
      "links": {
        "broadcasts.account": "https://api.getdrip.com/v2/accounts/{broadcasts.account}",
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each Single-Email Campaign record.
    status Returns whether the Single-Email Campaign is draft, canceled, scheduled, sent or sending.
    name The private name given to the Single-Email Campaign.
    from_name A "from name" that appears in your sent emails and can be changed on a per email basis. This setting overrides the account's default from name.
    from_email The address the Single-Email Campaign is sent from: its own From address, or the account's default From address if it has none. Read-only; set it with from_email_address_id.
    from_email_address_id The id of the address in from_email, matching an id in the account's sending addresses. Returns null if neither the campaign nor the account has a From address, or if the address has been deleted; from_email still shows it. See Sender.
    reply_to The Reply-To address, or null when replies go to the From address. Read-only; set it with reply_to_email_address_id.
    reply_to_email_address_id The id of the address in reply_to, matching an id in the account's sending addresses, or null. It is also null if the Reply-To address has been deleted; reply_to still shows it. See Sender.
    postal_address As required by the CAN-SPAM Act, this is a postal address used for all sent emails and can be changed on a per email basis.
    localize_sending_time The scheduled send_at time if set to be sent in the subscriber's time zone.
    send_at The timestamp representing when the Single-Email Campaign will be delivered.
    bcc A list of emails designated to receive a blind copy of the Single-Email Campaign. Read-only.
    created_at A read-only Drip generated timestamp for when the Single-Email Campaign was first created.
    href The url designated for retrieving the account record via the REST API.
    preview_url A read-only public URL for previewing the email content. Does not require authentication. Returns null for deleted Single-Email Campaigns.
    subject The Single-Email Campaign's subject.
    html_body The HTML content used in the email's body.
    text_body The plain text content used in the email's body.
    derived Read-only text generated when the campaign is read. derived.audience describes who it goes to in plain English, such as People who are in the "VIP customers" segment, or All people. It is display text: do not parse it, and expect its wording to change.
    links An object containing the account's REST API URL.

    Email Content

    The content object structure:

    {
      "content": {
        "html": {
          "type": "document",
          "value": "<html><body><h1>Hello!</h1></body></html>"
        },
        "text": {
          "type": "document",
          "value": "Hello!\n\nWelcome to our newsletter."
        }
      }
    }
    

    Email content is provided via a content object containing content type keys. Each key maps to an object with a type (the content variant) and a value (the content itself).

    Key Description
    html Required when creating. The HTML email content. Currently the only supported type is document: a full HTML document with a complete <html> structure. Supports Liquid templating.
    text Optional. The plain text version of the email. Currently the only supported type is document: a full plain text document. Supports Liquid templating. If omitted, the plain text version is generated automatically from the HTML.

    HTML content is validated and sanitized for security: JavaScript is not allowed, and dangerous CSS patterns are blocked.

    The HTML must also include two Liquid tags, as the CAN-SPAM Act requires:

    • an unsubscribe link: {{ unsubscribe_url }} or {{ unsubscribe_link }}
    • a postal address: {{ postal_address }}, {{ inline_postal_address }} or {{ html_postal_address }}

    Both usually go in the footer. The check is on the HTML itself, so setting the postal_address field does not satisfy it on its own. Without them, creating or updating the campaign responds with a 422 Unprocessable Entity:

    {
      "errors": [{
        "code": "can_spam_compliance",
        "attribute": "content.html",
        "message": "Content HTML must include {{ postal_address }} or {{ inline_postal_address }} or {{ html_postal_address }}"
      }]
    }
    

    Sender

    To change who a draft Single-Email Campaign is from and where replies go:

    curl -X PATCH "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "broadcasts": [{
          "from_name": "Acme Support",
          "from_email_address_id": "1234568",
          "reply_to_email_address_id": "1234569"
        }]
      }
    EOF
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID")
    
    request = Net::HTTP::Patch.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    request["Content-Type"] = "application/json"
    request.body = {
      broadcasts: [{
        from_name: "Acme Support",
        from_email_address_id: "1234568",
        reply_to_email_address_id: "1234569"
      }]
    }.to_json
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID",
      {
        method: "PATCH",
        headers: {
          "Content-Type": "application/json",
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        },
        body: JSON.stringify({
          broadcasts: [{
            from_name: "Acme Support",
            from_email_address_id: "1234568",
            reply_to_email_address_id: "1234569"
          }]
        })
      }
    );
    
    const body = await response.json();
    

    If an address id cannot be used, responds with a 422 Unprocessable Entity and changes nothing:

    {
      "errors": [{
        "code": "validation_error",
        "attribute": "from_email_address_id",
        "message": "[email protected] is not verified: use the id of an address in the account's sending_addresses that has verified: true."
      }]
    }
    

    A Single-Email Campaign's From name, From address and Reply-To address can be set when you create it, and changed while it is a draft with Update a Single-Email Campaign.

    • from_name is free text, up to 255 characters. It cannot be blank, and supports Liquid templating.
    • The From and Reply-To addresses are chosen by id, never typed in. Use an id from the account's sending addresses, returned by Fetch an account.
    • from_email_address_id must be an address with verified: true.
    • reply_to_email_address_id must be an address with verified: true and auto_generated: false.
    • On update, send null or "" to clear either one. A cleared From address sends from the account's default From address, and a cleared Reply-To sends replies to the From address.

    Any other id, such as an unverified or deleted address, or one that belongs to another account, responds with a 422 Unprocessable Entity and changes nothing.

    from_email, reply_to and bcc are read-only: they are returned in responses. Set the sender with the address ids above.

    A sender set here appears in the Drip app, the same as one chosen there.

    List all Single-Email Campaigns

    To list Single-Email Campaigns in an account:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.broadcasts
    
    if response.success?
      puts response.body["broadcasts"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const options = { status: "sent" };
    
    client.listBroadcasts(options)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The broadcasts property is an array of broadcast objects.
    {
      "links": { ... },
      "meta": {
        "page": 1,
        "sort": "created_at",
        "direction": "asc",
        "count": 5,
        "total_pages": 1,
        "total_count": 5,
        "status": "all"
      },
      "broadcasts": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/broadcasts

    Arguments

    Key Description
    page Optional. The page number (1-indexed). Defaults to 1.
    per_page Optional. The number of results per page, up to a maximum of 100. Defaults to 100.
    status Optional. Filter by one of the following statuses: draft, scheduled, sending, sent, canceled, deleted, or all. By default, deleted Single-Email Campaigns are excluded; use status=deleted or status=all to include them.
    sort Optional. Sort results by one of these fields: created_at, updated_at, send_at, or name. Defaults to created_at.
    direction Optional. Filter sort direction with: asc or desc. Defaults to asc.

    Create a Single-Email Campaign

    To create a Single-Email Campaign:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "broadcasts": [{
          "name": "December Newsletter",
          "subject": "Your December Newsletter is here!",
          "preheader": "See what's new this month...",
          "content": {
            "html": {
              "type": "document",
              "value": "<html><body><h1>Hello!</h1></body></html>"
            },
            "text": {
              "type": "document",
              "value": "Hello! Welcome to our newsletter."
            }
          },
          "postal_address": "123 Main St, Minneapolis, MN 55401"
        }]
      }
    EOF
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts")
    
    request = Net::HTTP::Post.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    request["Content-Type"] = "application/json"
    request.body = {
      broadcasts: [{
        name: "December Newsletter",
        subject: "Your December Newsletter is here!",
        preheader: "See what's new this month...",
        content: {
          html: {
            type: "document",
            value: "<html><body><h1>Hello!</h1></body></html>"
          },
          text: {
            type: "document",
            value: "Hello! Welcome to our newsletter."
          }
        },
        postal_address: "123 Main St, Minneapolis, MN 55401"
      }]
    }.to_json
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        },
        body: JSON.stringify({
          broadcasts: [{
            name: "December Newsletter",
            subject: "Your December Newsletter is here!",
            preheader: "See what's new this month...",
            content: {
              html: {
                type: "document",
                value: "<html><body><h1>Hello!</h1></body></html>"
              },
              text: {
                type: "document",
                value: "Hello! Welcome to our newsletter."
              }
            },
            postal_address: "123 Main St, Minneapolis, MN 55401"
          }]
        })
      }
    );
    
    const body = await response.json();
    

    Responds with a 201 Created and the new Single-Email Campaign if successful. The Location header contains the URL of the created record:

    {
      "links": { ... },
      "broadcasts": [{ ... }]
    }
    

    If the request is invalid, responds with a 422 Unprocessable Entity:

    {
      "errors": [{
        "code": "validation_error",
        "attribute": "subject",
        "message": "Subject is required"
      }]
    }
    

    Single-Email Campaigns created via the API start in the draft status, with an audience of everyone eligible to receive them. Set the audience to narrow it, then schedule it.

    HTTP Endpoint

    POST /v2/:account_id/broadcasts

    Arguments

    Key Description
    name Required. The private name given to the Single-Email Campaign (255 characters maximum).
    subject Required. The email subject line. Supports Liquid templating.
    content Required. An Email Content object. At minimum, include an html key. Optionally include a text key for the plain text version; if omitted, the plain text version is generated from the HTML.
    preheader Optional. Preview text shown in email clients before the email is opened. Supports Liquid templating.
    postal_address Optional. A physical mailing address for CAN-SPAM compliance. Defaults to the account's postal address.
    from_name Optional. The name the email is sent from (255 characters maximum). Supports Liquid templating. Defaults to the account's default From name.
    from_email_address_id Optional. The id of a verified address in the account's sending addresses to send from. Defaults to the account's default From address. See Sender.
    reply_to_email_address_id Optional. The id of a verified, non-auto-generated address in the account's sending addresses to receive replies. If omitted, replies go to the From address. See Sender.

    Fetch a Single-Email Campaign

    To fetch a specific Single-Email Campaign:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    broadcast_id = "BROADCAST_ID"
    response = client.broadcast(broadcast_id)
    
    if response.success?
      puts response.body
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const broadcastId = "BROADCAST_ID";
    
    client.fetchBroadcast(broadcastId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The broadcasts property is an array of one broadcast object.
    {
      "links": { ... },
      "broadcasts": [{ ... }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/broadcasts/:broadcast_id

    Arguments

    None.

    Update a Single-Email Campaign

    To update a Single-Email Campaign:

    curl -X PATCH "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "broadcasts": [{
          "subject": "Updated: December Newsletter!",
          "preheader": "New content inside...",
          "content": {
            "html": {
              "type": "document",
              "value": "<html><body><h1>Updated content!</h1></body></html>"
            }
          }
        }]
      }
    EOF
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID")
    
    request = Net::HTTP::Patch.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    request["Content-Type"] = "application/json"
    request.body = {
      broadcasts: [{
        subject: "Updated: December Newsletter!",
        preheader: "New content inside...",
        content: {
          html: {
            type: "document",
            value: "<html><body><h1>Updated content!</h1></body></html>"
          }
        }
      }]
    }.to_json
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID",
      {
        method: "PATCH",
        headers: {
          "Content-Type": "application/json",
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        },
        body: JSON.stringify({
          broadcasts: [{
            subject: "Updated: December Newsletter!",
            preheader: "New content inside...",
            content: {
              html: {
                type: "document",
                value: "<html><body><h1>Updated content!</h1></body></html>"
              }
            }
          }]
        })
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK and the updated Single-Email Campaign if successful:

    {
      "links": { ... },
      "broadcasts": [{ ... }]
    }
    

    If the Single-Email Campaign is not a draft, responds with a 409 Conflict:

    {
      "errors": [{
        "code": "conflict_error",
        "message": "Cannot update a broadcast with status 'sent'"
      }]
    }
    

    Only Single-Email Campaigns in the draft status can be updated via the API; all other statuses are read-only. Updates are partial: only the fields you include are changed. To change the From name, From address or Reply-To address, see Sender.

    Status, scheduling, and the audience are not updated here. Each has its own endpoint: Set the audience, Schedule, and Unschedule.

    HTTP Endpoint

    PATCH /v2/:account_id/broadcasts/:broadcast_id

    Arguments

    Key Description
    name Optional. The private name given to the Single-Email Campaign.
    subject Optional. The email subject line. Supports Liquid templating.
    content Optional. An Email Content object with html and/or text keys.
    preheader Optional. Preview text shown in email clients before the email is opened. Supports Liquid templating.
    postal_address Optional. A physical mailing address for CAN-SPAM compliance.
    from_name Optional. The name the email is sent from (255 characters maximum). Supports Liquid templating.
    from_email_address_id Optional. The id of a verified address in the account's sending addresses to send from. Send null or "" to use the account's default From address. See Sender.
    reply_to_email_address_id Optional. The id of a verified, non-auto-generated address in the account's sending addresses to receive replies. Send null or "" to have replies go to the From address. See Sender.

    Delete a Single-Email Campaign

    To delete a Single-Email Campaign:

    curl -X DELETE "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID")
    
    request = Net::HTTP::Delete.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID",
      {
        method: "DELETE",
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK and the Single-Email Campaign in the deleted status:

    {
      "links": { ... },
      "broadcasts": [{ ... }]
    }
    

    If the Single-Email Campaign is currently sending, responds with a 409 Conflict:

    {
      "errors": [{
        "code": "conflict_error",
        "message": "Cannot delete a broadcast that is currently sending"
      }]
    }
    

    Deleting is a soft delete: the Single-Email Campaign transitions to the deleted status and is hidden from default listings, but historical data is preserved. Single-Email Campaigns in the sending status cannot be deleted.

    HTTP Endpoint

    DELETE /v2/:account_id/broadcasts/:broadcast_id

    Arguments

    None.

    Send a test email

    To send a test email for a Single-Email Campaign:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/send_test" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "to_emails": ["[email protected]"],
        "preview_as": "[email protected]"
      }
    EOF
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/send_test")
    
    request = Net::HTTP::Post.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    request["Content-Type"] = "application/json"
    request.body = {
      to_emails: ["[email protected]"],
      preview_as: "[email protected]"
    }.to_json
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.code
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/send_test",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        },
        body: JSON.stringify({
          to_emails: ["[email protected]"],
          preview_as: "[email protected]"
        })
      }
    );
    
    // 204 No Content on success
    

    Responds with a 204 No Content if successful.

    If a recipient is not allowed, responds with a 422 Unprocessable Entity:

    {
      "errors": [{
        "code": "validation_error",
        "attribute": "to_emails",
        "message": "[email protected] is not a verified domain or active account member"
      }]
    }
    

    If a rate limit is exceeded, responds with a 429 Too Many Requests and a Retry-After header indicating when the limit resets:

    {
      "errors": [{
        "code": "rate_limit_error",
        "message": "Hourly test email limit exceeded. Maximum 20 requests per hour."
      }]
    }
    

    Sends a test email so you can preview how the Single-Email Campaign will appear to recipients. Test emails are marked with a "[TEST]" prefix in the from name, and any links that would trigger automations are stripped for safety. If sending is blocked on the account (for example, during a trial), tests are only delivered to the authenticated user.

    Recipient validation

    Each recipient email address must satisfy one of the following requirements:

    1. Verified domain: the email's domain is a verified sending domain in the account (e.g., if example.com is verified, [email protected] is allowed).
    2. Active account member: the email belongs to an active member of the account.

    Recipients that do not meet either requirement are rejected with a 422 validation error.

    Rate limits

    Rate limits are applied per user.

    Limit Window
    5 recipients Per request
    20 requests Per hour
    40 requests Per day

    HTTP Endpoint

    POST /v2/:account_id/broadcasts/:broadcast_id/send_test

    Arguments

    Key Description
    to_emails Required. An array of 1 to 5 email addresses to send the test to. See recipient validation above.
    preview_as Optional. The email address of an existing subscriber to use for Liquid template rendering. The test email is personalized as if sent to this subscriber, using their custom fields and tags. If omitted, Liquid variables use placeholder values.

    Set the audience

    To send a Single-Email Campaign to a saved segment:

    curl -X PUT "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/audience" \
      -H "Content-Type: application/vnd.api+json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d '{
            "filter": [
              [{ "type": "segments", "properties": { "operator": "in", "segment_id": "4815162" } }]
            ]
          }'
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/audience")
    
    request = Net::HTTP::Put.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    request["Content-Type"] = "application/vnd.api+json"
    request.body = {
      filter: [
        [{ type: "segments", properties: { operator: "in", segment_id: "4815162" } }]
      ]
    }.to_json
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/audience",
      {
        method: "PUT",
        headers: {
          "Content-Type": "application/vnd.api+json",
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        },
        body: JSON.stringify({
          filter: [
            [{ type: "segments", properties: { operator: "in", segment_id: "4815162" } }]
          ]
        })
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK and the Single-Email Campaign:

    {
      "links": { ... },
      "broadcasts": [{ ... }]
    }
    

    If a condition names a segment the account cannot use, responds with a 404 Not Found:

    {
      "errors": [{
        "code": "not_found_error",
        "attribute": "/filter/0/0/properties/segment_id",
        "message": "No active segment with id '4815162' was found on this account"
      }]
    }
    

    If the filter is malformed, responds with a 422 Unprocessable Entity, naming every problem at once:

    {
      "errors": [{
        "code": "unknown_operator",
        "attribute": "/filter/0/0/properties/operator",
        "message": "Unknown operator 'within' for condition type 'segments'. Valid operators: in, not_in"
      }]
    }
    

    If the campaign already has an audience and confirm=true was not sent, responds with a 409 Conflict:

    {
      "errors": [{
        "code": "confirmation_required",
        "attribute": "confirm",
        "message": "This broadcast has a filter audience (People who are in the \"VIP customers\" segment) that will be replaced and cannot be recovered. Retry with confirm=true to proceed."
      }]
    }
    

    Replaces who the Single-Email Campaign goes to. Only a draft campaign's audience can be changed; anything else responds with a 409 Conflict.

    A filter is a list of AND-sets, combined with OR. Everything inside one inner list has to be true of a person, and a person matching any inner list is included. So [[A, B], [C]] means "(A and B) or C".

    [[]] means everyone eligible to receive it, and is how you clear an audience. An empty filter, [], is rejected.

    Today the only condition type available is segments, with the operators in and not_in. The segment_id is the id from the Segments API. More condition types will follow.

    segment_id takes one id, never a list: ["4815162"] is rejected. For several segments, use one condition each. Two conditions in the same inner list mean "in both"; two in separate inner lists mean "in either".

    Replacing an audience requires confirm=true whenever the current audience is anything other than everyone, because what is being replaced cannot be recovered through the API. Read the audience first if you need to keep it.

    Every problem with a filter is reported in a single response. Each error's attribute is a JSON Pointer to the condition that caused it, so you can fix a request once rather than once per round trip.

    An audience set here appears in the Drip app as the campaign's recipients, the same as one chosen there.

    HTTP Endpoint

    PUT /v2/:account_id/broadcasts/:broadcast_id/audience

    Arguments

    Argument Description
    filter Required. A list of AND-sets of conditions. Send [[]] for everyone.
    confirm Optional. Set to true to acknowledge that the current audience will be replaced. Required whenever the current audience is anything other than everyone.

    Fetch the audience

    To read a Single-Email Campaign's audience:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/audience" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/audience")
    
    request = Net::HTTP::Get.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/audience",
      {
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK:

    {
      "audience": {
        "filter": [
          [{ "type": "segments", "properties": { "operator": "in", "segment_id": "4815162" } }]
        ]
      }
    }
    

    When the audience uses rules this API cannot yet express:

    {
      "audience": {
        "message": "This filter includes unsupported criteria and cannot be returned as a filter.",
        "summary": "People who are tagged with \"vip\"",
        "unsupported_types": ["tags"]
      }
    }
    

    filter comes back in the same shape it is set in, so reading an audience and writing it straight back changes nothing.

    filter is present only when writing it again would be accepted. Most audiences built in the Drip app use rules that have no form here yet, and those come back described instead: summary is plain-English display text, and unsupported_types names the condition types in the way. Expect that until more condition types are available.

    A present filter is not a promise that its segments still exist. That is not checked on read, so an audience naming a segment deleted since it was set reads back intact and responds with a 404 Not Found when written again.

    HTTP Endpoint

    GET /v2/:account_id/broadcasts/:broadcast_id/audience

    Arguments

    None.

    Schedule a Single-Email Campaign

    To send a Single-Email Campaign at 9:00 in each person's own time zone:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/schedule" \
      -H "Content-Type: application/vnd.api+json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d '{
            "send_at": "2026-11-01T09:00:00Z",
            "localize_sending_time": true
          }'
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/schedule")
    
    request = Net::HTTP::Post.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    request["Content-Type"] = "application/vnd.api+json"
    request.body = {
      send_at: "2026-11-01T09:00:00Z",
      localize_sending_time: true
    }.to_json
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/schedule",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/vnd.api+json",
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        },
        body: JSON.stringify({
          send_at: "2026-11-01T09:00:00Z",
          localize_sending_time: true
        })
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK and the Single-Email Campaign in the scheduled status:

    {
      "links": { ... },
      "broadcasts": [{ ... }]
    }
    

    If the request is malformed, responds with a 422 Unprocessable Entity, naming every problem at once:

    {
      "errors": [{
        "code": "validation_error",
        "attribute": "localize_sending_time",
        "message": "localize_sending_time is required with send_at: false sends at the instant given, true sends at that wall clock in each person's own zone."
      }]
    }
    

    If the campaign cannot be scheduled in its current state, responds with a 409 Conflict:

    {
      "errors": [{
        "code": "conflict_error",
        "message": "This broadcast is already scheduled. Unschedule it first to change when it sends."
      }]
    }
    

    Sets a draft Single-Email Campaign to send. There are three ways to say when, and localize_sending_time is required alongside send_at rather than defaulting, because the two readings of the same timestamp differ by hours for most people:

    Request Sends
    send_at, localize_sending_time: false At the instant given, honoring its offset.
    send_at, localize_sending_time: true At that time of day in each person's own time zone.
    send_at with an offset, localize_sending_time: true The same: the offset is dropped and only the time of day is used.

    So 2026-11-01T09:00:00-05:00 with localize_sending_time: true reaches everyone at 9:00 their own time, not at 14:00 UTC. People with no time zone on record receive a localized send at that time of day in UTC.

    To send now, pass send_immediately: true instead of send_at. Send exactly one of the two, and do not combine send_immediately with localize_sending_time.

    A send_at must be at least five minutes away, or at least 14 hours and five minutes away when localized, so that every time zone can still be reached. Localized sending cannot be used with a split test whose pool is less than 100%.

    Only a draft can be scheduled. To change when a scheduled campaign sends, unschedule it first, then schedule it again. A campaign that is already scheduled, sending, or sent, or whose account cannot send right now, responds with a 409 Conflict that says which.

    The audience is not checked here. A campaign with no audience set goes to everyone eligible to receive it, the same as in the Drip app. Read derived.audience first if that matters.

    With auto_resend, a second copy goes to people who did not open the first, resend_delay whole days later.

    HTTP Endpoint

    POST /v2/:account_id/broadcasts/:broadcast_id/schedule

    Arguments

    Argument Description
    send_at An ISO 8601 timestamp, such as 2026-11-01T09:00:00Z. Required unless send_immediately is true.
    localize_sending_time Required with send_at. false sends at the instant given; true sends at that time of day in each person's own time zone.
    send_immediately Optional. Set to true to send now instead of at send_at. Defaults to false.
    auto_resend Optional. Set to true to send a second copy to people who did not open the first. Defaults to false.
    resend_subject Optional. The subject for the resend. Defaults to the campaign's own subject.
    resend_delay Required when auto_resend is true. Whole days to wait before the resend, at least 1.

    Unschedule a Single-Email Campaign

    To return a scheduled Single-Email Campaign to draft:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/unschedule" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/unschedule")
    
    request = Net::HTTP::Post.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/unschedule",
      {
        method: "POST",
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK and the Single-Email Campaign in the draft status:

    {
      "links": { ... },
      "broadcasts": [{ ... }]
    }
    

    If the Single-Email Campaign has already sent, responds with a 409 Conflict:

    {
      "errors": [{
        "code": "conflict_error",
        "message": "Cannot unschedule a broadcast with status 'sent'"
      }]
    }
    

    Takes a scheduled Single-Email Campaign back to draft so it will not send. The scheduled send time is not preserved, so scheduling it again means setting the time again.

    Calling this on a campaign that is already a draft succeeds and changes nothing, so a retried call is safe. A campaign that is sending or has sent cannot be unscheduled.

    HTTP Endpoint

    POST /v2/:account_id/broadcasts/:broadcast_id/unschedule

    Arguments

    None.

    Email Series Campaigns

    Email Series Campaigns are represented as follows:

    {
      "id": "123456",
      "status": "active",
      "name": "SEO Email Course",
      "from_name": "John Doe",
      "from_email": "[email protected]",
      "reply_to": "[email protected]",
      "postal_address": "123 Anywhere St\nFresno, CA 99999",
      "minutes_from_midnight": 440,
      "localize_sending_time": true,
      "days_of_the_week_mask": "0111110",
      "start_immediately": true,
      "double_optin": true,
      "send_to_confirmation_page": false,
      "use_custom_confirmation_page": false,
      "confirmation_url": null,
      "notify_subscribe_email": "[email protected]",
      "notify_unsubscribe_email": "[email protected]",
      "bcc": null,
      "email_count": 10,
      "active_subscriber_count": 320,
      "unsubscribed_subscriber_count": 5,
      "created_at": "2013-06-21T10:31:58Z",
      "href": "https://api.getdrip.com/v2/9999999/campaigns/123456",
      "links": {
        "account": "9999999",
        "forms": ["888"]
      }
    }
    

    All responses containing Email Series Campaign data also include the following top-level link data:

    {
      "links": {
        "campaigns.account": "https://api.getdrip.com/v2/accounts/{campaigns.account}",
        "campaigns.form": "https://api.getdrip.com/v2/{campaigns.account}/forms/{campaigns.forms}",
        "campaigns.subscribers": "https://api.getdrip.com/v2/{campaigns.account}/campaigns/{campaigns.id}/subscribers"
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each Email Series Campaign record.
    status Returns whether the Email Series Campaign is active, paused or in draft.
    name The private name given to the Email Series Campaign.
    from_name A "from name" that appears in your sent emails. This setting overrides the account's default from name.
    from_email A "from email" that appears in your sent emails. This setting overrides the account's default from email.
    reply_to The Reply-To address set on the Email Series Campaign, or null if none is set. When it is null, replies go to the From address.
    postal_address As required by the CAN-SPAM Act, this is a postal address used for all sent emails.
    minutes_from_midnight The number of minutes after midnight for the time of day set for email sending.
    localize_sending_time The scheduled send_at time if set to be sent in the subscriber's time zone.
    days_of_the_week_mask A representation of the days of week when emails are set to be sent. For example, 1111100 represents sending enabled only for Mondays to Fridays while 1111111 represents sending enabled for all days of the week.
    start_immediately Returns true if the first email in the Email Series Campaign is set to be delivered immediately after a Email Series Campaign subscription.
    double_optin Returns true if double opt-in is enabled for the Email Series Campaign.
    send_to_confirmation_page Deprecated
    use_custom_confirmation_page Deprecated
    post_confirmation_url Deprecated
    notify_subscribe_email An email address set that receives a notification whenever a subscriber subscribes via a form submission.
    notify_unsubscribe_email An email address set that receives a notification whenever a subscriber unsubscribes via their subscription management page.
    bcc A blind copy email address set for all Email Series Campaign email deliveries.
    email_count Returns a count of all emails associated with the Email Series Campaign. Includes all email statuses.
    active_subscriber_count Returns a count of all subscribers who are actively subscribed to the Email Series Campaign.
    unsubscribed_subscriber_count Returns a count of all subscribers who unsubscribed from the Email Series Campaign via a delivered email.
    created_at A timestamp representing when the Email Series Campaign was first created.
    href The url designated for retrieving the Email Series Campaign record via the REST API.
    links An object containing the REST API URL for the account, any associated Email Series Campaign forms and subscribers subscribed to the Email Series Campaign.
    forms An object containing the associated form created for the Email Series Campaign. This is only populated if a form is created for the Email Series Campaign. Refer to Forms for an overview of the properties returned here.

    List all Email Series Campaigns

    To list all Email Series Campaigns:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/campaigns" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.campaigns
    
    if response.success?
      puts response.body["campaigns"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const options = { status: "active" };
    
    client.listCampaigns(options)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The campaigns property is an array of campaign objects.
    {
      "links": { ... },
      "meta": {
        "page": 1,
        "sort": "created_at",
        "direction": "asc",
        "count": 5,
        "total_pages": 1,
        "total_count": 5,
        "status": "all"
      },
      "campaigns": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/campaigns

    Arguments

    Key Description
    status Optional. Filter by one of the following statuses: draft, active, or paused. Defaults to all.
    sort Optional. Sort results by one of these fields: created_at or name. Defaults to created_at.
    direction Optional. Filter sort direction with: asc or desc. Defaults to asc.

    Fetch an Email Series Campaign

    To fetch a specific Email Series Campaign:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/campaigns/CAMPAIGN_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    campaign_id = 9999999
    response = client.campaign(campaign_id)
    
    if response.success?
      puts response.body
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const campaignId = 9998888;
    
    client.fetchCampaign(campaignId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The campaigns property is an array of campaign objects.
    # The forms property is an array of forms that feed directly into to the campaign.
    {
      "links": { ... },
      "campaigns": [{ ... }],
      "linked": {
        "forms": [{ ... }]
      }
    }
    

    HTTP Endpoint

    GET /v2/:account_id/campaigns/:campaign_id

    Arguments

    None.

    Activate an Email Series Campaign

    To activate an Email Series Campaign:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/campaigns/CAMPAIGN_ID/activate" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    campaign_id = 9999999
    response = client.activate_campaign(campaign_id)
    
    if response.success?
      puts response.body
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const campaignId = 9998888;
    
    client.activateCampaign(campaignId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful. If the Email Series Campaign cannot be activated, returns a 422 Unprocessable Entity.

    HTTP Endpoint

    POST /v2/:account_id/campaigns/:campaign_id/activate

    Arguments

    None.

    Pause an Email Series Campaign

    To pause an Email Series Campaign:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/campaigns/CAMPAIGN_ID/pause" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    campaign_id = 9999999
    response = client.pause_campaign(campaign_id)
    
    if response.success?
      puts response.body
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const campaignId = 9998888;
    
    client.pauseCampaign(campaignId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful. If the Email Series Campaign cannot be paused, returns a 422 Unprocessable Entity.

    HTTP Endpoint

    POST /v2/:account_id/campaigns/:campaign_id/pause

    Arguments

    None.

    List all subscribers subscribed to an Email Series Campaign

    To list subscribers on an Email Series Campaign:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/campaigns/CAMPAIGN_ID/subscribers" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    campaign_id = 9999999
    response = client.campaign_subscribers(campaign_id)
    
    if response.success?
      puts response.body["subscribers]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const campaignId = 9998888;
    
    client.listAllSubscribesToCampaign(campaignId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The subscribers property is an array of subscriber objects.
    {
      "links": { ... },
      "meta": {
        "page": 1,
        "direction": "desc",
        "count": 20,
        "total_pages": 1,
        "total_count": 20
      },
      "subscribers": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/campaigns/:campaign_id/subscribers

    Arguments

    Key Description
    status Optional. The status to filter by: active, unsubscribed, or removed. Defaults to active.
    page Optional. The page number. Defaults to 1.
    direction Optional. The direction to sort the results for created_at: asc or desc. Defaults to desc.
    per_page Optional. The number of records to be returned on each page. Defaults to 100. Maximum 1000.

    Subscribe someone to an Email Series Campaign

    To start a subscriber on an Email Series Campaign:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/campaigns/CAMPAIGN_ID/subscribers" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "subscribers": [{
          "email": "[email protected]",
          "utc_offset": 660,
          "double_optin": true,
          "starting_email_index": 0,
          "reactivate_if_removed": true,
          "custom_fields": {
            "shirt_size": "Medium"
          }
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    campaign_id = 9999999
    email = "[email protected]"
    options = {
      time_zone: "America/Los_Angeles",
      custom_fields: {
        name: "Jane Doe"
      }
    }
    
    response = client.subscribe(email, campaign_id, options)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const campaignId = 9998888;
    const payload = {
      subscribers: [{
        email: "[email protected]",
        time_zone: "Asia/Kuala_Lumpur",
        custom_fields: {
          name: "Jane Doe"
        }
      }]
    }
    
    client.subscribeToCampaign(campaignId, payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The subscribers property is an array of one object.
    {
      "links": { ... },
      "subscribers": [{ ... }]
    }
    

    HTTP Endpoint

    POST /v2/:account_id/campaigns/:campaign_id/subscribers

    Arguments

    Key Description
    email Required. The subscriber's email address.
    user_id Optional. A unique identifier for the user in your database, such as a primary key.
    time_zone Optional. The subscriber's time zone (in Olson format). Defaults to Etc/UTC
    double_optin Optional. If true, the double opt-in confirmation email is sent; if false, the confirmation email is skipped. Defaults to the value set on the Email Series Campaign.
    starting_email_index Optional. The index (zero-based) of the email to send first. Defaults to 0.
    custom_fields Optional. An Object containing custom field data. E.g. { "shirt_size": "Medium" }.
    tags Optional. An Array containing one or more tags. E.g. ["Customer", "SEO"].
    reactivate_if_removed Optional. If true, re-subscribe the subscriber to the Email Series Campaign if there is a removed subscriber in Drip with the same email address; otherwise, respond with 422 Unprocessable Entity. Defaults to true.
    prospect Optional. A Boolean specifiying whether we should attach a lead score to the subscriber (when lead scoring is enabled). Defaults to true. Note: This flag used to be called potential_lead, which we will continue to accept for backwards compatibility.
    base_lead_score Optional. An Integer specifying the starting value for lead score calculation for this subscriber. Defaults to 30.
    eu_consent Optional. A String specifying whether the subscriber granted or denied GDPR consent.
    eu_consent_message Optional. A String containing the message the subscriber granted or denied their consent to.

    List all of a subscriber's Email Series Campaign subscriptions

    To list Email Series Campaign subscriptions for a subscriber:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/SUBSCRIBER_ID/campaign_subscription" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_id = "bihfwo84teh35dgt99"
    
    response = client.campaign_subscriptions(subscriber_id)
    
    if response.success?
      puts response.body["campaign_subscriptions"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const subscriberId = "iuyfgfweufgr9hvrugegff";
    
    client.subscriberCampaignSubscriptions(subscriberId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The Email Series Campaign subscriptions property is an array of campaign subscription objects.
    {
      "links": {
        "campaign_subscriptions.account": "https://api.getdrip.com/v2/accounts/{campaign_subscriptions.account}",
        "campaign_subscriptions.subscriber": "https://api.getdrip.com/v2/subscribers/{campaign_subscriptions.subscriber}"
      },
      "meta": {
        "page": 1,
        "count": 5,
        "total_pages": 1,
        "total_count": 5
      },
      "campaign_subscriptions": [{
        "id": "123456",
        "campaign_id": "999999",
        "status": "active",
        "is_complete": false,
        "lap": 1,
        "last_sent_email_index": 0,
        "last_sent_email_at": "2016-03-25T11:00:00Z",
        "links": {
          "account": "9999999",
          "subscriber": "z1togz2hcjrkpp5treip"
        }
      }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/subscribers/:subscriber_id/campaign_subscriptions

    Arguments

    None.

    Custom Fields

    List all custom field identifiers used in an account

    To list all custom fields:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/custom_field_identifiers" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.custom_fields
    
    if response.success?
      puts response.body["custom_field_identifiers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    
    client.listAllCustomFields()
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    {
      "custom_field_identifiers": [ "first_name", "last_name" ]
    }
    

    Properties

    Property Description
    custom_field_identifiers Returns a list of all active custom field identifiers used in the target account.

    HTTP Endpoint

    GET /v2/:account_id/custom_field_identifiers

    Arguments

    None.

    Conversions

    Conversions are represented as follows:

    {
      "id": "99999",
      "status": "active",
      "name": "Trial Signup",
      "url": "/receipt",
      "default_value": 2000,
      "counting_method": "one_per_visitor",
      "created_at": "2013-06-21T10:31:58Z",
      "href": "https://api.getdrip.com/v2/9999999/goals/99999",
      "links": {
        "account": "9999999"
      }
    }
    

    All responses containing conversion data also include the following top-level link data:

    {
      "links": {
        "goals.account": "https://api.getdrip.com/v2/accounts/{goals.account}"
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each conversion record.
    status Returns whether the conversion is enabled or disabled.
    name The private name given to the conversion.
    url A URL used for detecting and recording conversions.
    default_value A default value assigned to a tracked conversion. Conversion values must be less than 2,147,483,647.
    counting_method Set either as one_per_visitor or all and determines whether a maximum of one conversion is counted per person or all.
    created_at A timestamp representing when the conversion was first created.
    href The url designated for retrieving the conversion record via the REST API.
    links An object containing the REST API URL for the account.

    See the Events API for recording conversion events.

    List all conversions

    To list all conversions in an account:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/goals" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.conversions
    
    if response.success?
      puts response.body["goals"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const options = { status: "active" };
    
    client.listConversions(options)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The goals property is an array of conversion goal objects.
    {
      "links": { ... },
      "goals": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/goals

    Arguments

    Key Description
    status Optional. The status to filter by: active, disabled, or all. Defaults to all.
    sort Optional. Sort results by one of these fields: created_at or name. Defaults to created_at.
    direction Optional. Filter sort direction with: asc or desc. Defaults to asc.

    Fetch a conversion

    To fetch a conversion:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/goals/CONVERSION_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    conversion_id = 9999999
    response = client.conversion(conversion_id)
    
    if response.success?
      puts response.body["goals"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const conversionId = 8889999;
    
    client.fetchConversion(conversionId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The goals property is an array of one conversion goal object.
    {
      "links": { ... },
      "goals": [{ ... }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/goals/:conversion_id

    Arguments

    None.

    Events

    Record an event

    To create or update a subscriber:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/events" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "events": [{
          "email": "[email protected]",
          "action": "Logged in",
          "properties": {
            "affiliate_code": "XYZ"
          },
          "occurred_at": "2014-03-22T03:00:00Z"
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    email = "[email protected]"
    action = "Docked with space station"
    properties = {
      station: "Mars Endeavor"
    }
    
    response = client.track_event(email, action, properties)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const payload = {
      email: "[email protected]",
      action: "Logged in",
      properties: {
        affiliate_code: "XYZ"
      }
    };
    
    client.recordEvent(payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful.

    If you need to create or update a collection of events at once, use the Batch API instead.

    HTTP Endpoint

    POST /v2/:account_id/events

    Arguments

    Key Description
    email Optional. The subscriber's email address. Either email or id must be included.
    id Optional. The subscriber's Drip id. Either email or id must be included.
    action Required. The name of the action taken. E.g. "Logged in"
    prospect Optional. A Boolean specifiying whether we should attach a lead score to the subscriber (when lead scoring is enabled). Defaults to true. Note: This flag used to be called potential_lead, which we will continue to accept for backwards compatibility.
    properties Optional. An Object containing custom event properties. If this event is a conversion, include the value (in cents) in the in the properties with a value key. Conversion values must be less than 2,147,483,647.
    occurred_at Optional. The String time at which the event occurred in ISO-8601 format. Defaults to the current time.

    List all custom events actions used in an account

    To list custom event actions:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/event_actions" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.event_actions
    
    if response.success?
      puts response["event_actions"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const options = { per_page: 200 };
    
    client.listEventActions(options)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    {
      "meta": {
        "count": 2,
        "page": 1,
        "total_count": 2,
        "total_pages": 1
      },
      "event_actions": [
        "Ate a sandwich",
        "Started a trial"
      ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/event_actions

    Arguments

    Key Description
    page Optional. The page number. Defaults to 1.
    per_page Optional. The number of records to be returned on each page. Defaults to 100. Maximum 1000.

    Forms

    Forms are represented as follows:

    {
      "id": "77777",
      "href": "https://api.getdrip.com/v2/9999999/forms/77777",
      "headline": "Long Tail SEO Course",
      "description": "Get our FREE email course",
      "button_text": "Sign Up!",
      "confirmation_heading": "Thank you for subscribing",
      "confirmation_text": "Please click the link in your email",
      "send_ga_event": true,
      "seconds_before_popup": 5,
      "days_between_popup": 5,
      "days_between_popup_after_close": 10,
      "orientation": "bottom_right_tab",
      "opacity": 0.8,
      "show_labels": false,
      "primary_color": "#333333",
      "secondary_color": "#d8ab93",
      "is_widget_enabled": true,
      "whitelist": [ "/landing", "/public" ],
      "blacklist": [],
      "is_whitelist_enabled": true,
      "is_blacklist_enabled": false,
      "hide_on_mobile": false,
      "is_embeddable": true,
      "created_at": "2013-06-21T10:31:58Z",
      "links": {
        "account": "9999999"
      }
    }
    

    All responses containing form data also include the following top-level link data:

    {
      "links": {
        "forms.account": "https://api.getdrip.com/v2/accounts/{forms.account}"
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each form record.
    href The url designated for retrieving the form record via the REST API.
    headline The visible headline on the form widget or embedded form.
    description A description shown in the body of the form widget or in the embedded form.
    button_text The text shown on the submission button for the form.
    confirmation_heading A heading shown after a subscriber submits the form.
    confirmation_text The text shown after a subscriber submits the form.
    send_ga_event Returns true if an event is sent to Google Analytics upon submission.
    seconds_before_popup A delay in seconds before the form widget is displayed.
    days_between_popup A delay in days between each appearance of the form widget.
    days_between_popup_after_close A delay in days between each appearance of the form widget after a visitor closes the form.
    orientation The position on the page where the form widget is displayed. Possible values are bottom_left_tab, bottom_right_tab, side_left_tab, side_right_tab, embedded or lightbox.
    opacity The opacity set for form field labels.
    show_labels Returns true if form field labels are shown above text boxes.
    primary_color The tab color for the form.
    secondary_color The headline color for the form.
    is_widget_enabled Returns true if the form widget is enabled and shown.
    whitelist An array of URL paths where the form is shown.
    blacklist An array of URL paths where the form is hidden.
    is_whitelist_enabled Returns true if whitelisted URLs are set.
    is_blacklist_enabled Returns true if blacklisted URLs are set.
    hide_on_mobile Returns true if the form widget is disabled for mobile devices.
    is_embeddable Deprecated
    created_at A timestamp representing when the form was first created.
    links An object containing the REST API URL for the account.

    List all forms

    To list all forms in an account:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/forms" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.forms
    
    if response.success?
      puts response.body["forms"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    
    client.listForms()
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The forms property is an array of form objects.
    {
      "links": { ... },
      "forms": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/forms

    Arguments

    None.

    Fetch a form

    To fetch a specific form:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/forms/FORM_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    form_id = 9999999
    response = client.form(form_id)
    
    if response.success?
      puts response.body["forms"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const formId = 9998888;
    
    client.fetchForm(formId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The forms property is an array of one form object.
    {
      "links": { ... },
      "forms": [{ ... }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/forms/:form_id

    Arguments

    None.

    Metrics

    The Metrics API returns aggregate email performance for an account: sends, deliveries, opens, clicks, bot clicks, unsubscribes, hard bounces, complaints, orders, and revenue.

    Results cover Single-Email Campaigns, and automation emails sent by Workflows. Confirmation emails (double opt-in) are excluded. Order and revenue values are reported in cents.

    Dates are interpreted in the account owner's time zone.

    Email metrics are represented as follows:

    {
      "email_id": 4455661,
      "broadcast_id": "123456",
      "workflow_placement": {
        "workflow_id": "789012",
        "node_id": "SENDEMAILNODE1"
      },
      "title": "December Newsletter",
      "email_metric": { ... }
    }
    

    Properties

    Property Description
    email_id A read-only Drip generated unique id used to identify each email record.
    broadcast_id The id of the Single-Email Campaign that sent the email. Only present for Single-Email Campaign emails.
    workflow_placement An object containing the workflow_id of the workflow that sends the email and the node_id of the send-email step within it. Only present when the request includes a workflow_ids filter and the email is sent by one of those workflows. node_id holds the same value Fetch a workflow's details returns as a node's id.
    title The name of the Single-Email Campaign, Email Series Campaign, or automation that sent the email.
    email_metric An object containing the email's metrics.

    Email Metrics

    The email metric object structure:

    {
      "sends": 1000,
      "deliveries": 970,
      "opens": 420,
      "open_rate": 0.42,
      "clicks": 85,
      "click_rate": 0.085,
      "bot_clicks": 12,
      "bot_click_rate": 0.012,
      "unsubscribes": 7,
      "unsubscribe_rate": 0.007,
      "hard_bounces": 18,
      "hard_bounce_rate": 0.018,
      "complaints": 2,
      "complaint_rate": 0.002,
      "orders": 24,
      "order_rate": 0.024,
      "revenue_in_cents": 384000,
      "revenue_per_person_in_cents": 384,
      "average_order_value_in_cents": 16000
    }
    

    Every rate is calculated against sends and rounded to four decimal places. The same object is used for the report summary and for each email's email_metric.

    Key Description
    sends The number of emails sent.
    deliveries The number of sent emails accepted by the recipient's mail server.
    opens The number of opens recorded.
    open_rate opens divided by sends.
    clicks The number of clicks recorded.
    click_rate clicks divided by sends.
    bot_clicks The number of clicks attributed to automated systems rather than people.
    bot_click_rate bot_clicks divided by sends.
    unsubscribes The number of unsubscribes.
    unsubscribe_rate unsubscribes divided by sends.
    hard_bounces The number of hard bounces.
    hard_bounce_rate hard_bounces divided by sends.
    complaints The number of spam complaints.
    complaint_rate complaints divided by sends.
    orders The number of orders attributed to the email.
    order_rate orders divided by sends.
    revenue_in_cents The revenue attributed to the email, in cents.
    revenue_per_person_in_cents revenue_in_cents divided by sends, in cents.
    average_order_value_in_cents revenue_in_cents divided by orders, in cents.

    Fetch email metrics

    To fetch email metrics:

    curl -g "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/metrics/email?start_date=2026-01-01&end_date=2026-01-31&broadcast_ids[]=BROADCAST_ID&workflow_ids[]=WORKFLOW_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/metrics/email")
    uri.query = URI.encode_www_form(
      "start_date" => "2026-01-01",
      "end_date" => "2026-01-31",
      "broadcast_ids[]" => "BROADCAST_ID",
      "workflow_ids[]" => "WORKFLOW_ID"
    )
    
    request = Net::HTTP::Get.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const params = new URLSearchParams({
      start_date: "2026-01-01",
      end_date: "2026-01-31"
    });
    params.append("broadcast_ids[]", "BROADCAST_ID");
    params.append("workflow_ids[]", "WORKFLOW_ID");
    
    const response = await fetch(
      `https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/metrics/email?${params}`,
      {
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    The response looks like this:

    # The emails property is an array of email metrics objects.
    {
      "summary": { ... },
      "emails_total": 3,
      "emails_truncated": false,
      "emails": [ ... ]
    }
    

    If the filters match no emails, the summary is zeroed and no emails are returned:

    {
      "summary": {
        "sends": 0,
        "deliveries": 0,
        ...
      },
      "emails_total": 0,
      "emails_truncated": false,
      "emails": []
    }
    

    If an argument is invalid or exceeds a limit, responds with a 400 Bad Request:

    {
      "errors": [{
        "code": "bad_request",
        "message": "Date range cannot exceed 366 days."
      }]
    }
    

    If the rate limit is exceeded, responds with a 429 Too Many Requests and a Retry-After header indicating when the limit resets:

    {
      "errors": [{
        "code": "rate_limit_exceeded",
        "message": "Rate limit exceeded: at most 20 requests per account per hour."
      }]
    }
    

    If the report cannot be produced in time, responds with a 503 Service Unavailable:

    {
      "errors": [{
        "code": "unavailable_error",
        "message": "Service temporarily unavailable, try again later"
      }]
    }
    

    The summary totals the report across every email in the range, and emails lists up to limit of those emails individually (100 by default). Emails are listed by sends, highest first, with ties broken by email_id in ascending order. emails_total is the number of emails that matched, and emails_truncated is true when that is more than emails lists. To list the rest, call again with limit set to emails_total, up to 1,000; beyond that the full list isn't available. This endpoint is not paginated.

    Rule- and form-automation emails appear only in unfiltered results. broadcast_ids reaches only Single-Email Campaign emails and workflow_ids reaches only Workflow emails, so neither filter can target them.

    Limits

    Limit Applies to
    366 days The date range, after defaults are applied
    25 ids workflow_ids per request
    1,000 emails The emails that broadcast_ids and workflow_ids resolve to
    1,000 emails limit

    Requests that exceed any of these limits are rejected with a 400 Bad Request.

    Rate limits

    This endpoint has its own rate limit, separate from the standard API rate limit. Limits are applied per account.

    Limit Window
    20 requests Per hour

    HTTP Endpoint

    GET /v2/:account_id/metrics/email

    Arguments

    Key Description
    start_date Optional. The first day of the range in YYYY-MM-DD format, inclusive. Defaults to 30 days ago.
    end_date Optional. The last day of the range in YYYY-MM-DD format, inclusive. Defaults to today.
    broadcast_ids Optional. An Array of Single-Email Campaign ids. Limits results to the emails sent by those Single-Email Campaigns.
    workflow_ids Optional. An Array of workflow ids. Limits results to the emails sent by those workflows. May be combined with broadcast_ids, in which case the results are the union of both filters.
    limit Optional. The maximum number of emails to list in emails, a whole number from 1 to 1,000. Defaults to 100. Does not change summary or emails_total.

    Orders (Legacy)

    We’ve released a new and improved endpoint for Orders functionality! This new endpoint will allow you to trigger automations and segment people based on the items contained in their orders. Check it out here.

    Note that the legacy Orders endpoint will continue to function. We will give fair notice before we retire it in the future.

    Orders are represented as follows:

    {
      "id": "9999999",
      "provider": "shopify",
      "upstream_id": "abcdef",
      "identifier": "Order_123456",
      "amount": 4900,
      "tax": 100,
      "fees": 0,
      "discount": 0,
      "permalink": "http://myorders.com/orders/123456",
      "currency_code": "USD",
      "properties": {
        "shirt_size": "Medium",
        "color": "red"
      },
      "occurred_at": "2013-06-21T10:31:58Z",
      "closed_at": "2013-06-21T10:35:58Z",
      "cancelled_at": null,
      "financial_state": "paid",
      "fulfillment_state": "fulfilled",
      "billing_address": {
        "name": "Bill Billington",
        "first_name": "Bill",
        "last_name": "Billington",
        "company": "Bills R US",
        "address_1": "123 Bill St.",
        "address_2": "Apt. B",
        "city": "Billtown",
        "state": "CA",
        "zip": "01234",
        "country": "United States",
        "phone": "555-555-5555",
        "email": "[email protected]"
      },
      "shipping_address": {
        "name": "Ship Shippington",
        "first_name": "Ship",
        "last_name": "Shipington",
        "company": "Shipping 4 Less",
        "address_1": "123 Ship St.",
        "address_2": "null",
        "city": "Shipville",
        "state": "CA",
        "zip": "01234",
        "country": "United States",
        "phone": "555-555-5555",
        "email": "[email protected]"
      },
      "items": [{
        "id": "8888888",
        "product_id": "765432",
        "sku": "4444",
        "amount": 4900,
        "name": "Canoe",
        "quantity": 1,
        "upstream_id": "hijkl",
        "upstream_product_id": "opqrs",
        "upstream_product_variant_id": "zyxwv",
        "price": 4900,
        "tax": 100,
        "fees": 0,
        "discount": 100,
        "taxable": true,
        "properties": {
          "color": "black"
        }
      }],
      "links": {
        "account": "9999999",
        "subscriber": "5555555"
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each order record.
    provider The identifier for the provider from which the order data was received in lower snake cased form. For example, shopify or my_store
    amount The total amount of the order in cents (e.g. if the order was $49.99, set the amount to 4999).
    tax The tax on the order in cents (e.g. if the order was $1.00, set the tax to 100).
    fees The fees on the order in cents (e.g. if the order was $1.00, set the fees to 100).
    discount The discount on the order in cents (e.g. if the order was $5.00, set the discount to 500).
    permalink A URL for the human-readable interface to view the order details.
    currency_code The alphabetic ISO 4217 code for the currency of the purchase.
    upstream_id A unique, internal id for the order (generally the primary key generated by the order management system).
    identifier A unique, external identifier for the order. This will be displayed in the Drip UI and should correspond to what a customer sees on invoices, email confirmations, etc.
    properties An Object containing properties about the order. E.g. { "size": "large" }
    occurred_at The String time at which the order occurred in ISO-8601 format. Defaults to the current time.
    closed_at The String time at which the order closed in ISO-8601 format.
    cancelled_at The String time at which the order was cancelled in ISO-8601 format. For an order that was not cancelled, this will be nil.
    financial_state The financial status of the order. One of the following values: pending, authorized, partially_paid, paid, partially_refunded, refunded, voided.
    fulfillment_state The fulfillment status of the order. One of the following values: not_fulfilled, partially_fulfilled, fulfilled.
    billing_address An object containing billing address information.

    Key Description
    name The full name on the billing address
    first_name The first name on the billing address
    last_name The last name on the billing address
    company The company on the billing address
    address_1 The billing street address
    address_2 Additional line of the billing street address
    city The billing address city
    state The billing address state
    zip The billing address zip code
    country The billing address country
    phone The phone number associated with the billing address
    email The email associated with the billing address
    shipping_address An object containing shipping address information.

    Key Description
    name The full name on the shipping address
    first_name The first name on the shipping address
    last_name The last name on the shipping address
    company The company on the shipping address
    address_1 The shipping street address
    address_2 Additional line of the shipping street address
    city The shipping address city
    state The shipping address state
    zip The shipping address zip code
    country The shipping address country
    phone The phone number associated with the shipping address
    email The email associated with the shipping address
    items An Array of objects containing information about specific order items.

    Key Description
    name The product name
    amount The line total (in cents).
    price The item price (in cents).
    tax The item tax (in cents).
    fees The item fees (in cents).
    discount The item discount (in cents).
    quantity The quantity of the item ordered (if omitted, defaults to 1).
    product_id A unique identifier for the specific product.
    upstream_id A unique identifier for the item from the provider.
    upstream_product_id A unique identifier for the specific product from the provider.
    upstream_product_variant_id A unique identifier for the specific product variant from the provider.
    sku The product SKU number.
    taxable Boolean indicating whether the item is taxable.
    properties An Object containing properties about the line item.
    links An object containing the REST API URL for the account.

    Create or update an order

    To create or update an order for a subscriber:

    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    order = {
      provider: "shopify",
      upstream_id: "abcdef",
      identifier: "Order_123456",
      amount: 4900,
      tax: 100,
      fees: 0,
      discount: 0,
      permalink: "http://myorders.com/orders/123456",
      currency_code: "USD",
      properties: {
        shirt_size: "Medium",
        color: "red"
      },
      occurred_at: "2013-06-21T10:31:58Z",
      closed_at: "2013-06-21T10:35:58Z",
      financial_state: "paid",
      fulfillment_state: "fulfilled",
      billing_address: {
        name: "Bill Billington",
        first_name: "Bill",
        last_name: "Billington",
        company: "Bills R US",
        address_1: "123 Bill St.",
        address_2: "Apt. B",
        city: "Billtown",
        state: "CA",
        zip: "01234",
        country: "United States",
        phone: "555-555-5555",
        email: "[email protected]"
      },
      shipping_address: {
        name: "Ship Shippington",
        first_name: "Ship",
        last_name: "Shipington",
        company: "Shipping 4 Less",
        address_1: "123 Ship St.",
        address_2: "null",
        city: "Shipville",
        state: "CA",
        zip: "01234",
        country: "United States",
        phone: "555-555-5555",
        email: "[email protected]"
      },
      items: [{
        id: "8888888",
        product_id: "765432",
        sku: "4444",
        amount: 4900,
        name: "Canoe",
        quantity: 1,
        upstream_id: "hijkl",
        upstream_product_id: "opqrs",
        upstream_product_variant_id: "zyxwv",
        price: 4900,
        tax: 100,
        fees: 0,
        discount: 100,
        taxable: true,
        properties: {
          color: "black"
        }
      }]
    }
    
    response = client.create_or_update_order("[email protected]", order)
    
    if response.success?
      # ...
    end
    
    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/orders" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -H "Content-Type: application/json" \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "orders": [{
          "email": "[email protected]",
          "provider": "shopify",
          "upstream_id": "abcdef",
          "identifier": "Order_123456",
          "amount": 4900,
          "tax": 100,
          "fees": 0,
          "discount": 0,
          "permalink": "http://myorders.com/orders/123456",
          "currency_code": "USD",
          "properties": {
            "shirt_size": "Medium",
            "color": "red"
          },
          "occurred_at": "2013-06-21T10:31:58Z",
          "closed_at": "2013-06-21T10:35:58Z",
          "financial_state": "paid",
          "fulfillment_state": "fulfilled",
          "billing_address": {
            "name": "Bill Billington",
            "first_name": "Bill",
            "last_name": "Billington",
            "company": "Bills R US",
            "address_1": "123 Bill St.",
            "address_2": "Apt. B",
            "city": "Billtown",
            "state": "CA",
            "zip": "01234",
            "country": "United States",
            "phone": "555-555-5555",
            "email": "[email protected]"
          },
          "shipping_address": {
            "name": "Ship Shippington",
            "first_name": "Ship",
            "last_name": "Shipington",
            "company": "Shipping 4 Less",
            "address_1": "123 Ship St.",
            "address_2": "null",
            "city": "Shipville",
            "state": "CA",
            "zip": "01234",
            "country": "United States",
            "phone": "555-555-5555",
            "email": "[email protected]"
          },
          "items": [{
              "id": "8888888",
              "product_id": "765432",
              "sku": "4444",
              "amount": 4900,
              "name": "Canoe",
              "quantity": 1,
              "upstream_id": "hijkl",
              "upstream_product_id": "opqrs",
              "upstream_product_variant_id": "zyxwv",
              "price": 4900,
              "tax": 100,
              "fees": 0,
              "discount": 100,
              "taxable": true,
              "properties": {
                "color": "black"
              }
            }]
        }]
      }
    EOF
    

    Responds with a 202 Accepted and an empty JSON response:

    {}
    

    When an order is created, the subscriber's lifetime_value attribute will be automatically incremented by the total amount of the order.

    To update an existing order, include the provider and upstream_id for that order in the payload.

    Note: A matching subscriber record must already be present in Drip before an order can be created.

    HTTP Endpoint

    POST /v2/:account_id/orders

    Arguments

    Property Description
    email Optional. The email address of the order's subscriber. Either email or id must be included.
    id Optional. The Drip id of the order's subscriber. Either email or id must be included.
    amount Required. The total amount of the order in cents (e.g. if the order was $49.99, set the amount to 4999).
    provider Optional. Required for updates. The identifier for the provider from which the order data was received in lower snake cased form. For example, shopify or my_store. Used to identify the order for updates.
    tax Optional. The tax on the order in cents (e.g. if the order was $1.00, set the tax to 100).
    fees Optional. The fees on the order in cents (e.g. if the order was $1.00, set the fees to 100).
    discount Optional. The discount on the order in cents (e.g. if the order was $5.00, set the discount to 500).
    permalink Optional. A URL for the human-readable interface to view the order details.
    currency_code Optional. The alphabetic ISO 4217 code for the currency of the purchase.
    upstream_id Optional. Required for updates. A unique, internal id for the order (generally the primary key generated by the order management system). Used to identify the order for updates.
    identifier Optional. A unique, external identifier for the order. This will be displayed in the Drip UI and should correspond to what a customer sees on invoices, email confirmations, etc.
    properties Optional. An Object containing properties about the order. E.g. { "size": "large" }
    occurred_at Optional. The String time at which the order occurred in ISO-8601 format. Defaults to the current time.
    closed_at Optional. The String time at which the order closed in ISO-8601 format.
    cancelled_at Optional. The String time at which the order was cancelled in ISO-8601 format. For an order that was not cancelled, this will be nil.
    financial_state Optional. The financial status of the order. One of the following values: pending, authorized, partially_paid, paid, partially_refunded, refunded, voided.
    fulfillment_state Optional. The fulfillment status of the order. One of the following values: not_fulfilled, partially_fulfilled, fulfilled.
    billing_address Optional. An object containing billing address information.

    Key Description
    name The full name on the billing address
    first_name The first name on the billing address
    last_name The last name on the billing address
    company The company on the billing address
    address_1 The billing street address
    address_2 Additional line of the billing street address
    city The billing address city
    state The billing address state
    zip The billing address zip code
    country The billing address country
    phone The phone number associated with the billing address
    email The email associated with the billing address
    shipping_address Optional. An object containing shipping address information.

    Key Description
    name The full name on the shipping address
    first_name The first name on the shipping address
    last_name The last name on the shipping address
    company The company on the shipping address
    address_1 The shipping street address
    address_2 Additional line of the shipping street address
    city The shipping address city
    state The shipping address state
    zip The shipping address zip code
    country The shipping address country
    phone The phone number associated with the shipping address
    email The email associated with the shipping address
    items Optional. An Array of objects containing information about specific order items.

    Key Description
    name Required. The product name
    amount Required. The line total (in cents).
    price The item price (in cents).
    tax The item tax (in cents).
    fees The item fees (in cents).
    discount The item discount (in cents).
    quantity The quantity of the item ordered (if omitted, defaults to 1).
    product_id A unique identifier for the specific product.
    upstream_id A unique identifier for the item from the provider.
    upstream_product_id A unique identifier for the specific product from the provider.
    upstream_product_variant_id A unique identifier for the specific product variant from the provider.
    sku The product SKU number.
    taxable Boolean indicating whether the item is taxable.
    properties An Object containing properties about the line item.

    Create or update a refund

    To create or update a refund for an order:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/refunds" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "refunds": [{
            "provider": "shopify",
            "order_upstream_id": "abcdef",
            "upstream_id": "tuvwx",
            "amount": 2000,
            "note": "Incorrect size",
            "processed_at": "2013-06-22T10:41:11Z"
          }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    refund = {
      provider: "shopify",
      order_upstream_id: "abcdef",
      upstream_id: "tuvwx",
      amount: 2000,
      note: "Incorrect size",
      processed_at: "2013-06-22T10:41:11Z"
    }
    
    response = client.create_or_update_refund(refund)
    
    if response.success?
      # ...
    end
    

    Responds with a 202 Accepted and an empty JSON response:

    {}
    

    When a refund is created, the subscriber's lifetime_value attribute will be automatically decremented by the total amount of the refund.

    To update an existing refund, include the upstream_id for that refund in the payload.

    HTTP Endpoint

    POST /v2/:account_id/refunds

    Arguments

    Property Description
    provider Required. The provider for the Order being refunded.
    order_upstream_id Required. The upstream_id for the Order being refunded.
    amount Required. The amount of the refund.
    upstream_id Optional. Required for updates. The unique id of refund in the order management system. Used to identify the refund for updates.
    note Optional. A note about the refund.
    processed_at Optional. The String time at which the refund was processed in ISO-8601 format.

    Order events

    Drip automatically records a number of events in the life cycle of an order. You can find triggers for these events by selecting Drip Order API from the provider dropdown in your Drip automation.

    Event Description
    Placed an order This event is fired when an order is created.
    Updated an order This event is fired when an existing order is updated.
    Paid an order This event is fired when the financial_state on an order is set to paid.
    Fulfilled an order This event is fired when the fulfillment_state on an order is set to fulfilled.
    Canceled an order This event is fired when the cancelled_at time on an order is set.
    Refunded an order This event is fired when a refund is created for an order.

    Segments

    Segments are saved groups of people, built in the Drip app from a set of rules. This API is read-only: segments are created and edited in the app, and read here so you can find one by name and point a Single-Email Campaign at it.

    The id returned here is the value the Single-Email Campaigns API takes as segment_id when setting an audience.

    Only active, permanent segments are returned. A deleted, expired, or temporary segment is treated as though it does not exist.

    List all segments

    To list all segments:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/segments" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/segments")
    
    request = Net::HTTP::Get.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/segments",
      {
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK:

    {
      "links": { ... },
      "meta": {
        "page": 1,
        "count": 2,
        "total_pages": 1,
        "total_count": 2
      },
      "segments": [{
        "id": "4815162",
        "href": "https://api.getdrip.com/v2/9999999/segments/4815162",
        "name": "VIP customers",
        "created_at": "2026-01-14T09:22:41Z",
        "updated_at": "2026-08-02T17:05:03Z",
        "links": { "account": "9999999" }
      }]
    }
    

    Results come back in a stable but unspecified order. Ordering is not part of the contract yet.

    HTTP Endpoint

    GET /v2/:account_id/segments

    Arguments

    Argument Description
    page Optional. The page number. Defaults to 1.
    per_page Optional. The number of segments per page. Defaults to 100, maximum 100.
    q Optional. Case-insensitive substring match on the segment's name.

    Fetch a segment

    To fetch a segment:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/segments/SEGMENT_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/segments/SEGMENT_ID")
    
    request = Net::HTTP::Get.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/segments/SEGMENT_ID",
      {
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    Responds with a 200 OK:

    {
      "links": { ... },
      "segments": [{
        "id": "4815162",
        "href": "https://api.getdrip.com/v2/9999999/segments/4815162",
        "name": "VIP customers",
        "created_at": "2026-01-14T09:22:41Z",
        "updated_at": "2026-08-02T17:05:03Z",
        "derived": {
          "summary": "People who are tagged with \"vip\" and have ordered in the last 90 days"
        },
        "links": { "account": "9999999" }
      }]
    }
    

    derived.summary is a plain-English description of the segment's rules, generated when you read it. It is display text: do not parse it, and expect the wording to change. It is returned here only, not in the list, because generating it walks the segment's rules.

    HTTP Endpoint

    GET /v2/:account_id/segments/:segment_id

    Arguments

    None.

    Subscribers

    Subscribers are represented as follows:

    {
      "id": "z1togz2hcjrkpp5treip",
      "status": "active",
      "email": "[email protected]",
      "first_name": "John",
      "last_name": "Doe",
      "address1": "123 Main St.",
      "address2": "Suite 200",
      "city": "Los Angeles",
      "state": "CA",
      "zip": "90210",
      "country": "US",
      "phone": "555-555-5555",
      "sms_number": "+16125551212",
      "sms_consent": true,
      "eu_consent": "granted",
      "time_zone": "America/Los_Angeles",
      "utc_offset": -440,
      "visitor_uuid": "sa8f7sdf78sdsdahf788d7asf8sd",
      "deliverable": true,
      "custom_fields": {
        "shirt_size": "Medium"
      },
      "tags": ["Customer", "SEO"],
      "ip_address": "111.111.111.11",
      "user_agent": "Chrome/36.0.1985.143",
      "original_referrer": "http://www.getdrip.com",
      "landing_url": "https://www.getdrip.com/docs/rest-api",
      "prospect": true,
      "lead_score": 72,
      "lifetime_value": 10000,
      "created_at": "2013-06-21T10:31:58Z",
      "href": "https://api.getdrip.com/v2/9999999/subscribers/12345",
      "user_id": "12345",
      "base_lead_score": 30,
      "links": {
        "account": "9999999"
      }
    }
    

    All responses containing subscriber data also include the following top-level link data:

    {
      "links": {
        "subscribers.account": "https://api.getdrip.com/v2/accounts/{subscribers.account}"
      }
    }
    

    Note: All subscriber API endpoints only work with your active people. Attempting to modify or delete an inactive person will result in an error.

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each subscriber record.
    status The subscriber's status whether active or unsubscribed.
    initial_status The subscriber's known status whether active or unsubscribed. To be used instead of status if subscriber's status is unchanged.
    email The subscriber's email address.
    first_name The subscriber's first name.
    last_name The subscriber's last name.
    address1 The subscriber's mailing address.
    address2 An additional field for the subscriber's mailing address.
    city The city, town, or village in which the subscriber resides.
    state The region in which the subscriber resides. Typically a province, a state, or a prefecture.
    zip The postal code in which the subscriber resides, also known as zip, postcode, Eircode, etc.
    country The country in which the subscriber resides.
    phone The subscriber's primary phone number.
    sms_number Optional. String. The subscriber's mobile phone number in E.164 formatting. E.g. "+16125551212". Only US-based numbers are supported at this time.
    sms_consent Optional. Boolean. true if the person has granted consent to receive marketing and other communication via SMS; false otherwise. Default: false. If you’re unsure whether or not you have gained legal SMS consent, check out our TCPA requirements article.
    eu_consent A string describing whether the subscriber GDPR consent is granted, denied, or unknown.
    time_zone The subscriber's time zone (in Olson format).
    utc_offset The UTC offset in minutes relative to UTC/GMT.
    visitor_uuid A read-only Drip generated unique id used to identify each subscriber's visitor record if available.
    deliverable Boolean. true if Drip can send email to this subscriber; false if the address has been marked undeliverable (for example, after a hard bounce). Independent of status: an active subscriber may be undeliverable. Read-only; ignored if supplied on create or update.
    custom_fields An Object containing custom field data. E.g. { "shirt_size": "Medium" }.
    tags An Array containing one or more tags. E.g. ["Customer", "SEO"].
    ip_address The subscriber's IP address if available.
    user_agent The subscriber's browser User Agent if available.
    original_referrer The initial referral URL when the subscriber first visited your site if available.
    landing_url The first page visited by the subscriber if available.
    prospect Returns true if the subscriber is marked as a lead.
    lead_score The subscriber's lead score.
    lifetime_value The subscriber's lifetime value in cents.
    created_at A timestamp representing when the subscriber record was first created.
    href The url designated for retrieving the subscriber record via the REST API.
    user_id A unique identifier for the user in your database, such as a primary key.
    base_lead_score An Integer specifying the starting value for lead score calculation for this subscriber. Defaults to 30.
    links An object containing the REST API URL for the account.

    Create or update a subscriber

    To create or update a subscriber:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers" \
    -H 'User-Agent: Your App Name (www.yourapp.com)' \
    -H 'Content-Type: application/json' \
    -u YOUR_API_KEY: \
    -d @- << EOF
    {
      "subscribers": [{
        "email": "[email protected]",
        "time_zone": "America/Los_Angeles",
        "custom_fields": {
          "shirt_size": "Medium"
        }
      }]
    }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_email = "[email protected]"
    options = {
      time_zone: "America/Los_Angeles",
      custom_fields: {
        shirt_size: "Medium"
      }
    }
    
    response = client.create_or_update_subscriber(subscriber_email, options)
    
    if response.success?
      puts response.body["subscribers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const payload = {
      email: "[email protected]",
      time_zone: "America/Los_Angeles",
      custom_fields: {
        shirt_size: "Medium"
      }
    };
    
    client.createUpdateSubscriber(payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The subscribers property is an array of one object.
    {
      "links": { ... },
      "subscribers": [{ ... }]
    }
    

    HTTP Endpoint

    POST /v2/:account_id/subscribers

    If you need to create or update a collection of subscribers at once, use our batch API instead.

    Note: Concurrently updating the same subscriber via multiple API calls is not supported and will fail with a rate limit error and the message "Too many concurrent requests for the same subscriber". You should retry the call after a short wait period to let the other requests to the same subscriber complete. Triggering this rate limit does not mean you've consumed your overall API rate limited capacity.

    Arguments

    Key Description
    email Optional. The subscriber's email address. Either email or id or visitor_uuid must be included.
    id Optional. The subscriber's Drip id. Either email or id or visitor_uuid must be included.
    visitor_uuid Optional. The uuid for a subscriber's visitor record. Either email or id or visitor_uuid must be included.
    new_email Optional. A new email address for the subscriber. If provided and a subscriber with the email above does not exist, this address will be used to create a new subscriber.
    first_name Optional. The subscriber's first name.
    last_name Optional. The subscriber's last name.
    address1 Optional. The subscriber's mailing address.
    address2 Optional. An additional field for the subscriber's mailing address.
    city Optional. The city, town, or village in which the subscriber resides.
    state Optional. The region in which the subscriber resides. Typically a province, a state, or a prefecture.
    zip Optional. The postal code in which the subscriber resides, also known as zip, postcode, Eircode, etc.
    country Optional. The country in which the subscriber resides.
    phone Optional. The subscriber's primary phone number.
    sms_number Optional. String. The subscriber's mobile phone number in E.164 formatting. E.g. "+16125551212". Only US-based numbers are supported at this time.
    sms_consent Optional. Boolean. true if the person has granted consent to receive marketing and other communication via SMS; false otherwise. Default: false. If you’re unsure whether or not you have gained legal SMS consent, check out our TCPA requirements article.
    user_id Optional. A unique identifier for the user in your database, such as a primary key.
    time_zone Optional. The subscriber's time zone (in Olson format). Defaults to Etc/UTC
    lifetime_value Optional. The lifetime value of the subscriber (in cents).
    ip_address Optional. The subscriber's ip address E.g. "111.111.111.11"
    custom_fields Optional. An Object containing custom field data. E.g. { "shirt_size": "Medium" }.
    tags Optional. An Array containing one or more tags. E.g. ["Customer", "SEO"].
    remove_tags Optional. An Array containing one or more tags to be removed from the subscriber. E.g. ["Customer", "SEO"].
    prospect Optional. A Boolean specifiying whether we should attach a lead score to the subscriber (when lead scoring is enabled). Defaults to true. Note: This flag used to be called potential_lead, which we will continue to accept for backwards compatibility.
    base_lead_score Optional. An Integer specifying the starting value for lead score calculation for this subscriber. Defaults to 30.
    eu_consent Optional. A String specifying whether the subscriber granted or denied GDPR consent.
    eu_consent_message Optional. A String containing the message the subscriber granted or denied their consent to.
    status Optional. A String specifying the subscriber's status: either active or unsubscribed.
    initial_status Optional. A String specifying the subscriber's known status: either active or unsubscribed. To be used if subscriber's status is unchanged.

    List all subscribers

    To list subscribers:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.subscribers
    
    if response.success?
      puts response.body["subscribers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const options = { status: "active", subscribed_before: "2017-01-01T00:00:00Z" };
    
    client.listSubscribers(options)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The subscribers property is an array subscriber objects.
    # The meta property contains pagination information.
    {
      "links": { ... },
      "meta": {
        "page": 1,
        "count": 5,
        "total_pages": 1,
        "total_count": 5
      },
      "subscribers": [{ ... }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/subscribers

    Arguments

    Key Description
    status Optional. Filter by one of the following statuses: all, active, unsubscribed, active_or_unsubscribed or undeliverable. Defaults to active.
    tags Optional. A comma separated list of tags. When included, returns only subscribers who have at least one of the listed tags.
    subscribed_before Optional. A ISO-8601 datetime. When included, returns only subscribers who were created before the date. Eg. "2017-01-01T00:00:00Z"
    subscribed_after Optional. A ISO-8601 datetime. When included, returns only subscribers who were created after the date. Eg. "2016-01-01T00:00:00Z"
    page Optional. The page number. Defaults to 1.
    per_page Optional. The number of records to be returned on each page. Defaults to 100. Maximum 1000.

    Fetch a subscriber

    To fetch a subscriber:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/ID_OR_EMAIL_OR_VISITOR_UUID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_email = "[email protected]"
    
    response = client.subscriber(subscriber_email)
    
    if response.success?
      puts response.body["subscribers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const idOrEmail = "[email protected]";
    
    client.fetchSubscriber(idOrEmail)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The subscribers property is an array of one object.
    {
      "links": { ... },
      "subscribers": [{ ... }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/subscribers/:id_or_email_or_visitor_uuid

    Arguments

    None.

    Remove a subscriber from one or all Email Series Campaigns

    To remove a subscriber from all Email Series s:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/ID_OR_EMAIL/remove" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    ##
    # To remove a subscriber from all Email Series Campaigns:
    ##
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_email = "[email protected]"
    response = client.unsubscribe(subscriber_email)
    
    if response.success?
      puts response.body["subscribers"]
    end
    
    ##
    # To remove a subscriber from a specific campaign:
    ##
    
    subscriber_email = "[email protected]"
    options = {
      campaign_id: 9999999
    }
    
    response = client.unsubscribe(subscriber_email, options)
    
    if response.success?
      puts response.body["subscribers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const idOrEmail = "[email protected]";
    const campaignId = 9998888;
    
    client.unsubscribeFromCampaign(idOrEmail, campaignId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    To remove a subscriber from a specific campaign:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/ID_OR_EMAIL/remove?campaign_id=CAMPAIGN_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    

    The response looks like this:

    # The subscribers property is an array of one object.
    {
      "links": { ... },
      "subscribers": [{ ... }]
    }
    

    HTTP Endpoint

    POST /v2/:account_id/subscribers/:id_or_email/remove

    This endpoint was previously labeled unsubscribe.

    Arguments

    Key Description
    campaign_id Optional. The Email Series Campaign from which to remove the subscriber. Defaults to all.

    Unsubscribe from all mailings

    To unsubscribe a subscriber from all mailings:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/ID_OR_EMAIL/unsubscribe_all" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_email = "[email protected]"
    response = client.unsubscribe_from_all(subscriber_email)
    
    if response.success?
      puts response.body["subscribers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const idOrEmail = "[email protected]";
    
    client.unsubscribeFromAllMailings(idOrEmail)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The subscribers property is an array of one object.
    {
      "links": { ... },
      "subscribers": [{ ... }]
    }
    

    HTTP Endpoint

    POST /v2/:account_id/subscribers/:id_or_email/unsubscribe_all

    Arguments

    None.

    Delete a subscriber

    To delete a subscriber:

    curl -X DELETE "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/ID_OR_EMAIL" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_email = "[email protected]"
    response = client.delete_subscriber(subscriber_email)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const idOrEmail = "[email protected]";
    
    client.deleteSubscriber(idOrEmail)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with 204 No Content if successful.

    HTTP Endpoint

    DELETE /v2/:account_id/subscribers/:id_or_email

    Arguments

    None.

    Tags

    List all tags used in an account

    To list all tags:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/tags" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.tags
    
    if response.success?
      puts response.body["tags"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    
    client.listAllTags()
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    {
      "tags": [
        "Customer",
        "SEO"
      ]
    }
    

    Properties

    Property Description
    email The subscriber's email address.
    tag The String tag to apply. E.g. "Customer".

    HTTP Endpoint

    GET /v2/:account_id/tags

    Arguments

    None.

    Apply a tag to a subscriber

    To apply a tag to a specific subscriber:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/tags" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "tags": [{
          "email": "[email protected]",
          "tag": "Customer"
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_email = "[email protected]"
    tag = "Customer"
    
    response = client.apply_tag(subscriber_email, tag)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const payload = {
      tags: [{
        email: "[email protected]",
        tag: "Customer"
      }]
    };
    
    client.tagSubscriber(payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 201 Created and an empty JSON response:

    {}
    

    HTTP Endpoint

    POST /v2/:account_id/tags

    Arguments

    Key Description
    email The subscriber's email address.
    tag The String tag to apply. E.g. "Customer"

    Remove a tag from a subscriber

    To apply a tag to a specific subscriber:

    curl -X DELETE "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/subscribers/ID_OR_EMAIL/tags/TAG" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    subscriber_email = "[email protected]"
    tag = "Customer"
    
    response = client.remove_tag(subscriber_email, tag)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const email = "[email protected]";
    const tag = "Customer";
    
    client.removeSubscriberTag(email, tag)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful.

    HTTP Endpoint

    DELETE /:account_id/subscribers/:email/tags/:tag

    Arguments

    None.

    Users

    Users are represented as follows:

    {
      "email": "[email protected]",
      "name": "John Doe",
      "time_zone": "America/Los_Angeles"
    }
    

    Fetch the authenticated user

    To fetch the current user:

    curl "https://api.getdrip.com/v2/user" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    
    client.fetchUser()
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    {
      "users":[{
        "email": "[email protected]",
        "name": "John Doe",
        "time_zone": "America/Los_Angeles"
      }]
    }
    

    HTTP Endpoint

    GET /v2/user

    Arguments

    None.

    Workflows

    Workflows are represented as follows:

    {
      "id": "123456",
      "href": "https://api.getdrip.com/v2/9999999/workflows/123456",
      "name": "Main Funnel",
      "status": "active",
      "created_at": "2016-07-01T10:00:00Z",
      "links": {
        "account": "9999999"
      }
    }
    

    All responses containing workflow data also include the following top-level link data:

    {
      "links": {
        "workflows.account": "https://api.getdrip.com/v2/accounts/{workflows.account}"
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each workflow record.
    href The url designated for retrieving the workflow record via the REST API.
    name The name assigned to the workflow.
    status The workflow's status whether draft, active, or paused.
    created_at A timestamp representing when the workflow record was first created.
    links An object containing the REST API URL for the account.

    List all workflows

    To list all workflows:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.workflows
    
    if response.success?
      puts response.body["workflows"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const options = { status: "active" };
    
    client.listAllWorkflows(options)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The workflows property is an array of workflow objects.
    {
      "links": { ... },
      "meta": {
        "page": 1,
        "sort": "sort_order",
        "direction": "desc",
        "count": 5,
        "total_pages": 1,
        "total_count": 5,
        "status": "all"
      },
      "workflows": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/workflows

    Arguments

    Key Description
    status Optional. Filter by one of the following statuses: draft, active, or paused. Defaults to all.
    sort Optional. Sort results by one of these fields: created_at or name. Defaults to created_at.
    direction Optional. Filter sort direction with: asc or desc. Defaults to asc.

    Fetch a workflow

    To fetch a workflow:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    response = client.workflow(workflow_id)
    
    if response.success?
      puts response.body["workflows"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    
    client.fetchWorkflow(workflowId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The workflows property is an array of one workflow object.
    {
      "links": { ... },
      "workflows": [{ ... }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/workflows/:workflow_id

    Arguments

    None.

    Fetch a workflow's details

    The details endpoint returns the structure of a single workflow: its entry triggers, its ordered steps, and everything nested beneath its decisions, goals, forks, and split tests. It is read-only.

    Workflows in every visible status are returned, including drafts.

    To fetch a workflow's details:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/details" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/details")
    
    request = Net::HTTP::Get.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/details",
      {
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    The response looks like this (abridged):

    # The workflows property is an array of one workflow object.
    {
      "links": {
        "workflows.account": "https://api.getdrip.com/v2/accounts/{workflows.account}"
      },
      "workflows": [
        {
          "id": "12345",
          "href": "https://api.getdrip.com/v2/9999999/workflows/12345",
          "name": "Welcome series",
          "description": "Onboarding for new trial signups",
          "status": "active",
          "created_at": "2026-01-04T17:22:03Z",
          "updated_at": "2026-07-28T14:02:11Z",
          "node_count": 9,
          "details": {
            "id": "root_1",
            "type": "path",
            "triggers": [
              {
                "id": "0a1b2c3d",
                "type": "trigger",
                "trigger_type": "submitted_form",
                "provider_id": "drip",
                "entry_point": true,
                "status": "active",
                "properties": { "form_id": "185216953", "source": "drip" },
                "incomplete": false,
                "actions_required": [],
                "derived": {
                  "type_name": "Submitted a form or Onsite campaign.",
                  "summary": "Submitted the \"Trial signup\" form",
                  "type_description": "This event is fired when the person submits a form or Onsite campaign.",
                  "segment_description": "people who are tagged with \"trial\""
                }
              }
            ],
            "steps": [
              {
                "id": "4e5f6a7b",
                "type": "action",
                "action_type": "send_email",
                "provider_id": "drip",
                "status": "active",
                "properties": { "automation_email_id": "957660884" },
                "incomplete": false,
                "actions_required": [],
                "email": { "id": "957660884", "subject": "Welcome, {{ subscriber.first_name }}!" },
                "derived": {
                  "type_name": "Send an email to a person",
                  "summary": "Send \"Welcome!\"",
                  "email_title": "Welcome!"
                }
              },
              {
                "id": "8c9d0e1f",
                "type": "delay",
                "delay_type": "wait_for_relative_date",
                "properties": {
                  "duration": 2,
                  "units": "days",
                  "days_of_the_week_mask": "0111110",
                  "minutes_from_midnight": 540,
                  "time_zone": "owner"
                },
                "incomplete": false,
                "derived": { "summary": "Wait 2 days, then resume on the next weekday at 9:00 am" }
              },
              {
                "id": "2a3b4c5d",
                "type": "decision",
                "true_path": {
                  "id": "6e7f8a9b",
                  "type": "path",
                  "triggers": [],
                  "steps": [
                    {
                      "id": "0c1d2e3f",
                      "type": "action",
                      "action_type": "apply_tag",
                      "provider_id": "drip",
                      "status": "active",
                      "properties": { "tag": "vip" },
                      "incomplete": false,
                      "actions_required": [],
                      "derived": { "type_name": "Apply a tag", "summary": "Apply the \"vip\" tag" }
                    }
                  ]
                },
                "false_path": { "id": "4a5b6c7d", "type": "path", "triggers": [], "steps": [] },
                "incomplete": false,
                "actions_required": [],
                "derived": { "summary": "Person is tagged \"engaged\"?" }
              },
              {
                "id": "8e9f0a1b",
                "type": "interrupt",
                "triggers": [ { "id": "2c3d4e5f", "type": "trigger", "...": "..." } ],
                "derived": { "summary": "Waiting for goals" }
              },
              {
                "id": "6a7b8c9d",
                "type": "split_test",
                "properties": { "workflow_split_test_id": "9z8y7x6w" },
                "paths": [
                  { "id": "0e1f2a3b", "type": "split_test_path", "triggers": [], "steps": [] },
                  { "id": "4c5d6e7f", "type": "split_test_path", "triggers": [], "steps": [] }
                ],
                "derived": { "summary": "Began a split test" }
              },
              {
                "id": "3c4d5e6f",
                "type": "exit",
                "derived": { "summary": "Exit the workflow" }
              }
            ]
          },
          "links": { "account": "9999999" }
        }
      ]
    }
    

    Properties

    In addition to the properties every workflow record carries, the details payload includes:

    Property Description
    description The description assigned to the workflow. May be empty.
    node_count The number of nodes in the workflow, counting containers.
    details The root path node, holding the workflow's entry triggers and its ordered steps.

    Nodes

    Every node in the tree carries an id and a type, so one key tells you how to read the rest of the node. Container nodes hold their children under triggers, steps, paths, true_path, or false_path, depending on their type. Branches are objects rather than bare arrays, so an empty branch still has an id.

    Node type Fields derived keys
    path, split_test_path id, type, triggers, steps None
    trigger id, type, trigger_type, provider_id, entry_point, status, properties, incomplete, actions_required type_name, summary, type_description, segment_description
    action id, type, action_type, provider_id, status, properties, incomplete, actions_required, email (send_email only) type_name, summary, email_title
    delay id, type, delay_type, properties, incomplete summary
    decision id, type, true_path, false_path, incomplete, actions_required summary
    fork id, type, paths None
    interrupt id, type, triggers summary
    split_test id, type, properties, paths summary
    exit id, type summary

    An interrupt node is a goal: the triggers beneath it are goal triggers rather than entry triggers, and they carry entry_point: false. A node's status is active or draft.

    New fields may be added to any node at any time. Ignore fields you do not recognize.

    Node configuration

    properties is the node's configuration as stored, and it is present on every trigger, action, delay, and split_test node. Trigger properties are the same object List all workflow triggers returns for the same trigger.

    An empty properties object does not mean the node is unconfigured; incomplete answers that. Several action types, such as activate_person and subscribe, store no fields even when fully configured.

    incomplete is true whenever a node is not fully configured, whether because no type has been chosen, because the node is blocked, or because it carries any actions_required. A decision whose criteria have not been set is incomplete in the same way. actions_required lists what is missing, as an array of { "code": ..., "message": ... } objects, in the same shape List all workflow triggers returns.

    Some configuration is never published. A drip/http_post action responds with an empty properties object and no derived.summary, because its endpoint URL and request headers are credentials; only derived.type_name survives. Raw segmentation criteria, provider credentials, and editor layout data are not published on any node.

    A send_email action whose email exists also carries an email object with the email's id and subject. email.id is the email's public id: pass it to Fetch a workflow email for the preheader and full HTML and text bodies. Use email.id rather than properties.automation_email_id, which is published as stored and may hold a legacy id that Fetch a workflow email does not accept. The subject is as stored, with any Liquid tags verbatim, and is null or empty on a draft whose subject has not been written.

    Derived text

    Human-readable text lives in a derived object, separate from properties. Everything in derived is generated when the response is built and is not part of the workflow's stored definition.

    Key Description
    summary What this particular node does. E.g. Send "Welcome!".
    type_name The display name of the node's type. Triggers and actions only.
    type_description What the node's type means in general. Triggers only.
    segment_description The humanized entry criteria for the trigger. Triggers only.
    email_title The title of the email the node sends. send_email actions only.

    Any key is omitted when it has no value, and a node with no text at all carries no derived object. Because these strings are built from the records the node refers to, a derived value can change when some other record is renamed, with no edit to the workflow itself. Use properties and the type fields for anything you parse.

    Joining to email metrics

    A node's id holds the same value the Metrics endpoint returns as workflow_placement.node_id, so joining details node id to workflow_placement.node_id lines the structure up with per-email performance. The two endpoints spell the field differently; the values are identical.

    A node id is stable for the life of the workflow record. Copying a workflow regenerates every node id, so ids do not carry across a copy.

    Caching

    If the response has not changed, responds with a 304 Not Modified and an empty body:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/details" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -H 'If-None-Match: "a1b2c3d4e5f6"' \
      -u YOUR_API_KEY:
    

    Responses carry an ETag covering every field of the response. Send it back as If-None-Match to get a 304 Not Modified when none of those fields has changed.

    The ETag describes this view of the workflow rather than the workflow's stored definition, so it is a cache validator only. Two workflows that differ solely in fields this endpoint withholds share an ETag, and a change confined to a withheld field does not invalidate one.

    Rate limits

    If the rate limit is exceeded, responds with a 429 Too Many Requests and a Retry-After header of 3600:

    {
      "errors": [{
        "code": "rate_limit_exceeded",
        "message": "Rate limit exceeded: at most 2000 requests per account per hour."
      }]
    }
    

    Fetching a workflow's details has its own rate limit of 2,000 requests per account per hour, in addition to the general rate limit. The limit counts requests in fixed one-hour windows, and Retry-After is always the full hour (3600 seconds), not the time left in the current window. Fetch a workflow email has only the general rate limit.

    HTTP Endpoint

    GET /v2/:account_id/workflows/:workflow_id/details

    Arguments

    None.

    Fetch a workflow email

    Returns one email a workflow sends: its subject, preheader, and full HTML and text bodies, along with its name, builder type, and sender. It is read-only.

    The email is identified by its public id, the email.id a send_email action carries in Fetch a workflow's details. An email is returned only through a workflow with a send_email step that names it.

    To fetch a workflow email:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/emails/WORKFLOW_EMAIL_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require "net/http"
    require "json"
    
    uri = URI("https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/emails/WORKFLOW_EMAIL_ID")
    
    request = Net::HTTP::Get.new(uri)
    request.basic_auth("YOUR_API_KEY", "")
    request["User-Agent"] = "Your App Name (www.yourapp.com)"
    
    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end
    
    puts response.body
    
    const response = await fetch(
      "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/emails/WORKFLOW_EMAIL_ID",
      {
        headers: {
          "User-Agent": "Your App Name (www.yourapp.com)",
          "Authorization": "Basic " + Buffer.from("YOUR_API_KEY:").toString("base64")
        }
      }
    );
    
    const body = await response.json();
    

    The response looks like this:

    # The emails property is an array of one email object.
    {
      "links": {
        "emails.account": "https://api.getdrip.com/v2/accounts/{emails.account}",
        "emails.workflow": "https://api.getdrip.com/v2/{emails.account}/workflows/{emails.workflow}"
      },
      "emails": [
        {
          "id": "957660884",
          "href": "https://api.getdrip.com/v2/9999999/workflows/12345/emails/957660884",
          "node_id": "4e5f6a7b",
          "email_id": 4455661,
          "name": "Welcome!",
          "builder_type": "text",
          "from_name": "John Doe",
          "from_email": "[email protected]",
          "reply_to": "[email protected]",
          "subject": "Welcome, {{ subscriber.first_name }}!",
          "preheader": "Here's how to get started",
          "html_body": "<p>Hi {{ subscriber.first_name }},</p>{% if subscriber.tags contains 'vip' %}<p>Thanks for being a VIP.</p>{% endif %}",
          "text_body": "Hi {{ subscriber.first_name }},",
          "created_at": "2026-01-04T17:22:03Z",
          "updated_at": "2026-07-28T14:02:11Z",
          "links": {
            "account": "9999999",
            "workflow": "12345"
          }
        }
      ]
    }
    

    Properties

    Property Description
    id The email's public id. The same value as email.id on the send_email action that sends it.
    href The url designated for retrieving the email via the REST API.
    node_id The id of the send_email node in Fetch a workflow's details that sends the email.
    email_id The value the Metrics endpoint returns as email_id for this email, so it joins the email to its performance. Not the id this endpoint takes; use id.
    name The name assigned to the email.
    builder_type The editor the email was built with, whether text or visual (the Visual Email Builder).
    from_name The From name set on the email. May be null.
    from_email The address the email is sent from: its own From address, or the account's default From address if it has none. May be null.
    reply_to The Reply-To address set on the email. May be null, in which case replies go to the From address.
    subject The subject line.
    preheader The preheader text.
    html_body The HTML body. For a Visual Email Builder email, this is the full generated HTML; for other emails, it is the body only, without the account's email template or footer.
    text_body The plain text body.
    created_at A timestamp representing when the email record was first created.
    updated_at A timestamp representing when the email record was last updated.
    links An object containing the ids of the account and the workflow.

    Content is returned as stored, as it is for Single-Email Campaigns: Liquid tags such as {{ subscriber.first_name }} and {% if %} blocks appear verbatim and are not rendered for any subscriber. subject, preheader, and the bodies may be null or empty when not yet written, as on a draft email.

    New fields may be added at any time. Ignore fields you do not recognize.

    Not found

    If no send_email step in the workflow names the email, responds with a 404 Not Found:

    {
      "errors": [{
        "code": "not_found_error",
        "message": "This workflow has no send-email step for that email id. Use the email's public id: the `email.id` of a send_email action in GET /v2/:account_id/workflows/:workflow_id/details."
      }]
    }
    

    The same 404 is returned for the id of a Single-Email Campaign, of an Email Series Campaign email, or of an email sent by a rule or a form, or an old id from properties.automation_email_id: only the public id in email.id is accepted. A workflow that does not exist or is archived responds with the standard 404 Not Found described in Errors.

    HTTP Endpoint

    GET /v2/:account_id/workflows/:workflow_id/emails/:workflow_email_id

    Arguments

    None.

    Activate a workflow

    To activate a workflow:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/activate" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    response = client.activate_workflow(workflow_id)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    
    client.activateWorkflow(workflowId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful.

    HTTP Endpoint

    POST /v2/:account_id/workflows/:workflow_id/activate

    Arguments

    None.

    Pause a workflow

    To pause a workflow:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/pause" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    response = client.pause_workflow(workflow_id)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    
    client.pauseWorkflow(workflowId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful.

    HTTP Endpoint

    POST /v2/:account_id/workflows/:workflow_id/pause

    Arguments

    None.

    Start someone on a workflow

    To start a someone on a workflow:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/subscribers" \
      -H "Content-Type: application/json" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "subscribers": [{
          "email": "[email protected]",
          "time_zone": "America/Los_Angeles",
          "custom_fields": {
            "shirt_size": "Medium"
          }
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    options = {
      email: "[email protected]",
      time_zone: "America/Los_Angeles",
      custom_fields: {
        shirt_size: "Medium"
      }
    }
    response = client.start_subscriber_workflow(workflow_id, options)
    
    if response.success?
      puts response.body["subscribers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    const payload = {
      subscribers: [{
        email: "[email protected]",
        time_zone: "America/Los_Angeles",
        custom_fields: {
          shirt_size: "Medium"
        }
      }]
    }
    
    client.startOnWorkflow(workflowId, payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The subscribers property is an array of one object.
    {
      "links": { ... },
      "subscribers": [{ ... }]
    }
    

    If the workflow is not active, the subscriber will not be added to the workflow.

    HTTP Endpoint

    POST /v2/:account_id/workflows/:workflow_id/subscribers

    Arguments

    Key Description
    email Optional. The subscriber's email address. Either email or id must be included.
    id Optional. The subscriber's Drip id. Either email or id must be included.
    first_name Optional. The subscriber's first name.
    last_name Optional. The subscriber's last name.
    address1 Optional. The subscriber's mailing address.
    address2 Optional. An additional field for the subscriber's mailing address.
    city Optional. The city, town, or village in which the subscriber resides.
    state Optional. The region in which the subscriber resides. Typically a province, a state, or a prefecture.
    zip Optional. The postal code in which the subscriber resides, also known as zip, postcode, Eircode, etc.
    country Optional. The country in which the subscriber resides.
    phone Optional. The subscriber's primary phone number.
    user_id Optional. A unique identifier for the user in your database, such as a primary key.
    time_zone Optional. The subscriber's time zone (in Olson format). Defaults to Etc/UTC
    custom_fields Optional. An Object containing custom field data. E.g. { "shirt_size": "Medium" }.
    tags Optional. An Array containing one or more tags. E.g. ["Customer", "SEO"].
    prospect Optional. A Boolean specifiying whether we should attach a lead score to the subscriber (when lead scoring is enabled). Defaults to true. Note: This flag used to be called potential_lead, which we will continue to accept for backwards compatibility.
    eu_consent Optional. A String specifying whether the subscriber granted or denied GDPR consent.
    eu_consent_message Optional. A String containing the message the subscriber granted or denied their consent to.

    Remove a subscriber from a workflow

    To remove someone from a workflow:

    curl -X DELETE "https://v2/api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/subscribers/ID_OR_EMAIL" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    subscriber_email = "[email protected]"
    
    response = client.remove_subscriber_workflow(workflow_id, subscriber_email)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    const idOrEmail = "[email protected]"
    
    client.removeFromWorkflow(workflowId, idOrEmail)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful.

    If the subscriber is not already on the workflow, nothing will happen.

    HTTP Endpoint

    DELETE /v2/:account_id/workflows/:workflow_id/subscribers/:id_or_email

    Arguments

    None.

    List all workflow triggers

    To list all triggers on a workflow:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/triggers" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    response = client.workflow_triggers(workflow_id)
    
    if response.success?
      puts response.body["triggers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    
    client.listTriggers(workflowId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    {
      "triggers": [
        {
          "id": "f7gysdf7gyd7",
          "type": "trigger",
          "trigger_type": "submitted_landing_page",
          "provider": "leadpages",
          "properties": {
            "landing_page": "My Landing Page"
          },
          "actions_required": [
            {
              "code": "configure_provider",
              "message": "Configure your LeadPages connection"
            }
          ]
        }
      ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/workflows/:workflow_id/triggers

    Arguments

    None.

    Create a workflow trigger

    To create a workflow trigger:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/triggers" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "triggers": [
          {
            "provider": "leadpages",
            "trigger_type": "submitted_landing_page",
            "properties": {
              "landing_page": "My Landing Page"
            }
          }
        ]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    options = {
      provider: "leadpages",
      trigger_type: "submitted_landing_page",
      properties: {
        landing_page: "My Landing Page"
      }
    }
    response = client.create_workflow_trigger(workflow_id, options)
    
    if response.success?
      puts response.body["triggers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    const payload = {
      provider: "leadpages",
      trigger_type: "submitted_landing_page",
      properties: {
        landing_page: "My Landing Page"
      }
    }
    
    client.createTrigger(workflowId, payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    {
      "triggers": [
        {
          "id": "f7gysdf7gyd7",
          "type": "trigger",
          "provider": "leadpages",
          "trigger_type": "submitted_landing_page",
          "properties": {
            "landing_page": "My Landing Page"
          },
          "actions_required": [
            {
              "code": "configure_provider",
              "message": "Configure your LeadPages connection"
            }
          ]
        }
      ]
    }
    

    HTTP Endpoint

    POST /v2/:account_id/workflows/:workflow_id/triggers

    Arguments

    Key Description
    provider Required. A String indicating a provider.
    trigger_type Required. A String indicating the automation trigger type.
    properties Optional. An Object containing properties for the given trigger.

    Update a workflow trigger

    To update a workflow trigger:

    curl -X PUT "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/workflows/WORKFLOW_ID/triggers/TRIGGER_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "triggers": [
          {
            "provider": "leadpages",
            "trigger_type": "submitted_landing_page",
            "properties": {
              "landing_page": "My Landing Page"
            }
          }
        ]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    workflow_id = 9999999
    options = {
      provider: "leadpages",
      trigger_type: "submitted_landing_page",
      properties: {
        landing_page: "My Landing Page"
      }
    }
    response = client.update_workflow_trigger(workflow_id, options)
    
    if response.success?
      puts response.body["triggers"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const workflowId = 222333;
    const triggerId = "abc123";
    const payload = {
      provider: "leadpages",
      trigger_type: "submitted_landing_page",
      properties: {
        landing_page: "My Landing Page"
      }
    }
    
    client.updateTrigger(workflowId, triggerId, payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    {
      "triggers": [
        {
          "id": "f7gysdf7gyd7",
          "type": "trigger",
          "provider": "leadpages",
          "trigger_type": "submitted_landing_page",
          "properties": {
            "landing_page": "My Landing Page"
          },
          "actions_required": [
            {
              "code": "configure_provider",
              "message": "Configure your LeadPages connection"
            }
          ]
        }
      ]
    }
    

    HTTP Endpoint

    PUT /v2/:account_id/workflows/:workflow_id/triggers/:trigger_id

    Arguments

    Key Description
    provider Required. A String indicating a provider.
    trigger_type Required. A String indicating the automation trigger type.
    properties Optional. An Object containing properties for the given trigger.

    Webhooks

    Webhooks are represented as follows:

    {
      "id": "77777",
      "href": "https://api.getdrip.com/v2/9999999/webhooks/77777",
      "post_url": "http://www.mysite.com/my-webhook-endpoint",
      "version": "1",
      "include_received_email": false,
      "events": [
        "subscriber.created",
        "subscriber.subscribed_to_campaign"
      ],
      "created_at": "2013-06-21T10:31:58Z",
      "links": {
        "account": "9999999",
      }
    }
    

    All responses containing webhook data also include the following top-level link data:

    {
      "links": {
        "webhooks.account": "https://api.getdrip.com/v2/accounts/{webhooks.account}"
      }
    }
    

    Properties

    Property Description
    id A read-only Drip generated unique id used to identify each webhook record.
    href The url designated for retrieving the webhook record via the REST API.
    post_url The url that the webhook will post to.
    version The webhook version. The current stable version is 2.
    include_received_email Returns true if a notification is sent whenever a subscriber receives an email.
    created_at A timestamp representing when the webhook record was first created.
    events An array specifying which events are enabled for webhook notifications.
    links An object containing the REST API URL for the account.

    List all webhooks

    To list all webhooks in an account:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/webhooks" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    response = client.webhooks
    
    if response.success?
      puts response.body["webhooks"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    
    client.listWebhooks()
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The webhooks property is an array of webhook objects.
    {
      "links": { ... },
      "webhooks": [ ... ]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/webhooks

    Arguments

    None.

    Fetch a webhook

    To fetch a specific webhook:

    curl "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/webhooks/WEBHOOK_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    webhook_id = 999999
    response = client.webhook(webhook_id)
    
    if response.success?
      puts response.body["webhooks"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const webhookId = 111222;
    
    client.fetchWebhook(webhookId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    The response looks like this:

    # The webhooks property is an array of one webhook object.
    {
      "links": { ... },
      "webhooks": [{ ... }]
    }
    

    HTTP Endpoint

    GET /v2/:account_id/webhooks/:webhook_id

    Arguments

    None.

    Create a new webhook

    To create a webhook:

    curl -X POST "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/webhooks" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY: \
      -d @- << EOF
      {
        "webhooks": [{
          "post_url": "http://www.mysite.com/my-webhook-endpoint",
          "events": [
            "subscriber.created",
            "subscriber.subscribed_to_campaign"
          ]
        }]
      }
    EOF
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    pot_url = "https://www.mylistener.com/receieve"
    include_received_email = false
    events = [
      "subscriber.created",
      "subscriber.subscribed_to_campaign"
    ]
    
    response = client.create_webhook(post_url, include_received_email, events)
    
    if response.success?
      puts response.body["webhooks"]
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const payload = {
      webhooks: [{
        post_url: "http://www.mysite.com/my-webhook-endpoint",
        events: [
          "subscriber.created",
          "subscriber.subscribed_to_campaign"
        ]
      }]
    }
    
    client.createWebhook(payload)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 201 Created like this:

    {
      "links": { ... },
      "webhooks": [{
        "id": "77777",
        "href": "https://api.getdrip.com/v2/9999999/webhooks/77777",
        "post_url": "http://www.example.com/api/v2/form",
        "version": "1",
        "include_received_email": false,
        "events": [
          "subscriber.created",
          "subscriber.subscribed_to_campaign"
        ],
        "created_at": "2013-06-21T10:31:58Z",
        "links": {
          "account": "9999999",
        }
      }]
    }
    

    HTTP Endpoint

    POST /v2/:account_id/webhooks

    Arguments

    Key Description
    post_url The url that the webhook will post to.
    include_received_email Optional. A Boolean specifying whether we should send a notification whenever a subscriber receives an email. Defaults to false.
    events Optional. An Array specifiying which events we should send notifications for. Eligible events can be found in the webhooks documentation. By default, we will send notifications for all events except subscrber.received_email.

    Destroy a webhook

    To destroy an existing webhook:

    curl -X DELETE "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/webhooks/WEBHOOK_ID" \
      -H 'User-Agent: Your App Name (www.yourapp.com)' \
      -u YOUR_API_KEY:
    
    require 'drip'
    
    client = Drip::Client.new do |c|
      c.api_key = "YOUR API KEY"
      c.account_id = "YOUR_ACCOUNT_ID"
    end
    
    webhook_id = 999999
    response = client.delete_webhook(webhook_id)
    
    if response.success?
      # ...
    end
    
    // npm install drip-nodejs --save
    
    const client = require('drip-nodejs')({ token: YOUR_API_KEY, accountId: YOUR_ACCOUNT_ID });
    const webhookId = 111222;
    
    client.destroyWebhook(webhookId)
      .then((response) => {
        // Handle `response.body`
      })
      .catch((error) => {
        // Handle errors
      });
    

    Responds with a 204 No Content if successful.

    HTTP Endpoint

    DELETE /v2/:account_id/webhooks/:webhook_id

    Arguments

    None.

    Webhook Events

    Webhooks allow you to receive an HTTP POST to the URL(s) of your choosing anytime certain events occur in your Drip account. All our webhook events contain data serialized as JSON. If you'd like to be notified (with data) everytime a visitor subscribes, you'll want to use webhooks.

    Setting Up

    Adding a webhook URL is dead simple. Head over the Webhooks settings page, enter your URL, and hit "Create Webhook". That's it!

    Because of the potential for high volume, we will not send notifications for subscriber.received_email events by default. To receive a post every time a subscriber receives an email, enable these events using the checkbox on the webhook's settings.

    Please note that some webhook endpoints may implement rate limiting, especially for entry-level or free accounts. We will attempt to re-send webhooks for up to 3 days if they are rate limited. In addition, you will be notified and your webhook will be temporarily disabled if its endpoint generates any other error for 3 days.

    Resources

    Subscriber

    {
      "id": "z1togz2hcjrkpp5treip",
      "status": "active",
      "deliverable": true,
      "email": "[email protected]",
      "custom_fields": {
        "shirt_size": "Medium"
      },
      "tags": ["Customer", "SEO"],
      "time_zone": "America/Los_Angeles",
      "utc_offset": -440,
      "created_at": "2013-06-21T10:31:58Z"

    [Page truncated to keep GeezerVison snappy.]

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.