Data API
Server API integration manual

Request format

The request should be sent to: https://api.devtodev.com/stat/v1/?api=ak-cDNRQl0Lypq4AOUrx8aGGMnmJT1FSebd where:
  • api - individual devtodev API app key, which can be found on the page of app integration;
  • v1 - the current version of the API aggregator.
All the transferred data must be in UTF8 encoding.
Contents must be sent as POST in gzip. The archive must contain JSON with one or more events for one or several users.
The size of a package can't exсeed 1 MB before compression. Packages that exсeed this size can't be processed.
If there are several events they must be formed inside a user object by type (name).
{
"abcd1234abcd" : { // Main identifier (device or user ID)
"prev" : "asdf2345234asdf", // Previous main identifier (device or user ID)
// in case it has been changed
"userId":"", // Additional identifier (it is used if there is an identifier
// that is different from the main identifier.
// For example, a cross-platform user identifier)
"prevUserId":""; // Previous additional identifier in case it has been changed
"sc" :[ // Event name
{}, // Parameters of the first event
{}, // Parameters of the second event
],
"gs" :[ // Event name
{} // Event parameters
],
},
"1234abc1234" : { // Unique user ID
"userID":"", // Additional identifier (it is used if there is an identifier
// that is different from the main identifier.
"sc" :[ // Event name
{}, // Parameters of the first event
{}, // Parameters of the second event
],
"gs" :[ // Event name
{} // Event parameters
],
},
}

Response format

HTTP Code
State
413
Wrong size of the data package (exceeds the maximum)
400
API key is absent
401
Wrong API key
403
Administrative restrictions on data received from a client
400
The error of data unpacking
{
"error_message":"Wrong GZIP format"
}
400
The error of JSON format
{
"error_message":"Wrong JSON format"
}
200
Package is received
200
The package is received, but there are errors found during the validation of events syntax.
The errors found are specified in an answer in the following format:
1.
{ "errors": { "rg": { "expected": "[timestamp]", "received": [ "[timestamps]", "[timestaTTmp]" ] } } } The message indicates that there have been received fields listed under the tag "received", but there are no fields that are listed under the tag "expected" among them. Such an event will not be processed.
2.
{ "errors": { "rg": { "expected": "[timestamp]", "useless": [ "[timestamps]", "[timestaTTmp]" ] } } }
The message indicates that there have been received extra fields listed under the tag "useless", however, fields listed under the tag "expected" are enough. Such an event will be processed.

The list of events

Information about a source of user appearance

(traffic source, referral) It is used when it is necessary to track data about a source of user appearance. The event is sent when an app is first launched by a user if a user came from a tracked source. Maximum of the fields from the following accessible data must be transferred.
"rf" : [
{
"timestamp" : 1386259227, // Required field! The date of registration
"publisher" : "", // Required field! The source from which a user came - the name of
// An advertising platform (advertising network)
"subpublisher" : "", // In case a platform is an aggregator - the name of a platform
// From which a user was resold
"subad" : "", // Specific banner from which a user came (for Facebook)
"subadgroup" : "", // The group of ads(for Facebook)
"subcampaign" : "", // The name of a campaign from which a user came
"subplacement" : "", // Banner placement - its position on a page
"subsite" : "", // Who placed a banner (an app/ a website where a banner is placed)
"country" : "US", // Required field! The country of a user (format ISO 3166-1 alpha-2)
"currencyCode" : "USD", // The currency of referral's cost (format ISO 4217)
"cost" : 9.99, // The cost of a referral in a specified currency
}
]

Information about a user

It is not sent in case there is some data missing. The event can't be submitted as a package.
"ui": [{
"timestamp": 1386259227,
"country": "GB", // The country of a user (format ISO 3166-1 alpha-2)
"language": "en", // The language of a user (format ISO 639-1 (1998)
"crossUid": "customuserid", // Custom user ID
"ip": "127.0.0.1", // IP
"carrier": "Beeline", // The name of a network operator
"isRooted": 0, // Rooted (jailbroken) device (1 - rooted)
"userAgent": "a lot of info" // Browser user-agent
}]
"pl": [{
"data": {
"age": 21, //Reserved. User's age in years
"cheater": true, //Reserved. True, if a user is a cheater
//In case you have your own methods to detect
//cheaters, you can mark such users.
//Event records made by cheaters will be
//ignored when counting statistical metrics.
"tester": true, //Reserved. True, if a user is a tester
//Attention! This marker cannot be removed
//through the SDK (It can not be set to false
//after true).
//Event records made by testers will be
//ignored when counting statistical metrics.
"gender": 1, //Reserved. User's sex 0-unknown, 1-male, 2-female
"name": "John Doe", //Reserved. User's name
"email": "[email protected]", //Reserved. User's e-mail
"phone": "+15555555555", //Reserved. User's phone number
"photo": "http://google.com/pic.png", //Reserved. User's photo
//Custom characteristics of a user in a key-value format
"key1": "stringValue", //String value
"key2": 1.54, //Number value
"key3": [1, 2, "something"] //Array
},
"timestamp": 12313 //The date of data changes
}]
"pl": [{
"data": {
"key1": null, //Remove user's characteristic key1
"key2": null //Remove user's characteristic key2
},
"timestamp": 12313
}]

