TON Upload

The TON (Twitter Object Nest) API allows implementers to upload media and various assets to Twitter. In this document we will cover authentication & authorization, usage, principles, and provide examples to get started.

Please consult with your Platform Relations representative or Ads API Partner Engineer on details specific to your integration; the below information may not be true for your integration. This document covers upload only. The TON API supports other operations but they are not covered in this document, as they are not needed for the upload API.

Authentication & Authorization

The TON API requires 3-legged authorization

Usage

The TON API supports non-resumable and resumable upload methods based on the size of the file. For files less than 64MB, non-resumable may be used. For files greater than or equal to 64MB, resumable must be used. Resumable uploads require chunk sizes of less than 64MB. Calculation of 64MB is based on 1024 bytes (64 * 1024 * 1024).

If your dedicated upload bandwidth for the TON Upload is less than ~20 Mbit/s we recommend using resumable upload even for files less than 64MB in size.

Principles

  • The endpoint for the TON API is ton.twitter.com
  • All requests must be made over HTTPS
  • All responses are in JSON
  • The Content-Type of your request cannot be "application/x-www-form-urlencoded"
  • The Content-Type of your request will be a valid media type as defined by IANA: http://www.iana.org/assignments/media-types/media-types.xhtml
  • Chunks should be in integer multiples of x-ton-min-chunk-size (except the last).
  • The location header after upload should be saved to be used in subsequent Twitter APIs, such as the Video API.

Buckets

For Tailored Audiences, please use the bucket name ta_partner.

Note that the ta_partner bucket also requires the x-ton-expires header to be set with an expiration date up to 7 days from the current date (see the ton-upload example script for more detail). For all other TON API buckets, this header is optional however it’s safe and a good practice to pass this header all the time and buckets that do not require it will simply ignore it.

Each bucket can be configured to support additional requirements. To confirm requirements for other features using the TON API, please refer to the documentation of that feature.

Examples

Included below are several examples on how to get started using the TON API. Please note that your Application ID must be whitelisted for the bucket that you are attempting to use.

Twurl

Twurl is a Ruby gem that is like curl, but tailored specifically for the Twitter API. Once configured, it can be used to make requests similar to curl.

An example non-resumable request:

twurl -t -H ton.twitter.com /1.1/ton/bucket/product_bucket_name -X POST -A "Content-Type: image/jpeg" -A "Content-Length: 136" --data "MY PRECIOUS BYTES"

You can find a sample Ruby TON upload script that depends on Twurl here.

Single Chunk Upload

 

Photo uploads and small tailored audiences will typically be under 64MB and can use non-resumable upload.

An example non-resumable photo upload request:

POST /1.1/ton/bucket/{bucket} HTTP/1.1
Host: ton.twitter.com
Content-Type: image/jpeg
Content-Length: {number_of_bytes}
Authorization: OAuth oauth_consumer_key="XXXXXXXXXX", oauth_nonce="XXXXXXXXXX", oauth_signature="XXXXXXXXXX", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1426878860", oauth_token="XXXXXXXXXX", oauth_version="1.0"

{image bytes}

The response:

HTTP/1.1 201 OK
Date: Wed, 05 Nov 2014 22:50:16 UTC
Content-Length: 0
Location: /1.1/ton/bucket/{bucket}/AzGxDfEg_Hj.jpg

Once completed, the Location header should be saved as it may be used in subsequent Twitter API calls.

Resumable Upload

Some uploads such as videos or large tailored audiences might be greater than 64MB and should use resumable upload. Resumable upload is a 2-step process. First, make a request with the total content length and content type which returns a location. Second, upload chunks of size less than 64MB using the location from the initial request. Note that chunks should be in integer multiples of x-ton-min-chunk-size (except the last).

Please choose an upload chunk size such that you can reliable upload the chunk in a 30-second window. For example: If you have dedicated upload bandwidth of 10Mbit/s, please use an upload chunk size smaller than 37.5 MB.

An example resumable upload initialization request:

POST /1.1/ton/bucket/{bucket}?resumable=true HTTP/1.1

host: ton.twitter.com

content-length: 0

content-type: video/mp4

x-ton-content-type: video/mp4

x-ton-content-length: 516928473

authorization: OAuth oauth_consumer_key="XXXXXXXXXX", oauth_nonce="XXXXXXXXXX", oauth_signature="XXXXXXXXXX", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1426878860", oauth_token="XXXXXXXXXX", oauth_version="1.0"

The response:

HTTP/1.1 201 OK

date: Wed, 05 Nov 2014 22:50:16 UTC

location: /1.1/ton/bucket/{bucket}/SzFxGfAg_Zj.mp4?resumable=true&resumeId=28401873

x-ton-max-chunk-size: {max chunk size}

x-ton-min-chunk-size: {min chunk size, except the last chunk}

expires: Wed, 05 Nov 2014 23:50:16 UTC

content-length: 0

The initialization request requires the following headers:

  • authorization: See 3-legged authorization
  • content-length: Set to 0
  • content-type: The Content-Type of the asset to be uploaded, cf. [1]
  • x-ton-content-type: Identical to content-type
  • x-ton-content-length: Total number of bytes of the asset to be uploaded

The initialization response contains a Location which should be saved as it will be used in all subsequent requests.

After initialization, chunks can be uploaded.

An example resumable video upload request:

PUT /1.1/ton/bucket/{bucket}/SzFxGfAg_Zj.mp4?resumable=true&resumeId=28401873 HTTP/1.1

authorization: // oAuth1.0a (3-legged) details here

content-type: video/mp4

content-length: {number of bytes transferred in this request}

content-range: bytes {starting position, inclusive, 0-indexed}-{end position, inclusive}/{total content length}



{video bytes}

The response for each chunk except the last:

HTTP/1.1 308 Resume Incomplete

date: Wed, 05 Nov 2014 23:20:10 UTC

content-length: 0

range: 0-{current uploaded length}

The response for the last chunk:

HTTP/1.1 201 Created

date: Wed, 05 Nov 2014 23:30:10 UTC

location: /1.1/ton/bucket/{bucket}/SzFxGfAg_Zj.mp4

content-length: 0

Once completed, the location header should be saved as it may be necessary for subsequent Twitter API calls.