Using API
- API potential
- Postback
- Lead receiver
- Lead feed
- Balance
Postback
Parameters in the link
&web_id - The affiliate's ID in your system (if you have one); maximum length - 100 symbols. &sub1 - additional data in any format; maximum length - 100 symbols. &sub2 - additional data in any format; maximum length - 100 symbols. &sub3 - additional data in any format; maximum length - 100 symbols. &sub4 - additional data in any format; maximum length - 100 symbols. &sub5 - additional data in any format; maximum length - 100 symbols. &utm_source - maximum length - 100 symbols. &utm_medium - maximum length - 100 symbols. &utm_campaign - maximum length - 100 symbols. &utm_content - maximum length - 100 symbols. &utm_term - maximum length - 100 symbols.
When a system has a new offer and its status changes, our system can notify a third-party system about it, by sending a HTTP request. Request can be sent with the help of POST or GET method (based on the profile settings), but data is transferred in URL (consequently, it's received in $_GET). Our system will send postback every minute during a week until it receives HTTP status 200. Postback can be active no more than 3 times - when a new order is created, when the status is changed to confirmed, held, canceled or trash and when it's changed from held to confirmed. Global URLs of postbacks are specified on cpa.tl administrator panel Traffic Light on profile page. You can also specify postbacks for each stream individually. You can specify a special URL status; if URL isn't specified for "trash", URL for "canceled" will be used. If there's no URL for confirmed or canceled, there won't be postback for these statuses. Information about the attempts to send postbacks is stored for 30 days. URL can include macros: {id} - Order ID in our system {id2} - Order ID in our system(if we received an order via API) {created_at} - order creation time in ISO format (for example, '2015-06-12T17:50:39+00:00'), always UTC {created_at_unixtime} - order creation time in the form of POSIX timestamp (for example, 1434131439) {status} - options new|cancelled|holded|confirmed {status_code} - options 0|-10|5|10 {status_id} - 2 - new, 1 - confirmed, 4 - confirmed in hold, 3 - canceled {payout} - payout for an affiliate for an order {payout_currency} - the currency in which an affiliate gets funds in (for example, 'USD', 'EUR', 'RUB') {offer_id} - offer's id in our system {country} - client's country (for example, 'RU') {ip_address} - client's IP address (let's say '176.59.124.152') {trash} - numeric code if it's a trash order {comment} - comment (as a rule, used in case of refusal); can be empty if a call center doesn't provide refusal comments * trash description (in case of trash) {sub1} - from a corresponding parameter in a link {sub2} - from a corresponding parameter in a link {sub3} - from a corresponding parameter in a link {sub4} - from a corresponding parameter in a link {sub5} - from a corresponding parameter in a link {web_id} - from a corresponding parameter in a link {utm_source} - from a corresponding parameter in a link {utm_medium} - from a corresponding parameter in a link {utm_campaign} - from a corresponding parameter in a link {utm_content} - from a corresponding parameter in a link {utm_term} - from a corresponding parameter in a link {fee} - the same as "payout" (outdated) {subaccount} - the same as "sub1" (outdated) {ex} - the same as "sub2" (outdated) {extra} - the same as "sub2" (outdated) Status (status): new - processing cancelled - canceled holded - confirmed as hold confirmed - confirmed Status code (status_code): 0 - processing -10 - canceled 5 - confirmed as hold 10 - confirmed Example of URL postback: http://example.com/api/orders/postback/?o={id}&click_id={sub1}&offer={offer_id}&money={payout}&s={status}
Lead receiver
POST http://api.cpa.tl/api/lead/send Request is sent to this URL with the help of POST method, message body contains data: "key": string - API access key, get it in a profile https://cpa.tl/u/profile "id": string - Lead ID in your system "offer_id": int - offer's id in our system "stream_hid": string - Stream id in our system "ip_address": string - Lead IP address "name": sting - Client's name and surname "phone": string - Client's phone number "comments": string - Comment on the order "country": string - Client's country "address":string - Client's address "tz": int - time zone, for example, GMT +3 for Europe/Moscow (how to get a time zone?) "web_id": string - affiliate ID in your system "email": string - client's email "ip_address": string "user_agent": string "utm_source": string(100) "utm_medium": string(100) "utm_campaign": string(100) "utm_content": string(100) "utm_term": string(100) "sub1": string(255) "sub2": string(255) "sub3": string(255) "sub4": string(255) "sub5": string(255) If successful, the response will be HTTP 200, in json format, and will contain the following data: "id" - lead id in our system; "autologin_url" (optional) - link to the broker's website auto-login, if the offer category supports this feature; "error" (optional) - error message if the request could not be successfully sent to the advertiser. Examples of a successful response: {"id": 123} {"id": 123, "autologin_url": "https://example.click?token=kfjdgksjd"} Example of a response with an error: {"id": 123, "autologin_url": "", "error": "Lead sending error to the advertiser"} required fields: key, offer_id, phone, country, ip_address it'd be very desirable to specify this for additional traffic control: name, web_id, user_agent In case of an error, HTTP 409 will be sent as an aswer, in json format, it will contain error status, for example: {"errmsg": "country is a required field"} Possible error statuses offer not found - offer not found or no GEO matches the country field incorrect IP-address - wrong IP address country is a required field - 'country' field is required for saving an order incorrect country code; should be ISO2 or ISO3 format - wrong country code in a country field customer phone is a required field - 'phone' field is required for saving an order incorrect customer phone - wrong phone number customer name too long - 'name' field is too long wrong tz {} - tz (timezone) field wrong format incorrect timezone - tz (timezone) field wrong format duplicate order [ {} ] - order double
Php example ( download ):
<?php $apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx'; $offer_id = 0; // every offer has its own ID, clarify it on the administrator panel or contact the support $stream_hid = ''; // not required, if an order will be linked to a stream $apiUrl = 'http://api.cpa.tl/api/lead/send'; if ($_SERVER['REQUEST_METHOD'] == 'POST') { $data_post = $_POST; $data = array( 'key' => $apiKey, 'id' => microtime(true), // it's better to specify the value that will help you to identify your lead; it can remain microtime if you have no CRM 'offer_id' => $offer_id, 'stream_hid' => $stream_hid, 'name' => $data_post['name'], 'phone' => $data_post['phone'], 'comments' => $data_post['comments'], 'country' => $data_post['country'], // format ISO 3166-1 Alpha-2 - https://ru.wikipedia.org/wiki/ISO_3166-1 'address' => $data_post['address'], 'tz' => $data_post['timezone_int'], // it's desirable to take it from a landing page, but if it's impossible, leave this field empty or enter 3 (Moscow time zone) 'web_id' => '', 'ip_address' => isset($_SERVER["HTTP_CF_CONNECTING_IP"]) ? $_SERVER["HTTP_CF_CONNECTING_IP"] : $_SERVER['REMOTE_ADDR'], 'user_agent' => $_SERVER['HTTP_USER_AGENT'], ); $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => http_build_query($data), 'ignore_errors' => true, ) ); $context = stream_context_create($options); $result = file_get_contents($apiUrl, false, $context); $obj = json_decode($result); if (null === $obj) { // Error in an answer print("Invalid JSON"); } else if (!empty($obj->errmsg)) { // Error in a request print("Error: " . $оbj->errmsg); } else { print('Order ID: ' . $obj->id); } }Python example ( download ):
import time import requests API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxx' API_URL = 'http://api.cpa.tl/api/lead/send' offer_id = 0 # offer ID in our system, every offer has its own ID, clarify it on the administrator panel or contact the support stream_hid = '' # not required, if an order will be linked to a stream data = { 'key': API_KEY, 'id': int(round(time.time() * 1000)), # it's better to specify the value that will help you to identify your lead 'offer_id': offer_id, # every offer has its own ID, clarify it on the administrator panel or contact the support 'stream_hid': stream_hid, 'name': 'tester (refuse)', 'phone': '8 999 1111122', 'comments': 'test lead', 'country': 'RU', # format ISO 3166-1 Alpha-2 - https://ru.wikipedia.org/wiki/ISO_3166-1 'address': '', 'tz': 3, # it's desirable to take it from a landing page, but if it's impossible, leave this field empty or enter 3 (Moscow time zone) 'web_id': '', 'ip_address': '194.58.117.14', # ip of the order. in Django, you can get request.META.get('REMOTE_ADDR') 'user_agent': '', # in Django, you can get HTTP_USER_AGENT } r = requests.post(API_URL, data=data) if r.status_code == 200: lead_id = r.json().get('id') print('Order ID: {}'.format(lead_id)) elif r.status_code == 404: print('check API_KEY, API_URL, offer_id') elif r.status_code == 409: err_mess = r.json().get('errmsg') print(err_mess)
How to get a time zone :
You can get client's time zone with the help of javascript and specify it in the hidden field of the form <input id="tz" name="timezone_int" type="hidden" value="" /> <script> $(document).ready(function () { $("#tz").val(new Date().getTimezoneOffset() / -60); }); </script>
Lead feed
GET http://api.cpa.tl/api/lead/feed?key=<key>&[filters] provides a list of leads in json format. <key> - API access key, get it in a profile https://cpa.tl/u/profile possible filters: - id - search by lead ID in our system - id2 - search by lead ID in your system - offset - download shift (if no info = 0) You can check several leads at the same time by specifying several id or id2, for example - id2[]=1&id2[]=2&id2[]=3&id2[]=N - date - if 1 value is specified - leads for this date; if 2 - all leads for the specified period (the date ‘before’ is not included in the sample). period (the date ‘before’ is not included in the sample). For example: - date=2024-06-01 - see leads for June 1st, 2024 - date[]=2024-06-01&date[]=2024-07-01 - see leads for June - date_to_with - if true, the "before" date will be included in the selection. For example: - date[]=2024-06-01&date[]=2024-06-30&date_to_with=true - see leads for June - by_status_changed_at - if the parameter is true, filtering will be carried out by last status change date, not by creation date. Answer description: count - number of leads in the answer total - total number of leads based on requested filters offset - current download shift limit - requested number of leads leads - the list of leads Lead field description: "status_code": int - 0 - new, 10 - confirmed, 5 - confirmed in hold, -10 - canceled "status": string - "new" - new, "confirmed" - confirmed, "holded" - confirmed in hold, "cancelled" - canceled "status_id": int - 2 - new, 1 - confirmed, 4 - confirmed in hold, 3 - canceled "trash": int or null - numeric code if it's a trash order "comment": string or null - comment (for example, failed to contact a client), as a rule, used in case of a refusal; it can be empty if a call center doesn't provide refusal comments * trash description (in case of trash) "payout": string - payout for an affiliate for an order (for example, '500.00' или '90') "payout_currency": string - the currency in which an affiliate gets funds in (for example, 'USD', 'EUR', 'RUB') "created_at": string - order creation time in ISO format (for example, '2015-06-12T17:50:39+00:00'), always UTC "created_at_unixtime": int - order creation time in the form of POSIX timestamp (for example, 1434131439) "id": 43179 - lead/order ID in our system "id2": 205 - lead/order ID in your system (it may be 'null') "offer_id": 5 - offer's id in our system "country": string - client's country (for example, 'RU') "ip_address": string - client's IP address (let's say '176.59.124.152') "order_page": string - Order page URL address "utm_source" - value specified when creating a lead "utm_medium" - value specified when creating a lead "utm_campaign" - value specified when creating a lead "utm_content" - value specified when creating a lead "utm_term" - value specified when creating a lead "web_id" - value specified when creating a lead "sub1" - value specified when creating a lead "sub2" - value specified when creating a lead "sub3" - value specified when creating a lead "sub4" - value specified when creating a lead "sub5" - value specified when creating a lead "fee" - the same as "payout" (устаревшее) "subaccount" - the same as "sub1" (устаревшее) "ex" - the same as "sub2" (устаревшее) "extra" - the same as "sub2" (устаревшее) "trash_reason" - the same as "trash" (устаревшее)
Php example ( download ):
<?php $apiKey = 'xxxxxxxxxxxxxxxxxxxxxxxxx'; $apiUrl = 'http://api.cpa.tl/api/lead/feed'; $data = array( 'key' => $apiKey, // setting up the filters. You can use one or several filters // getting ID data in our system 'id' => ['xxxxxx', 'xxxxxx'], // getting ID data in your system //'id2' => ['xxxxxx', 'xxxxxx'], // getting all orders for this date //'date' => ['2018-07-01', '2018-07-15'], ); function http_build_query_noindex($a, $b=0, $c=0){ if (!is_array($a)) { return false; } foreach ((array)$a as $k=>$v){ if ($c) { $k = $b."[]"; } elseif (is_int($k)) { $k = $b . $k; } if (is_array($v)||is_object($v)) { $r[]=http_build_query_noindex($v, $k, 1); continue; } $r[] = urlencode($k) . "=" . urlencode($v); } return implode("&", $r); } $result = file_get_contents($apiUrl.'?'.http_build_query_noindex($data, '')); $obj = json_decode($result); if (null === $obj) { // Error in an answer echo "Invalid JSON"; } elseif (!empty($jsonObj->errmsg)) { // Error in a request echo "Error: " . $jsonObj->errmsg; } else { print('Orders received: ' . $obj->count . " \nPython example ( download ):
"); foreach ($obj->leads as $lead) { print($lead->id . ' - ' . $lead->status. " \n
"); } }
import datetime import requests API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxx' API_URL = 'http://api.cpa.tl/api/lead/feed' data = { 'key': API_KEY, # forming filters # 'id': 'xxxxxx', # getting data on an order based on ID in our system # 'id': ['xxxxxx', 'xxxxxx', ], # getting data on several orders based on ID in our system # 'id2': 'xxxxxx', # getting data on an order based on ID in your system # 'id2': ['xxxxxx', 'xxxxxx', ], # getting data on several orders based on ID in our system # 'date': '2018-07-15', # getting all orders for this date # 'date': datetime.date.today().strftime('%Y-%m-%d'), # getting today's orders 'date': ['2018-07-01', '2018-07-15', ], # getting orders placed from July, 1st to July, 15th, 2018 } r = requests.get(API_URL, params=data) if r.status_code == 200: data = r.json() print('received {} orders'.format(data.get('count'))) for lead in data.get('leads'): lead_id = lead.get('id2') # Lead ID in your system status_code = lead.get('status') if status_code == 'new': status = 'new' elif status_code == 'confirmed': status = 'confirmed' elif status_code == 'new|cancelled': status = 'canceled' else: status = '--' print('Order {} status {}'.format(lead_id, status)) elif r.status_code == 404: print('check API_KEY, API_URL, offer_id') elif r.status_code == 409: err_mess = r.json().get('errmsg') print(err_mess)
Balance
GET http://api.cpa.tl/api/user/balance?key=<key> provides information about the amount of funds in all currencies in json format. <key> - API access key, get it in a profile https://cpa.tl/u/profile answer description: currency - currency, may be provided in: 'RUB', 'USD', 'EUR', 'COIN' { currency: { "total": 0, - total profit "payment": 0, - payouts made "earn": 0, - deposited "hold": 0, - hold "balance": 0, - account balance } }