Information about an app

The recommended interval of sending is not more than once per 24h.
"ai": [{
"timestamp": 1386259227,
"sdkVersion": "1.1", // Required. In case of communication via API,
// the version of implementation of a communication mechanism
"appVersion": "1.2", // App version
"codeVersion": 14.0, // Version of app's code
"bundleId": "com.myown.app" // App's bundle
}]

Information about a device

The recommended interval of sending is not more than once per 24h. Information is the most relevant for mobile devices.
"di" :[
{
"timestamp" : 1386259227,
"manufacturer" : "Apple", // The manufacturer of a device
"model" : "iPhone 4,1", // uname (iOS), MODEL (Android)
"screenResolution" : "1024x768", // The display's resolution of a device
"screenDpi" : 144, // The density of display's points
"odin" : "klflaiuewfuasydfiasydpf98ay4", // DeviceUniqueId SHA-1 (Windows Phone),
// AndroidId SHA-1 (Android)
"openUdid" : "f;isyofa7w8yp4fapw49", // OpenUDID ((Android, iOS, Windows phone)
"idfa" : "AYTSD-ADSYS-LAUSDY-IUAYSD", // Ad identifier IDFA (iOS)
"idfv" : "87ASD-9A7SD-AD2G-Q26EO-AS7D", // Device identifier within the vendor IDFV (iOS)
"d2dUdid" : "dsufyoa-sfa3wr-ra3rawQ2-AWR3A",// Base64 от DeviceUniqueId (Windows Phone) ,
// random by http:// www.ietf.org/rfc/rfc4122.txt (Android)
"imei" : "w87ea6owe7aow78eaow", // IMEI (Android)
"androidId" : "o8a7d6oa8s7b6doa87sb6d8bs", // AndroidID (Android)
"advertisingId" : "38400000-8cf0-11bd-b23e-10b96e40000d", // Advertising ID (Android, Windows phone 8.1)
"serialId" : "asd76asd9", // Hardware serial number (Android,Windows phone)
"deviceVersion": "8.1", // OS version
"deviceModel": "Windows" // The name of OS family
}
]

Game session

In case it is possible to fix the length of a session, it is sent during the end of a session or during the next session. If there is no such possibility, send the date of the start of a session, the length of a session must be placed in the middle in case it is known. The absence of a parameter of a session's length makes it impossible to count some metrics.
"gs" : [
{
"timestamp" : 1386259227, // The date of session's start
"length" : 34, // The length of a session in seconds
"level" : 3, // Player's level
"inProgress" : ["village"]
},
]

Tutorial steps

The event allows to learn how a user goes through a tutorial. The event is created after every completed step.
If a tutorial that hasn't been completed is programmed to reset to the beginning, the repeated reference of identical steps will be counted and influence the statistical metrics.
"tr" : [
{
"step" : 1, // the number of a tutorial step that has been completed
"timestamp" : 1386259227, // date
"level" : 3, // player's level
"inProgress" : ["village"],// location (game level) in which an action has been performed
}
]
Use the following constants for basic actions:
"step" : -1 // The beginning of a tutorial(before completing the first step)
"step" : 0 // The tutorial is skipped
"step" : -2 // The tutorial is completed (instead of the last step's number)
In all other cases use the number of steps above 0.

New level

