Getting tailored audience list


#1

I need to get tailored audience list by account.

I was able to call API https://dev.twitter.com/ads/reference/get/accounts to get a list of accounts that has granted Ad Manager to our application. However when I call https://ads-api.twitter.com/0/accounts/:account_id/tailored_audiences to get a list of account’s tailored_audience I get an Exception. I though that I have READ privilege for the accounts, then should have the privilege to get account’s tailored audience.

TwitterException{exceptionCode=[545a39f5-04ab62f3], statusCode=403, message=The client application making this request does not have access to this API, code=-1, retryAfter=-1, rateLimitStatus=RateLimitStatusJSONImpl{remaining=1996, limit=2000, resetTimeInSeconds=1432771614, secondsUntilReset=853}, version=3.0.5}


Changing specific tailored audience list
#2

@neterictw can you provide the full HTTP request and response you’re making (not your logs)?

For simplicity and to narrow down a potential permission issue quicker, let’s troubleshoot this outside of your implementation using twurl.

gem install twurl
twurl authorize --consumer-key key --consumer-secret secret
twurl --trace -H ads-api.twitter.com "/0/accounts"
twurl --trace -H ads-api.twitter.com "/0/accounts/xxxx/tailored_audiences"

#3

C:\Users\elin>twurl --trace -H ads-api.twitter.com "/0/accounts"
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\nC
ontent-Type: application/x-www-form-urlencoded\r\nAuthorization: OAuth oauth_consumer_key=“aA1WEjRu4Oa6lKQDRP2I1WLNo”, oauth_nonce=“UQoIX
1givPY96pbeiAJzC52kMFAQLp8o9JclQdIss”, oauth_signature=“ZeLWcofzBS5MOkvfPn1BRi%2B47ZM%3D”, oauth_signature_method=“HMAC-SHA1”, oauth_ti
mestamp=“1432806618”, oauth_token=“39596342-JLe13ZR5ZANIX7v5LooyZbjxuAnf3AfZsP0Ng5AjU”, oauth_version=“1.0”\r\nConnection: close\r\nHo
st: 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: 623\r\n”
-> “content-type: application/json;charset=utf-8\r\n”
-> “date: Thu, 28 May 2015 09:50:17 GMT\r\n”
-> “server: tsa_k\r\n”
-> “set-cookie: guest_id=v1%3A143280661695666717; Domain=.twitter.com; Path=/; Expires=Sat, 27-May-2017 09:50:16 UTC\r\n”
-> “strict-transport-security: max-age=631138519\r\n”
-> “x-access-level: read-write\r\n”
-> “x-connection-hash: a3cca7bda5107de7590d938008e80d46\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: 1998\r\n”
-> “x-rate-limit-reset: 1432807447\r\n”
-> “x-response-time: 186\r\n”
-> “x-runtime: 0.006667\r\n”
-> “x-transaction: cf1e13828a423a66\r\n”
-> “x-xss-protection: 1; mode=block\r\n”
-> “\r\n"
reading 623 bytes…
-> “”
-> “\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x00\xA4\x95Ko\xDB0\f\xC7\xBFJ\xA1s\x8C\xE9-Y\xB7\xB6\xCB\xAD\xD8v0P\x0F\x04\x94Dg\xC6\x1C;\xF5\xA3mV \xE4\xBBOn\x8A\"\xDD\x9C\xC3\x1A\xC0\a\xCB\x14\xFF\"\x7F\"\xE9'\xD2\xE1\xDD\x88\xFD@\xDC\x13\xD9B\a\x9B>\xBD\xED\xF7\v\x12a\x00\xE2\xBE=\x91 \x066H\x1C).\xAF?_\\-on\xC8\x82\f\xD5\x06\x7F\xB7\xCD\xF4\xF9r\x83]\x15\xE0\xFB\x87\x9B\xB6_]6k\xAC\xB1?\xDA\xB1\xEA\x1F\xAA!\xFC\\A:\x80p\x CADFU\xC6yA\x8D\xA34=_\xD3\xDE*&\x9Bl\xC6*\xA4E\xE8\x10\x06\x8C\xAF\x0E<\xA3,cy\xC1rG\xA5\xA3jr\xE8\xA1\x9E\xAC9\x04\xC2si\x8C\x05Sr\xA5\xB
D\x88J\xE8\\xFAXj\xA5\xD3\xCEq\e\xDF\xA8\xC9\x8C&AQ\xB0t|\xEE\xC4\xB3\x1Al\xB7]{\x0F\xF5\xAA\x1F\x18\xFB)\xA7\xEB\xEB\xE5\x97b\xF91\x19c\x CA'\t\x10WB\xDD\xE3~\xF1\x8A\xE3\x13\x0EW\xD0\xE3Y0R4\x89\x87)\xA8\xFD\vF\xF3\xAB\xBD\xC3y\x18*c\xB2\xE0\xDC1\xFB\x16\x86\x92\xB4\xE4\\\x94! 2\x86\xA5\xB6&4\b\xDE\xD2h\xBC\xB28\x03Ce4E\x90OjB9)\xDF\x0F\xE3\x16\x9B\xB8;\v\x85\x9A\xAE\x99\xCF\xA06\xA0\x12\x8FF\xAFa\x06\x88\xCCX\xA A\x0EV0\xEA\x98r\\\x1C\x01\xD1\xAC\xF4hx\xA9\xC0\x83\xD7\xDE\xC7h\xF2\x83\xD5 \xA5\xA4V\xCC\x03IA\xD8\x82j\xA7R\x10\xEC\xFD@\xD6mW\xD55\\x
F8\xB1\xAF\x1A\xEC\xFB3\xCB$]<\x97’\xD9\x04\xCA\xEASl\xB8\x9Aj]\t\xC7\xE9q\xE70)B\x00\xAEu\xCE\xAC\x0F\xB9\xC9%\xF8\xC0K\xA1E\xC2F\xE7;g\nB
x15\x949\x99\x9A\xE7\x8Cb\xB9\x82f}\xDBbun\xBD\xC8\x8C\xEB\x7F\xE7\xC8\x81\xC9n’\xEA\x87\x19&\a73\xB9q\xE1\xA89b\x128\x93\xD1b.r\x1A\xA5\xB6
\xDC\a\x83\x11\xBD\x92\x8A\xD12”;\xD5@/j\xD6\t\xFE~&\xCB\xEEy\xF8\x9D\xCB\xC3\x9E\xE61l\xEEO\xF2\xC8\v\xFA<P\x98<\xE2a\x19z\xAFC\f\xC6(\x04
\xA3\x85@\xCB"X\x0F\xA5\x16*\xD8\x93<\xF2\xA9\x7FD\x8AC\xFF/\x8F\x1F\x87\xBF\xCEj\xD8m’\x04\x10B;6\xC3\x94u;$\x85\xC3\xCA\xE9\x05i\xF0qX\x8
5\xB1\xEB\xDB\x8E\xB8f\xAC\xEB\xFD\x1F\x00\x00\x00\xFF\xFF\x03\x00k\xFE\xE0\xE9\xC8\x06\x00\x00”
{“request”:{“params”:{}},“data”:[… customer data here… {“name”:“Eric”,“timezone”:“America/Los_Angeles”,“timezone_switch_at”:“2015-04-28T07:00:00Z”,“id”:“18ce53yytmv”,“created_at”:“2015-04-
29T02:18:14Z”,“salt”:“81ebb6cdc775ea7633e81da8baf635c8”,“updated_at”:“2015-04-29T06:37:06Z”,“approval_status”:“ACCEPTED”,“deleted”:false}],“
data_type”:“account”,“total_count”:6,“next_cursor”:null}read 623 bytes

Conn close


#4

C:\Users\elin>twurl --trace -H ads-api.twitter.com "/0/accounts/18ce53yytmv/tailored_audiences"
opening connection to ads-api.twitter.com:443
opened
starting SSL for ads-api.twitter.com:443
SSL established
<- “GET /0/accounts/18ce53yytmv/tailored_audiences HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: /\r\nUs
er-Agent: OAuth gem v0.4.7\r\nContent-Type: application/x-www-form-urlencoded\r\nAuthorization: OAuth oauth_consumer_key=“aA1WEjRu4Oa6lKQDR
P2I1WLNo”, oauth_nonce=“r9cPGpAUqShwZAoxcs6K1P8597DJfKjW3kzomVYiHZg”, oauth_signature=“0EcnY6BgeZ7S5cRplBpIYRqilU4%3D”, oauth_signature
method=“HMAC-SHA1”, oauth_timestamp=“1432806678”, oauth_token=“39596342-JLe13ZR5ZANIX7v5LooyZbjxuAnf3AfZsP0Ng5AjU”, oauth_version=“1
.0”\r\nConnection: close\r\nHost: ads-api.twitter.com\r\nContent-Length: 0\r\n\r\n"
<- “”
-> “HTTP/1.1 403 Forbidden\r\n”
-> “connection: close\r\n”
-> “content-disposition: attachment; filename=json.json\r\n”
-> “content-encoding: gzip\r\n”
-> “content-length: 166\r\n”
-> “content-type: application/json;charset=utf-8\r\n”
-> “date: Thu, 28 May 2015 09:51:17 GMT\r\n”
-> “server: tsa_k\r\n”
-> “set-cookie: guest_id=v1%3A143280667713190250; Domain=.twitter.com; Path=/; Expires=Sat, 27-May-2017 09:51:17 UTC\r\n”
-> “strict-transport-security: max-age=631138519\r\n”
-> “x-access-level: read-write\r\n”
-> “x-connection-hash: 2d34d4ee730810c1388e2ac54f12b5dd\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: 1998\r\n”
-> “x-rate-limit-reset: 1432807477\r\n”
-> “x-response-time: 192\r\n”
-> “x-runtime: 0.00907\r\n”
-> “x-transaction: 1a04bb1826040299\r\n”
-> “x-xss-protection: 1; mode=block\r\n”
-> "\r\n"
reading 166 bytes…
-> “”
-> "\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x00,\xCEA\n\x830\x10@\xD1\xAB\f\xB3\xF6\x04\xEE\x82\x15\x1A\x10\x95\x127-E\x868h\xA8&6I\xBB\t\xB9{-\x
ED\xFE\xF1\xF9\t\xD9{\xE7\x03\x96\xB7\x84\xDAM\x8C%\x0E\xAD\x18\xD4\xB9\xBB\xC8k}\x1A\xABF\xD6\xAD\x1AE\xDF7\xB2\x12Jv-\x16\xB8q\b4\x7F\xADZ
\x18\xF4j\xD8F\xA0}
\x8D\xA6h\x9C\x85\x8D\x1E\xC6\xCE\x10\x17\x13\xC0\xF3\xF3\xC5!\xC2\xE48\x80u\x11\x16z3\x90\xD6G\x04\xA2\xFB!\xD1K\xCC\xF
7\x02\xFF\x18\xCB\x84;y\xDA\x8E\xB1\x94s\xFE\x00\x00\x00\xFF\xFF\x03\x00\xD8sZ\xFD\xA7\x00\x00\x00”
{“errors”:[{“code”:“UNAUTHORIZED_CLIENT_APPLICATION”,“message”:“The client application making this request does not have access to this API”
}],“request”:{“params”:{}}}read 166 bytes
Conn close


