Scheduled Tweets

Introduction

Scheduled Tweets allow an advertiser or user to create a Tweet that can be scheduled to go live at a later date. In addition to being able create and manage these Tweets, the API allows the ability to associate these Tweets with a line item, to be promoted once the Tweet goes live. This allows advertisers to stage create native Tweets and plan their campaign creatives in advance of any key initiatives. For example, staging a Tweet creative to live immediately upon a new product announcement.

The full set of functionality provided by the Scheduled Tweets API endpoints are listed below:

  • Create, modify and view newly scheduled Tweets
  • Associate a Scheduled Tweet with a line item
  • Query and manage existing scheduled Tweets
  • Once a Scheduled Tweet goes live, retrieve the live Tweet id

API Endpoints

The entire set of endpoints related to the above functionality is listed below:

Scheduled Tweet Management

Scheduled Promoted Tweets

Scheduled Tweet View

Due to the nature of Scheduled Tweets being separate entities from “live” Tweets, there are two different sets of validations run on any creates or edits to these Tweets. The first set of validation rules are run during the Scheduled Tweet creation step, specifically:

Scheduled Tweet Create:

  • Validate that the authenticated user has access to create organic Tweets for a given @handle Promoted-Only Tweet create privileges requires authenticated user to be an account user with Tweet composer permissions
  • Validate that there are no more than 30 Tweets that are scheduled to be created within a 15 minute window of the scheduled_at time. A SCHEDULED_TWEET_LIMIT_EXCEEDED error message indicates that too many Scheduled Tweets have been scheduled within the same future, 15 minute time frame.  Advertisers will need to remove an existing Scheduled Tweet or move the scheduled_at time earlier or later.

Scheduled Tweet goes "live":

  • These validation rules are run at the scheduled_at time and are identical to those applied on regular Tweet creation in the API. For example, a Scheduled Tweet will not go live and the scheduled_status will be set to FAILED if the Scheduled Tweet contains both an image and a gif

Workflow

Create a new Scheduled Tweet

A new Scheduled Tweet can be created using the POST accounts/:account_id/scheduled_tweets endpoint. This endpoint has the following required parameters, scheduled_at time along with the Tweet text if no media entities are included in the Tweet. In addition, this endpoint provides a few additional options that allow you to create a scheduled Tweet on behalf of another @handle via the as_user_id param along with the ability to add a card (card_uri) and any media (media_ids). Note, a Tweet can only contain entities of the same type, i.e., either Video, Gif or Image. The nullcast param controls whether the Tweet is a “Promoted-Only” Tweet or not. All newly created Scheduled Tweets are "Promoted-Only" (nullcast=true) by default. If nullcast=false then an Organic Scheduled Tweet is created

Once a Scheduled Tweet is successfully created, the response will contain an id field, which refers to the unique identifier of the Scheduled Tweet itself. In addition to this field, another field called tweet_id is also returned. This field is null initially, however once the Tweet goes live this field is populated with the ID of the “live” Tweet.

twurl -H 'ads-api.twitter.com' -X POST "/6/accounts/:account_id/scheduled_tweets" -d 'scheduled_at=2017-12-24T23:59:00Z&text=Happy Holidays!'

This will create the following Scheduled Tweet:

{
  "request": {
    "params": {
      "text": "Happy Holidays!",
      "scheduled_at": "2017-12-24T23:59:00Z"
    }
  },
  "data": {
    "completed_at": null,
    "id_str": "917507899668099072",
    "text": "Happy Holidays!",
    "user_id": "3271358660",
    "scheduled_status": "SCHEDULED",
    "id": 917507899668099100,
    "media_ids": [],
    "nullcast": true,
    "created_at": "2017-10-09T21:51:44Z",
    "scheduled_at": "2017-12-24T23:59:00Z",
    "card_uri": null,
    "updated_at": "2017-10-09T21:51:44Z",
    "tweet_id": null,
    "media_keys": []
  }
}

Once this Scheduled Tweet goes live, the tweet_id field will be populated with the "live" Tweet's ID.

View a Scheduled Tweet

The GET accounts/:account_id/scheduled_tweets/preview/:scheduled_tweet_id endpoint can then be used with the Scheduled Tweet id from the previous step to generate a preview of the Tweet, for mutiple platforms, i.e., Android, iOS and Desktop. The API response will contain the preview HTML that is ready to be used to render a preview for the Scheduled Tweet. The relevant CSS and images will be served directly via Twitter.

twurl -H ads-api.twitter.com -X GET "/6/accounts/:account_id/scheduled_tweets/preview/917507899668099072