Allows you to analyze players' distribution by game levels. The event is created when a player moves to the next level. In order to track the average state of game currency accounts, the amount of spendings and earnings of a currency, the amount of a game currency bought while completing a level, you can also send this data in this event.
"lu" : [
{
"level" : 10, // Required. The level that a player got
"timestamp" : 1386259227, // Required. The date of moving to the next level
"inProgress" : ["village"],// Location (game level)in which an action has been performed
"balance" : { // Optional. The balances of a game currency at the end of a level
"money1" : 123, // The name of a game currency as a key and its amount
"money2" : 11,
},
"spent" : { // Optional. The amount of a currency spent on a level
"money1" : 12, // The name of a game currency as a key and its amount
"money2" : 2,
"wood" : 12,
},
"earned" : { // Optional. The in-game currency that was earned on a level
"money1" : 8,
"money2" : 2,
"stone" : 1,
},
"bought" : { // Optional. The in-game currency that was bought on a level
"money1" : 10,
"money2" : 2,
}
},
]

Connection to social networks

Allows you to track existing connections to social networks.
"sc" : [
{
"socialNetwork" : "FB", // The name of a social network. The value from the list
// of constants for popular networks or your own string name
"timestamp" : 1386259227, // The date of connection
"level" : 3, // Player's level
"inProgress" : ["village"]// Location (game level) in which an action has been performed
},
...
]
Constants that are supported by the system:
EN
Evernote
RT
Reddit
FB
Facebook
RR
Renren
GM
Google Mail
TB
Tumblr
GP
Google+
TW
Twitter
IN
LinkedIn
VK
VK
OK
Odnoklassniki
VB
Viber
PI
Pinterest
WP
WhatsApp
QQ
Qzone

Publication in social networks

Allows you to track publications in social networks. It also allows you to analyze viral channels to optimize marketing efficiency.
It is sent after a publication has been approved by a social network.
"sp" : [
{
"socialNetwork" : "FB", // The name of a social network. The value from the list of
// constants for popular networks or your own string name
"postReason" : "levelup", // The reason of publication (max. 32 symbols). We recommend you
// to group reasons instead of sending such names as "Level 99 reached".
"timestamp" : 1386259227, // The date of publication
"level" : 3, // Player's level
"inProgress" : ["village"]// Location (game level)in which an action has been performed
},
...
]
We recommend to specify actions that encourage to make a publication as a reason:
For example:
  • Start playing
  • New level reached
  • New building
  • New ability
  • Quest completed
  • New item
  • Collection completed
  • Invitation
  • Asking for help
  • New Record
  • Achievement
  • URL sharing
  • Recommendation
  • Review
and so on...

Real payment

In case you transfer data related to several transactions, group them by item name.
"rp": [
{
"name": "inapp_name_1", // The name of a purchase
"entries": [
{
"orderId": "124567.7654321",// Transaction identifier (max. 64 symbols)
"price": 1.99, // The price of a purchase in a transaction currency
"currencyCode": "USD", // Transaction currency(ISO 4217 format)
"timestamp": 1386259227, // The date of a transaction
"level": 3, // Player's level
"inProgress": ["village"] // Location (game level) in which an action has been performed
},{ //If there is one more identical purchase for a report period
"orderId": "1224567.7634327",
"price": 1.99,
"currencyCode": "USD",
"timestamp": 1386259227,
"level": 3,
"inProgress": ["village"]
}
]
},{ //If there are other purchases for a report period
"name": "inapp_name_2",
"entries": [
{
"orderId": "1234567.7654321",
"price": 9.99,
"currencyCode": "USD",
"timestamp": 1386259227,
"level": 3,
"inProgress": ["town"]
}
]
}
]

In-game purchase

It is used to track the ways in which an in-game currency is spent and the popularity of in-game items.
"ip" : [
{
"purchaseType" : "Weapon", // The group of an item (max. 96 symbols)
"purchaseId" : "Dagger", // The unique name or ID of an item (max. 32 symbols)
"purchaseAmount" : 1, // The amount of items bought
"purchasePrice" : 1.0, // The price of an item (the overall price of a purchase if there
// are several identical items are bought) in an in-game currency
"purchasePriceCurrency" : "Coins", // The name of an in-game currency that was used to buy
// an item (max. 24 symbols)
"timestamp" : 1231872631, // The date of a purchase
"level" : 3, // Player's level
"inProgress" : ["village"] // Location (game level) in which an action has been performed
},
]
In case one item is sold in several currencies, a purchase is divided into several events, the amount of which corresponds to the number of currencies. Wherein the number of items is specified only in one event.
"ip" : [
{
"purchaseType" : "Weapon", // The group of an item (max. 96 symbols)
"purchaseId" : "Dagger", // The unique name or ID of an item (max. 32 symbols)
"purchaseAmount" : 1, // The amount of items bought
"purchasePrice" : 1.0, // The price of an item (the overall price of a purchase if there
// are several identical items are bought) in an in-game currency
"purchasePriceCurrency" : "Coins", // The name of an in-game currency that was used to buy
// an item (max. 24 symbols)
"timestamp" : 1231872631, // The date of a purchase
"level" : 3, // Player's level
"inProgress" : ["village"] // Location (game level) in which an action has been performed
},
{
"purchaseType" : "Weapon",
"purchaseId" : "Dagger",
"purchaseAmount" : 0,
"purchasePrice" : 2.0,
"purchasePriceCurrency" : "Gold",
"timestamp" : 1231872631,
"level" : 3,
"inProgress" : ["village"]
},
]