#5

Looks like your application is configured correctly and I’m seeing this request succeed:

twurl -H ads-api.twitter.com "/0/accounts/18ce53yytmv/tailored_audiences"

{
  "request": {
    "params": {
      "account_id": "18ce53yytmv"
    }
  },
  "data": [
    {
      "targetable": false,
      "name": "test_list_audience_1",
      "targetable_types": [
        "CRM",
        "EXCLUDED_CRM"
      ],
      "audience_type": "CRM",
      "id": "s1ra",
      "reasons_not_targetable": [
        "TOO_SMALL"
      ],
      "list_type": "TWITTER_ID",
      "created_at": "2015-05-05T13:24:15Z",
      "updated_at": "2015-05-05T19:44:51Z",
      "partner_source": "OTHER",
      "deleted": false,
      "audience_size": null
    },
    ... OMITTED CONTENTS ...
    {
      "targetable": true,
      "name": "aaaa",
      "targetable_types": [
        "CRM",
        "EXCLUDED_CRM"
      ],
      "audience_type": "CRM",
      "id": "s29x",
      "reasons_not_targetable": [],
      "list_type": "TWITTER_ID",
      "created_at": "2015-05-06T02:40:58Z",
      "updated_at": "2015-05-06T09:14:42Z",
      "partner_source": "OTHER",
      "deleted": false,
      "audience_size": "660"
    }
  ],
  "data_type": "tailored_audiences",
  "total_count": 5,
  "next_cursor": null
}

