Using Twurl — Twitter Developers

Tutorials

Using Twurl

Twurl is a curl-like application, tailored specifically for the Twitter API. It knows how to grant an access token to a client application 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 client applications 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 application 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" "/2/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" "/2/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" "/2/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 facilatates the discussion.

To find out more about twurl and its options, run twurl --help or visit twurl’s GitHub page.

Ready to build your solution?

Review the documentation to get started

  • Read Previous
  • Read Next