Custom event

If it is necessary to count events that are absent from the main types of events, use user events. An event must have a unique name and can include up to 20 parameters. You can use up to 300 unique names.
"ce" : [
{
"name" : "house_purchase", // The name of an event (max. 72 symbols)
"entries" : [
{
"t1" : 1231872631, // The date of an event
"level" : 3, // Player's level
"inProgress" : ["village"], // Location (game level) in which an action has been performed
"p" : {
"t1" : {
// up to 10 parameters grouped by data types
"double" : { // Parameters with values - in numbers
"key1" : 1, // The name of a parameter as a key(max. 32 symbols) and
// the value of a parameter
"key2" : 2.123,
},
"string" : { // Parameters with values - in strings
"key3" : "a", // The name of a parameter as a key(max. 32 symbols) and
// the value of a parameter (max. 255 symbols)
"key4" : "abc",
}
}
}
},
{ // If there are several events with the same name
"t1" : 1231872638,
"level" : 3,
"inProgress" : ["village"],
"p" : {
"t1" : {
"double" : {
"key1" : 1,
"key2" : 2.123,
},
"string" : {
"key3" : "a",
"key4" : "abc",
}
}
}
}
},
{ // If one user had several events with different names for
// a reporting period, continue
}
]

Progression event

First of all, the event is used for games with short locations (game levels) that are completed during one game session. The event allows to gather data about the success in location completion and receive statistics by parameters that are changeable during location completion.
"pe" : [
{
"id" : "location2", // The name of a location
"level" : 3, // Player's level at the moment of location completion
"params" : { // Event parameters
"source" : "location1", // The name of the previous location of a player
"difficulty" : 1, // Optional. The level of difficulty of location completion
"success" : true, // Success in location completion
"duration" : 180 // Optional. Time in seconds of location completion
},
"spent" : { // Optional. Resources spent during location completion
"money1" : 12, // The record of a resource in the format of
// resource's name - the amount of a resource
"money2" : 2,
"wood" : 12
},
"earned" : { // Optional. Resources that are received during location completion
"money1" : 8,
"money2" : 2,
"stone" : 1
},
"timestamp" : 1234567890 // The time of exit from a location
}
]

Ad impression

The event is used for individual tracking of ad revenue.
Do not use this event if you use ad networks that utilize the server-server protocol for sending ad revenue data (ironSource, AppLovin MAX, and Fyber networks) and you already set up this method of data collection because if you use both data sources, your revenue data may be duplicated.
Example:
"adrv": [{
"ad_network": "TestAdNetwork", //Name of the ad network responsible for the impression (from 1 to 100 symbols)
"revenue": 0.3434, //Reward for banner display in USD
"ad_unit": "TestAdUnit", //Banner name (from 1 to 100 symbols,optional)
"placement": "TestPlacement" //Banner placement (from 1 to 100 symbols, optional)
}]

Clearing user data

The "Wipe" function can help when you test your app and/or when you need to clear user data as a part of the gameplay.
By default, when you send an event without any parameters, a user-specified will be "forgotten". We will keep user data in the database, but you won’t be able to find them by their main identifier. Respectively, the following event batch with the same identifier will result in creating a new user. Also, in certain circumstances, you can’t just ‘forget’ some of the users. Therefore, we have provided several flags that might be helpful.
"wipe" : [
{
"saveRegistration": true, // Optional. A new user will inherit registration dates after
// an old user; a new user will not be registered by devtodev as
// the new one. It might be useful when you test your app.
"savePayingStatus": true, // Optional. Old user payment data will be copied into a new
// user card (number of payments, amounts and payment dates).
"saveCheaterTester": true, // Optional. cheater and tester labels will be copied into
// a new user card. It might be useful when you test your app.
"saveCustomProperties": true, // Optional. Old user custom fields and values from those fields
// will be copied into the new user card.
"timestamp" : 1234567890 // Optional. The time of exit from a location
}
]

Tracking state (GDPR)

Limiting the processing of user data. The right to erasure.

This event is implemented in accordance with the GDPR requirements.
A developer must use this event in case a user doesn’t want their data to be sent and processed in the devtodev system.
When calling "ts" event with the parameter "isTrackingAllowed": false, it is a command to the server to delete all user’s personal data that has been collected by devtodev from this app and a command to block the collection of any data of this user in future.
The user will remain listed as an impersonal unit in previously aggregated metrics.
When sending a true value, the permission to block data collection is removed.
{
"JohnDoe": {
"prev": "LittleJohn",
"ts" : [{
"isTrackingAllowed": false,
"timestamp" : 1386259227
}]
}
}

An example of a package

'POST' https://api.devtodev.com/stat/v1/?api=ak-npADyEmjxc0usQR52k6it38zUPSloGT7 with gzipped body:
{
"JohnDoe": {
"prev": "LittleJohn",
"tr": [{
"step": 1,
"timestamp": 1386259227,
"level": 1,
"inProgress": ["village"]
}, {
"step": 2,
"timestamp": 1386259236,
"level": 1,
"inProgress": ["village"]
}, {
"step": 3,
"timestamp": 1386259288,
"level": 1,
"inProgress": ["town"]
}],
"gs": [{
"timestamp": 1386259227,
"length": 1250,
"level": 3
}],
"pl": [{
"data": {
"gender": 1
}
}],
"lu": [{
"level": 4,
"inProgress": ["village"],
"timestamp": 1442392006,
"balance": {
"Coins": 1234,
"Gold": 11
}
}],
"ce": [{
"name": "Round_finished",
"entries": [{
"t1": 1442392451,
"level": 4,
"inProgress": ["village"],
"p": {
"t1": {
"double": {
"Round_time": 83,
"Score": 2.123
},
"string": {
"Result": "Victory",
"Type": "Flawless"
}
}
}
}, {
"t1": 1442393455,
"level": 4,
"inProgress": ["town"],
"p": {
"t1": {
"double": {
"Round time": 102,
"Score": 1.5
},
"string": {
"Result": "Defeat",
"Type": "Shameful"
}
}
}
}]
}],
"pe": [{
"id": "town",
"level": 3,
"params": {
"source": "vilage",
"difficulty": 2,
"success": true,
"duration": 180
},
"spent": {
"Turns": 54,
"Boost Bomb": 1,
"Extra 5 Turns": 1
},
"earned": {
"Stars": 3,
"Score": 1200,
"Coins": 5
},
"timestamp": 1234567890
}],
"ip": [{
"purchaseType": "Weapon",
"purchaseId": "Dagger",
"purchaseAmount": 1,
"purchasePrice": 30.0,
"purchasePriceCurrency": "Coins",
"timestamp": 1442393479,
"level": 4,
"inProgress": ["village"]
}],
"rp": [{
"name": "Currency pack 1",
"entries": [{
"orderId": "1234567.7654321",
"inProgress": ["village"],
"level": 4,
"price": 1.99,
"currencyCode": "USD",
"timestamp": 1442393460
}]
}],
"sp": [{
"socialNetwork": "FB",
"postReason": "New level reached",
"level": 4,
"inProgress": ["village"],
"timestamp": 1442392006
}]
}
}

Utility for testing

https://www.devtodev.com/upload/files/devtodevapitester.jar

An example of sending to PHP

An example of the implementation of a request to PHP with the use of Curl. The sending of real payment.
$url = 'https://api.devtodev.com/stat/v1/?api='.$api;
$params = [
$uid=>[
'rp' =>[
[
'name' => $name,
'entries' =>[
[
'orderId' => $transactionId,
'price' => 100,
'currencyCode' => 'USD',
'timestamp' => time(),
'level'=> 5,
'inProgress'=> ['village']
]
]
]
]
]
];
$curlHandle = curl_init($url);
curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array('Content-Type: text/plain;charset=UTF-8'));
curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlHandle, CURLOPT_POST, TRUE);
curl_setopt($curlHandle, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
curl_setopt($curlHandle, CURLOPT_POSTFIELDS, gzencode(json_encode($params)));
curl_setopt($curlHandle, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curlHandle, CURLOPT_ENCODING, 'gzip');
$response = curl_exec($curlHandle);