#6

hI, @brandonmblacK,

Thanks for the quick reply. But what confused me is that one request has returned results, but not for the other. I think once we have the ADs account list API access, we also have tailored audience list privilege, right?

I could access the tailored audience API couple days ago, but then I was not able to access it since yesterday.

Thanks,
Eric.


#7

To make things clear, I will describe in

more detail about what we encountered in the past a few weeks.

About 2-3 weeks ago, we tried out the Ads API, here were what we could and could not do -

  1. Get the list of Ads accounts that have granted access to NetBase account (OK)
  2. Get Ads account detail informaiton (OK)
  3. Get Ads account permission (OK)
  4. Get campaign lists (OK)
  5. Get list of tailored audiences (OK)
  6. Create a new tailored audience (NOT OK with UNAUTHORIZED_CLIENT_APPLICATION exception)
  7. Link the uploaded audience file( uploaded through TON API) with existing tailored audience (NOT OK with UNAUTHORIZED_CLIENT_APPLICATION exception)

We escalated this problem to twitter about 1 week ago, then Twitter helped made some configuration changes to our application. Unfortunately, after that configuration changes, what used to work stopped working -

  1. Get the list of Ads accounts that have granted access to NetBase account (OK)
  2. Get Ads account detail information (OK)
  3. Get Ads account permission (OK)
  4. Get campaign lists (NOT OK with UNAUTHORIZED_CLIENT_APPLICATION exception)
  5. Get list of tailored audiences (NOT OK with UNAUTHORIZED_CLIENT_APPLICATION exception)
  6. Create a new tailored audience (NOT OK with UNAUTHORIZED_CLIENT_APPLICATION exception)
  7. Link the uploaded audience file( uploaded through TON API) with existing tailored audience (NOT OK with UNAUTHORIZED_CLIENT_APPLICATION exception)

