Insights Reporting API

This API is now deprecated. Access to this API will be removed in late June 2023 after which the Tapjoy GraphQL API must be used for reporting purposes.

1. Overview

The Tapjoy Insights API is a REST API for retrieving metrics about offers (ad_groups), with optional country-level breakdowns.The Insights API offers access to the last two years of data.

The API returns data in realtime. Data is collected in near-realtime and should be no more than a few minutes behind. In the worst case scenario it can be up to an hour behind however so it reccommended you use it as a source of data for yesterday.

2. Insights Endpoint

Make your insights requests to:

https://api.tapjoy.com/v1/ad_groups//insights

Where the "id" is the offer id for which you are requesting data. Please see the Legacy Reporting API if you need to retrieve offer ids.

3. Requesting Access

You will need the Publisher Reporting API Key, which can be found in the publisher dashboard under Settings->App Settings->App Info->API Keys.

If you are using the "V2″ Tapjoy dashboard (dashboard.tapjoy.com), you can find this key at https://dashboard.tapjoy.com/reporting/api. There, it is called the "Insights Reporting API Key"/

Please note, this is a different key from the Legacy Reporting API key.

4. Authentication and Authorization

Requests are authenticated using a standard two-legged OAuth2 flow. An access token is requested using the Publisher Reporting API Key, and the resulting access token is used to authenticate against future requests.

Access tokens have a 1-hour lifetime and cannot be refreshed. Once a token expires you simply request a new one with your Publisher Reporting API Key.

A. Requesting an access token

To request an access token you must send a POST request with an Authorization header using your Publisher Reporting API Key. If the credentials are valid the response will include an access token and the number of seconds until the token expires.

Example Request

POST /v1/oauth2/token
Host: api.tapjoy.com
Authorization: Basic <Publisher Reporting API Key> 
Accept: application/json; */*

Success Response

status 200
{
    “access_token”: “token_string”,
    “token_type”: “bearer”,
    “expires_in”: 3600,
    “refresh_token”: null
}

Bad Credentials Response

status 401
{
    “error”: “Unauthorized”
}

B. Using an access token

Once you have an access token requests can be made to the rest of the API. The access token should be sent with every request in the Authorization header with a type of “Bearer”. If the access token has expired or does not exist the response will have a status of 401 Unauthorized.

Example Request

GET /v1/ad_groups/bdbcfcc0-2e39-0133-d996-6c4008927a44/insights
Host: api.tapjoy.com
Authorization: Bearer 
Accept: application/json; */*

Expired Token Response

status 401
{
    “error”: “Unauthorized”
}

5. Example request script

Here is a sample script in Ruby that requests an access token and then uses it to request insights on an ad group. Note that this script assumes the client credentials are correct. We’ve omitted error handling from the example.

require 'base64'
require 'json'
require 'net/https'

http = Net::HTTP.new('api.tapjoy.com', 443)
http.use_ssl = true

###
# Request an access token
###
request = Net::HTTP::Post.new('/v1/oauth2/token')
request['Authorization'] = "Basic #{publisher_reporting_api_key}"
response = http.request(request)
oauth = JSON.parse(response.body)
access_token = oauth['access_token']

###
# Use the token to request insights
###
path = "/v1/ad_groups/#{ad_group_id}/insights"
path << "?time_preset=yesterday&breakdowns=country_code"
request = Net::HTTP::Get.new(path)
request['Authorization'] = "Bearer #{access_token}"

response = http.request(request)
###
# Output response body, see examples in Responses section below for data formatting
###
puts response.body

6. Request Parameters

NameValuesDescription
start\_timee.g. 2015-08-01T00:00:00-04:00The start time of the query range in ISO8601 format, now only hourly rounding time supported, for example 2015-08-01T00:30:00-04:00 is not eligible. start\_time requires end\_time if provided. start/end\_time and time\_preset are mutually exclusive.
end\_timee.g. 2015-08-01T00:00:00-04:00The end time of the query range in ISO8601 format, now only hourly rounding time supported, for example 2015-08-01T00:30:00-04:00 is not eligible. end\_time requires start\_time if provided. start/end\_time and time\_preset are mutually exclusive.
time\_incrementhourly, dailyThe increment by which data points will be split. “daily” will result in one data point per day.
time\_presettoday, yesterday, last\_weekMutually exclusive with start/end\_time.
breakdownscountry\_codeA metric to segment the data by. Only one breakdown per request is supported.

7. Responses

HTTP Response Codes

200 - Successful request accompanied by a response body
403 - Unauthorized
422 - Invalid parameters accompanied by error message body
500 - Internal server error

Response Body

Depending on whether optional breakdowns are requested via the "breakdowns" parameter, i.e. by country, there are two possible response structures.

For ad_groups that have a secondary tracking offer, there is a separate request URL in the "metadata" section of the response. Associated spend data may be found on the secondary offer in that case.

With "breakdowns", where metrics are grouped by country:

{
    "data": {
      "bdbcfcc0-2e39-0133-d996-6c4008927a44": {
      "insights": {
        "US":{
            "paid_clicks": [
                [ 1440115200, 34],
                [ 1440201600, 39]
            ],
            "global_renders": [
                [ 1440115200, 191]
                [ 1440201600, 120],
            ],
            "global_conversions": [
                [ 1440115200, 25]
                [ 1440201600, 28],
            ],
            "installs_spend": [
                [ 1440115200, -1401.38]
                [ 1440201600, -2435.12],
            ]
        },
        "CA":{
            "paid_clicks": [
                [ 1440115200, 12],
                [ 1440201600, 15]
            ],
            "global_renders": [
                [ 1440115200, 78]
                [ 1440201600, 85],
            ],
            "global_conversions": [
                [ 1440115200, 8]
                [ 1440201600, 12],
            ],
            "installs_spend": [
                [ 1440115200, -700.38]
                [ 1440201600, -543.12],
            ]
        }
    }
    "metadata": {
        "name": "AdGroup name",
        "platform": "iOS",
        "secondary_offer_id" : "2a27ecfe-a6fe-4f4f-a32f-727ef69823d1",
    },
    "rel" : {
            "link" : "https://api.tapjoy.com/v1/ad_groups/2a27ecfe-a6fe-4f4f-a32f-727ef69823d1"/insights"
   }
  }
 }
}

Without "breakdowns", where the metrics will be directly under the “insights” stanza:

{
  "data": {
      "bdbcfcc0-2e39-0133-d996-6c4008927a44": {
      "insights": {
      "paid_clicks": [
          [ 1440115200, 34],
          [ 1440201600, 39]
      ],
      "global_renders": [
          [ 1440115200, 191]
          [ 1440201600, 120],
      ],
      "global_conversions": [
          [ 1440115200, 25]
          [ 1440201600, 28],
      ],
      "installs_spend": [
          [ 1440115200, -1401.38]
          [ 1440201600, -2435.12],
      ]
    }
  "metadata": {
      "name": "AdGroup name",
      "platform": "iOS"
      }
    }
  }
}

Each metric in the “insights” stanza will be an array of two element arrays. The first element is the number of seconds since epoch and the second is the value of the metric for that time period.

In the example above the “time_increment” parameter was set to “daily” so there is one data point per day.

Error Body

Error bodies will be sent back with all 422 response codes with the format:

{
  "errors":[ "Explanation of the error condition" ]
}