{
  "request": {
    "params": {
      "scheduled_tweet_id": 917507899668099100
    }
  },
  "data": [
    {
      "platform": "web",
      "preview": "<!DOCTYPE html> <html> <head>   <meta charset=\"utf-8\" />      <link href=\"https://ton.twimg.com/macaw-campaigns/css/tweet_preview.bundle.76e12b712eba64893586.css\" rel=\"stylesheet\" /> </head>  <body>       <div class=\"Tweet--timeline   Tweet   Tweet--web          \"  data-tweet-id=\"917507899668099072\">    <img class=\"Tweet-avatar\" src=\"https://pbs.twimg.com/profile_images/618551153131786241/g-MIydXB_normal.jpg\" width=\"48\" height=\"48\" alt=\"\"/>    <div class=\"Tweet-body\">     <div class=\"Tweet-header\">       <div class=\"Tweet-userData\">         <a href=\"https://twitter.com/imit8me\" target=\"_blank\" class=\"Tweet-userLink\">           <span class=\"Tweet-name\">Tushar Bhushan</span>                            <span class=\"Tweet-screenName\">@imit8me</span>         </a>       </div>         <span class=\"Tweet-timeLabel\">         <span class=\"Tweet-timestamp\">           <span class=\"Icon Icon--clock\"></span>           Dec 24         </span>       </span>     </div>         <div class=\"Tweet-text \" dir=\"\">Happy Holidays!</div>        </div>     <div class=\"Tweet-footer\">         <div class=\"Tweet-actions \">   <button class=\"Tweet-action Tweet-action--reply\" type=\"button\">     <span class=\"Icon Icon--reply\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--retweet\" type=\"button\">     <span class=\"Icon Icon--retweet\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--favorite Tweet-action--like\" type=\"button\">     <span class=\"Icon Icon--heart\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--dm\" type=\"button\">     <span class=\"Icon Icon--dm\"></span>   </button> </div>             <div class=\"Tweet-context Tweet-context--promotion\">   <div class=\"Tweet-badge Tweet-badge--promotedBy\">      <span class=\"Icon Icon--promoted\"></span>      <span class=\"Tweet-badgeText\">Promoted</span>   </div> </div>    </div> </div>   </body> </html> "
    },
    {
      "platform": "android",
      "preview": "<!DOCTYPE html> <html> <head>   <meta charset=\"utf-8\" />      <link href=\"https://ton.twimg.com/macaw-campaigns/css/tweet_preview.bundle.76e12b712eba64893586.css\" rel=\"stylesheet\" /> </head>  <body>       <div class=\"Tweet--timeline   Tweet   Tweet--android          \"  data-tweet-id=\"917507899668099072\">    <img class=\"Tweet-avatar\" src=\"https://pbs.twimg.com/profile_images/618551153131786241/g-MIydXB_normal.jpg\" width=\"48\" height=\"48\" alt=\"\"/>    <div class=\"Tweet-body\">     <div class=\"Tweet-header\">       <div class=\"Tweet-userData\">         <a href=\"https://twitter.com/imit8me\" target=\"_blank\" class=\"Tweet-userLink\">           <span class=\"Tweet-name\">Tushar Bhushan</span>                            <span class=\"Tweet-screenName\">@imit8me</span>         </a>       </div>         <span class=\"Tweet-timeLabel\">         <span class=\"Tweet-timestamp\">           <span class=\"Icon Icon--clock\"></span>           Dec 24         </span>       </span>     </div>         <div class=\"Tweet-text \" dir=\"\">Happy Holidays!</div>        </div>     <div class=\"Tweet-footer\">         <div class=\"Tweet-actions \">   <button class=\"Tweet-action Tweet-action--reply\" type=\"button\">     <span class=\"Icon Icon--reply\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--retweet\" type=\"button\">     <span class=\"Icon Icon--retweet\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--favorite Tweet-action--like\" type=\"button\">     <span class=\"Icon Icon--heart\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--dm\" type=\"button\">     <span class=\"Icon Icon--dm\"></span>   </button> </div>             <div class=\"Tweet-context Tweet-context--promotion\">   <div class=\"Tweet-badge Tweet-badge--promotedBy\">      <span class=\"Icon Icon--promoted\"></span>      <span class=\"Tweet-badgeText\">Promoted</span>   </div> </div>    </div> </div>   </body> </html> "
    },
    {
      "platform": "iphone",
      "preview": "<!DOCTYPE html> <html> <head>   <meta charset=\"utf-8\" />      <link href=\"https://ton.twimg.com/macaw-campaigns/css/tweet_preview.bundle.76e12b712eba64893586.css\" rel=\"stylesheet\" /> </head>  <body>       <div class=\"Tweet--timeline   Tweet   Tweet--iphone          \"  data-tweet-id=\"917507899668099072\">    <img class=\"Tweet-avatar\" src=\"https://pbs.twimg.com/profile_images/618551153131786241/g-MIydXB_normal.jpg\" width=\"48\" height=\"48\" alt=\"\"/>    <div class=\"Tweet-body\">     <div class=\"Tweet-header\">       <div class=\"Tweet-userData\">         <a href=\"https://twitter.com/imit8me\" target=\"_blank\" class=\"Tweet-userLink\">           <span class=\"Tweet-name\">Tushar Bhushan</span>                            <span class=\"Tweet-screenName\">@imit8me</span>         </a>       </div>         <span class=\"Tweet-timeLabel\">         <span class=\"Tweet-timestamp\">           <span class=\"Icon Icon--clock\"></span>           Dec 24         </span>       </span>     </div>         <div class=\"Tweet-text \" dir=\"\">Happy Holidays!</div>        </div>     <div class=\"Tweet-footer\">         <div class=\"Tweet-actions \">   <button class=\"Tweet-action Tweet-action--reply\" type=\"button\">     <span class=\"Icon Icon--reply\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--retweet\" type=\"button\">     <span class=\"Icon Icon--retweet\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--favorite Tweet-action--like\" type=\"button\">     <span class=\"Icon Icon--heart\"></span>     <span class=\"Tweet-actionCount\">##</span>   </button>   <button class=\"Tweet-action Tweet-action--dm\" type=\"button\">     <span class=\"Icon Icon--dm\"></span>   </button> </div>             <div class=\"Tweet-context Tweet-context--promotion\">   <div class=\"Tweet-badge Tweet-badge--promotedBy\">      <span class=\"Icon Icon--promoted\"></span>      <span class=\"Tweet-badgeText\">Promoted</span>   </div> </div>    </div> </div>   </body> </html> "
    }
  ]
}
Happy Holidays!