As you can see, it is worse than before the application configuration change.

Below are the steps that we tried after the configuration change. Please not that these were directly using Twitter’s twurl, instead of our implementation.

I am using my account to do the test (My twitter Ads account id is 18ce53yytmv).

1: grand access to NetBase application as Ad Manager.
2: install twurl and authorize with NetBase consumer-key and consumer-secret
> twurl authorize --consumer-key key --consumer-secret secret
> Sign in to the URL generated by the previous command using NetBase Account, and input the generated PIN number.
> Authentication Complete.

3: call get account lists, API> twurl -t -H ads-api.twitter.com /0/accounts | python -m json.tool
We can get a list of accounts that have granted access to NetBase.
{
“approval_status”: “ACCEPTED”,
“created_at”: “2015-04-29T02:18:14Z”,
“deleted”: false,
“id”: “18ce53yytmv”,
“name”: “Eric”,
“salt”: “81ebb6cdc775ea7633e81da8baf635c8”,
“timezone”: “America/Los_Angeles”,
“timezone_switch_at”: “2015-04-28T07:00:00Z”,
“updated_at”: “2015-04-29T06:37:06Z”
}

4: call get account detailed information, API> twurl -t -H ads-api.twitter.com /0/accounts/18ce53yytmv | python -m json.tool
{
“data”: {
“approval_status”: “ACCEPTED”,
“created_at”: “2015-04-29T02:18:14Z”,
“deleted”: false,
“id”: “18ce53yytmv”,
“name”: “Eric”,
“salt”: “81ebb6cdc775ea7633e81da8baf635c8”,
“timezone”: “America/Los_Angeles”,
“timezone_switch_at”: “2015-04-28T07:00:00Z”,
“updated_at”: “2015-04-29T06:37:06Z”
},
“data_type”: “account”,
“request”: {
“params”: {
“account_id”: “18ce53yytmv”
}
}
}

5: call get account permissions information, API> twurl -t -H ads-api.twitter.com /0/accounts/18ce53yytmv/authenticated_user_access | python -m json.tool
{
“data”: {
“permissions”: [
“AD_MANAGER”
],
“user_id”: 39596342
},
“data_type”: “user_access”,
“request”: {
“params”: {
“account_id”: “18ce53yytmv”
}
}
}

6: call get account campaigns list, API> twurl -t -H ads-api.twitter.com /0/accounts/18ce53yytmv/campaigns | python -m json.tool
{
“errors”: [
{
“code”: “UNAUTHORIZED_CLIENT_APPLICATION”,
“message”: “The client application making this request does not have access to this API”
}
],
“request”: {
“params”: {}
}
}

7: call get account tailored audience list, API> twurl -t -H ads-api.twitter.com /0/accounts/18ce53yytmv/tailored_audiences | python -m json.tool
{
“errors”: [
{
“code”: “UNAUTHORIZED_CLIENT_APPLICATION”,
“message”: “The client application making this request does not have access to this API”
}
],
“request”: {
“params”: {}
}
}

