Tutorials / Using Twurl

Using Twurl

The Ads API program enables businesses to create and manage ad campaigns programmatically on Twitter. To help achieve your business goals, the Ads API provides the following suite of tools: Objective-based campaigns, analytics, and targeting.

Twurl is a curl-like application, tailored specifically for the Twitter API. It knows how to grant an access token to a Twitter app for a specified user and then sign all requests with that access token. It also provides other development and debugging conveniences such as defining aliases for common requests, as well as support for multiple access tokens to easily switch between different Twitter apps and Twitter accounts.

Setting up Twurl

Twurl can be installed using RubyGems as follows:

gem install twurl

After you have twurl installed, you can authorize your Twitter app and Twitter account using your consumer key and its secret.

twurl authorize --consumer-key key --consumer-secret secret

This will return a URL that you should open up in your browser. Authenticate to Twitter, and then enter the returned PIN back into the terminal. Assuming all that works well, your account will be authorized to make requests with the API.

Making requests

The simplest request just requires that you specify the host and the path you want to request.

Similar to curl, a GET request is performed by default.

twurl -H "https://ads-api.twitter.com" "/5/accounts/"

{"request":{"params":{}},"data":
{"name":"Furni","business_name":null,"timezone":"America\/Los_Angeles","timezone_switch_at":"2016-04-
06T07:00:00Z","id":"18ce54ayf0z","created_at":"2016-04-
07T14:40:15Z","salt":"b88939e5cabbca720159cb3659d73c06","updated_at":"2017-02-
08T08:49:53Z","business_id":null,"approval_status":"ACCEPTED","deleted":false}}

You can also pipe the returned response into jq, which gives you a nicely formatted output, as well as some additional format options.

twurl -H "https://ads-api.twitter.com" "/5/accounts/" | jq .

      {
  "request": {
    "params": {}
  },
  "data": {
    "name": "Furni",
    "business_name": null,
    "timezone": "America/Los_Angeles",
    "timezone_switch_at": "2016-04-06T07:00:00Z",
    "id": "18ce54ayf0z",
    "created_at": "2016-04-07T14:40:15Z",
    "salt": "b88939e5cabbca720159cb3659d73c06",
    "updated_at": "2017-02-08T08:49:53Z",
    "business_id": null,
    "approval_status": "ACCEPTED",
    "deleted": false
  }
}
    

One more handy thing which is worth mention is that by passing the -t or –trace to twurl you can get a full trace of your request, including headers:

twurl -t -H "https://ads-api.twitter.com" "/5/accounts/" | jq .

      opening connection to ads-api.twitter.com:443...
opened
starting SSL for ads-api.twitter.com:443...
SSL established
<- "GET /0/accounts/ HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: OAuth gem v0.4.7\r\nContent-Type: application/x-www-form-urlencoded\r\nAuthorization: OAuth oauth_consumer_key=\"OIDntXZULiYrCzSBq23BQ\", oauth_nonce=\"KZEtbucXokJODhhwn3xYsliatynuZ9oMrL1JtA5Oo\", oauth_signature=\"NKILQIbnIlyggPjCdfBZuQ%2FUaq0%3D\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1463521174\", oauth_token=\"11459892-un76nJyLTIGuBjPjxH3nKSlV3Hk7s7NDdoagecqFt\", oauth_version=\"1.0\"\r\nConnection: close\r\nHost: ads-api.twitter.com\r\nContent-Length: 0\r\n\r\n"
<- ""
-> "HTTP/1.1 200 OK\r\n"
-> "connection: close\r\n"
-> "content-disposition: attachment; filename=json.json\r\n"
-> "content-encoding: gzip\r\n"
-> "content-length: 906\r\n"
-> "content-type: application/json;charset=utf-8\r\n"
-> "date: Tue, 17 May 2016 21:39:34 GMT\r\n"
-> "server: tsa_a\r\n"
-> "set-cookie: guest_id=v1%3A146352117479278616; Domain=.twitter.com; Path=/; Expires=Thu, 17-May-2018 21:39:34 UTC\r\n"
-> "strict-transport-security: max-age=631138519\r\n"
-> "x-access-level: read-write\r\n"
-> "x-connection-hash: 51c36dec361937126c6257b5f6650c29\r\n"
-> "x-content-type-options: nosniff\r\n"
-> "x-frame-options: SAMEORIGIN\r\n"
-> "x-rate-limit-limit: 2000\r\n"
-> "x-rate-limit-remaining: 1999\r\n"
-> "x-rate-limit-reset: 1463522074\r\n"
-> "x-response-time: 15\r\n"
-> "x-runtime: 0.007239\r\n"
-> "x-transaction: dddc2f2770de948c\r\n"
-> "x-xss-protection: 1; mode=block\r\n"
-> "\r\n"
reading 906 bytes...
-> ""
-> "\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x00\xB4\x96\xDBn\xDBF\x10\x86_\x85\xE0\xB5\xD4\xCE\x9E\x0Fw\xB1\xE3\xB6\x17\r\x10\xA0D\v\xA4-\x84\xE1\x1E$\xC1\x14\xA9\x92\x94\x1C\xD9\xF0\xBBgI\x19\xAD\x9CP\x06*\xB5\x80\x04Q\xD8\xDD\xE1\xEE\xB7\xF3\xFF3Oy\e\xFE\xDA\x85\xAE\xCF\xEDS\xBE\xC5\x167]zz~\x9E\xE5\x1E{\xCC\xED\xEFOy\x8D\x9B\x90\xDB\xFC\xB6\xC5\xF52\xFB\xAD]/W}>\xCB\xFB\xF5&<6\xF50\xF2n\x13\xDA\xB5\xC3?\xBE\xFF\xB9\xE9\x16\xEF\xEAe\xA8Bw2c\xD1=\xAC{\xB7Z`zG\xBD\xAB\xAAY\xBE\xF6i\x15w\xBB\xF6\x90\xA6\xB96`\x1F\xFC8\x9CS tN\xC8\x9C@A\xA9\xE5`\xA9\xF8\x94\xE6tX\x8D\xA3\x8E9\x032P/\xA3+\xBD\xE6\b1h.40\x17J/\xD2\xCC\xDD\xD6\xBF\x8A&\xE7\xC0\xE6\x94\x15\x94Y&,\xD7C4\xDCn\xDBf\x8F\xD5\xA2\xEB\xB1\xDFu\xC3\tno\xEF>\x16w\xEF\xD3\xA0O\xBBO\x01r\e\xB1\xEA\xC2\xF3\xEC\xEF\xF3\xDF\xB4X\xFB\xA6\xCEn*t\xF7\x17\x03\x18\xF6\xC4\xC7\x13\xAA\x02\xB4\x05H\x9FaO#\x12\xE3\xC8\xBE\x9DFB\xE7\x90\x16HK\xB8e\xE6\x04\tG\xA7\xB5R\xDE\b\xE4F3\x10\"2&\x8D3et!\x90\xF2,\x12^\x10c\x19}y\xFDeH\x8AU\xC8n\xB0]\xA7E\xC3\xEFUP\xD8\x1C\xC4\x9C\xD2\x02\xD4WP\x84x`\xF7\xFB\t*d\xC4(\n\xA2l\xCA\x15JN\xA8\xA0\x03\xC59\x8F\x118P-\x05S\x9EEE}\x89J2\xA9\xDC4\x151^\n\xB7<1\xE6\x97S\xF9\x18\xD05\xEE>\xFB\xA5o\xDA\xF0?1Y\xEE\xEF\xCD\xEA,\x13^Pb\xA9\xB4\x82\x9F0\x11I1\x11\xA5c\xD2\x19\x01\x80\xCCD\x8A.\x10]\x1A\x88\x18\xE8\eLR\xB4\x01\x8B\xBAB<\xA1\xAD}\xF6kh\xBB\xCB\xBD\xE3(\x1DHJ\xA0\xDFJ\x87h\x17\x04\xDBSg\xB6\x13X\x8E\xCB\xD8p\x10.-\x9C\n(jBY\xD0\xA0\xC0{\x14TIa\x92\xC1\x94\xD4`\xC9\x9DV\xE4\r\x01\x01\xB1)\xF7\x18\xB9\x1C\xCBOi\xA0\xCE>\x85zy\x15\x151\a>\xFA\xC3\xD7yr\xA4r\xD0K\xC7'\xA8\x88\x81J\xBA^\x02\x96\x90\xD7Td\x89\xCC\x95\x92%_\x11R#C#\xA4\x91\x1A\xBCF\xD0%\xE8s\xC9\x02\xB2 \xE9j\xC8UN\xFB\x98\x98\xAC\xD2\xB7\nWcI\xF2\xD1\xE7\xB0<j\xA8\xCBi,i\x99\x19\xAF7\x15 8\xD5\x90QRj\xCA\x1D\xD51\x1A\xA1\xB87\x12\xA8\x14\x10\x82\x03 g|\xE5\x98,\xDA\nf\xC5\x15\x1A\xFA'Y\xB2y\xF6\xA1\xA9\xBB>\xB4\xDF\xB9f\xF3\x9A\xD1\xDD\xAEm\xB6a@4T\xAB7\xE9\fV!\x8B\x11\xCD7t\xB8z\x88U?I\xE7X\xBC\x86\xEA\x91\x8E$_\xD5\"\xAF\x1Cj4\x11|PQ\xFB\xE4-\xE8\tS\x8AP#\xCA8Ag*\xDA\x7F@\xE7\xC7\xA6YV!{\x7F\xF3\xE1*8\xEA,\x9C\xC3n\xF9\xF9,\x1C=t\e\"\x19\xE6)\x1C/\xA8V\f4\x04\x16KUr.@\xF2\xA8\xA2\f\xDE\x99\xA0\xD9t\xEA\f~>\xC0\x11\xE2E\x9F\x97\xC1\xF9a\xD7\xD6\xEB\xAB\xB4$G\x8B\x91g\xB4\xC4\xF1\x10\xE1q\x02\x88|q\xA6\xD4\xB6\xA4f\x8E\x9C6s\xA5\xD6\x86\x99 \x1C\x96\xA5C5\xD03\xAEd\xC9\x7F\xBDb\x0E\xE44\x90\x93h\xF4_[\xCC\x9F\xC7\xAEv\xD1\x1F\xB6a\xEC\x12\\\xB3\xAB\xC7\x82\xD4\xF4)\xC2\xF1_\x12\xFD,\xAF\xC3\xE7~\x91\x1A\xD4\xAEi\x8FM\xEB\xF3\x17\x00\x00\x00\xFF\xFF\x03\x00J8W8)\v\x00\x00"
read 906 bytes
Conn close
{
  "request": {
    "params": {}
  },
  "data": [
    {
      "name": "Furni",
      "timezone": "America/Los_Angeles",
      "timezone_switch_at": "2016-04-06T07:00:00Z",
      "id": "18ce54ayf0z",
      "created_at": "2016-04-07T14:40:15Z",
      "salt": "b88939e5cabbca720159cb3659d73c06",
      "updated_at": "2016-04-07T14:40:28Z",
      "approval_status": "ACCEPTED",
      "deleted": false
    }
  ],
  "data_type": "account",
  "total_count": 1,
  "next_cursor": null
}
    

Using twurl is also very helpful when you’re on Ads API forums to discuss or ask about any API behavior that you think might not be working quite right. Providing a twurl request that reproduces the behavior you are seeing will provide a clear and standardized format that facilitates the discussion.

To find out more about twurl and its options, run twurl --help or visit twurl’s GitHub page. Be sure to check out this blog post on the subject for further inspiration.

Ready to build your solution?

Review the documentation to get started