A sample view of the newly created Scheduled Tweet is shown above

Associate a Scheduled Tweet with a line item

While Scheduled Tweets can be used to create Organic Tweets, we also allow partners to create a “Promoted-Only” (nullcast=true) Tweet either one of which can be associated with a line item. In order to facilitate this, we provide a POST accounts/:account_id/scheduled_promoted_tweets endpoint as well. This endpoint only allows a single Promoted Scheduled Tweet to be associated with a line item in a single API call. In order to associate multiple Scheduled Tweets to the same line item, multiple API calls are necessary.

Please note that it is not possible to modify an existing Scheduled Promoted Tweet.

twurl -H 'ads-api.twitter.com' -X POST "/6/accounts/:account_id/scheduled_promoted_tweets" -d 'line_item_id=a44qc&scheduled_tweet_id=917507899668099072'

{
  "data": {
    "line_item_id": "a44qc",
    "id": "26576",
    "created_at": "2017-10-09T22:24:16Z",
    "updated_at": "2017-10-09T22:24:16Z",
    "scheduled_tweet_id": "917507899668099072",
    "tweet_id": null,
    "deleted": false
  },
  "request": {
    "params": {
      "line_item_id": "a44qc",
      "scheduled_tweet_id": 917507899668099100,
      "account_id": "aaaaa"
    }
  }
}

This endpoint only creates an association between a given Scheduled Tweet and a line item. Once the campaign/line item flight dates are current, the line item with automatically start serving the corresponding “live” Tweet. While we do validate during this step that the Scheduled Tweet is in the SCHEDULED state, and that the given Scheduled Tweet is valid for the given objective, no other validations are run. Any remaining validation rules that apply to the line item and Scheduled Tweet are run when the Tweet goes “live”

In order to ensure that there are no issues with campaign serving it is recommend that the Scheduled Tweet be scheduled_at a time prior to the campaign/line item flight dates.

For example, let's say the Scheduled Tweet is set to go live after the campaign start date (and that there is only a single Tweet associated with a single line item), then the campaign will be ACTIVE, however given that the Scheduled Tweet is not live yet, there will be no creatives available for serving.

Scheduled Tweet Management

The remaining sets of endpoints allow API consumers to manage all their Scheduled Tweets and Scheduled Promoted Tweets. These APIs can be used to either return a list of all Scheduled Tweets optionally filtered by a given state as well as lookup a given Scheduled Tweet by its id.

What happens when a Scheduled Tweet goes live?

Once a given Scheduled Tweet is about to go live, or in other words at the scheduled_at time, the following updates are made:

  • The “live” Tweet is created however this may have a latency of upto 1 second
  • The tweet_id is added to the following entities:
    • Scheduled Tweet
    • Promoted Scheduled Tweet
  • A new Promoted Tweet entity is created

Best Practices

The following best practices are recommended when creating or promoting Scheduled Tweets:

  • Ensure that the Tweet is valid when creating the Scheduled Tweet (for example, a Tweet can only have either an Image, Video or Gif and not any combination of the three)
  • Ensure that the campaign flight dates (i.e., the start_time and end_time) align with the scheduled_at time for the Scheduled Tweet
  • Scheduled Tweets should not be scheduled for more than one year in the future (365 days)
  • Tweet preview is currently not supported for Scheduled Tweets (this is ability to preview Scheduled Tweets prior to creation)