Exception Examples:

C:\Users\elin>twurl -t -H ads-api.twitter.com /0/accounts/18ce53yytmv/tailored_audiences | python -m json.tool
opening connection to ads-api.twitter.com:443
opened
starting SSL for ads-api.twitter.com:443
SSL established
<- “GET /0/accounts/18ce53yytmv/tailored_audiences HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: /\r\nUs
er-Agent: OAuth gem v0.4.7\r\nContent-Type: application/x-www-form-urlencoded\r\nAuthorization: OAuth oauth_consumer_key=“aA1WEjRu4Oa6lKQDR
P2I1WLNo”, oauth_nonce=“6Kajp8VLYdrOkf6syx1BdamcUWFzqc4GxUvZ6rU3OA”, oauth_signature=“ixx2O0O90roenRz5NBpTvu2LZZo%3D”, oauth_signature_
method=“HMAC-SHA1”, oauth_timestamp=“1433495810”, oauth_token=“39596342-2X0I4qZQQHSq0ZDurZU8bTxDf7ByGNbRf2XAISdag”, oauth_version=“1.
0”\r\nConnection: close\r\nHost: ads-api.twitter.com\r\nContent-Length: 0\r\n\r\n”
<- “”
-> “HTTP/1.1 403 Forbidden\r\n”
-> “connection: close\r\n”
-> “content-disposition: attachment; filename=json.json\r\n”
-> “content-encoding: gzip\r\n”
-> “content-length: 166\r\n”
-> “content-type: application/json;charset=utf-8\r\n”
-> “date: Fri, 05 Jun 2015 09:16:49 GMT\r\n”
-> “server: tsa_k\r\n”
-> “set-cookie: guest_id=v1%3A143349580980242679; Domain=.twitter.com; Path=/; Expires=Sun, 04-Jun-2017 09:16:49 UTC\r\n”
-> “strict-transport-security: max-age=631138519\r\n”
-> “x-access-level: read-write-directmessages\r\n”
-> “x-connection-hash: 1801e3f18ed2eed0a2e11e723ffc2a6c\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: 1989\r\n”
-> “x-rate-limit-reset: 1433495905\r\n”
-> “x-response-time: 222\r\n”
-> “x-runtime: 0.009011\r\n”
-> “x-transaction: c974a8f0e54800a0\r\n”
-> “x-xss-protection: 1; mode=block\r\n”
-> "\r\n"
reading 166 bytes…
-> “”
-> "\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x00,\xCEA\n\x830\x10@\xD1\xAB\f\xB3\xF6\x04\xEE\x82\x15\x1A\x10\x95\x127-E\x868h\xA8&6I\xBB\t\xB9{-\x
ED\xFE\xF1\xF9\t\xD9{\xE7\x03\x96\xB7\x84\xDAM\x8C%\x0E\xAD\x18\xD4\xB9\xBB\xC8k}\x1A\xABF\xD6\xAD\x1AE\xDF7\xB2\x12Jv-\x16\xB8q\b4\x7F\xADZ
\x18\xF4j\xD8F\xA0}_\x8D\xA6h\x9C\x85\x8D\x1E\xC6\xCE\x10\x17\x13\xC0\xF3\xF3\xC5!\xC2\xE48\x80u\x11\x16z3\x90\xD6G\x04\xA2\xFB!\xD1K\xCC\xF
7\x02\xFF\x18\xCB\x84;y\xDA\x8E\xB1\x94s\xFE\x00\x00\x00\xFF\xFF\x03\x00\xD8sZ\xFD\xA7\x00\x00\x00"
read 166 bytes
Conn close
{
“errors”: [
{
“code”: “UNAUTHORIZED_CLIENT_APPLICATION”,
“message”: “The client application making this request does not have access to this API”
}
],
“request”: {
“params”: {}
}
}


#8

@neterictw I again confirmed today that the application associated with the consumer key in your request traces here is setup for both Ads API access as well as TON API access correctly (read and write on both). However, I’m simply just not seeing the same issue and can’t reproduce your problem.

Are you experiencing the issue outside of twurl as well?


#9

Hi, @brandonmblack:

Now we have no problem to do the queries. The settings now are correct.

Thanks.


#10

Fantastic. Thank you for confirming.