Coupon Feed API: Full Feed

The "Full Feed" API returns a complete CSV or JSON file of all the coupons in your subscription (along with the filters and customization as per your account settings).

If you have a use case where you need to drop and reload all offers from CouponAPI in your Database, then you can use the below flowchart to build such a script in PHP, Python, Java or  NodeJS.

Please note that this method is more complicated to implement than the Incremental Feeds. So we recommend you manually upload the full feed CSV file from your CouponAPI Account if need arises and then continue calling the Incremental Feed API.

Flowchart

The below diagram shows how the process should work:

Explanation

To start the process, you must call the getFullFeed API and pass a "callback" URL to the API along with other details. This call may come from an automated script or an HTML form on your admin page. Upon receiving this request, CouponAPI will start generating your Full Feed file. Once the file is ready, CouponAPI will call the "callback" URL and give the file name. You can then access this file and process it on your server.

API Endpoint

GET  https://couponapi.org/api/getFullFeed/

Sample Request

https://couponapi.org/api/getFullFeed/?API_KEY=[YOUR_API_KEY]&callback=https%3A%2F%2Fexample.com%2Fcallback-hook.php&format=json

Request Parameters

  • API_KEY (required) (string)
  • callback (required) (URL)
    • The encoded URL where CouponAPI should call to inform when the file is ready. CouponAPI will pass the filename of the generated feed.
  • format (optional) (string)
    • Possible Values: csv, json
    • Default Value: csv
  • off_record (optional) (boolean)
    • Possible Values: 0,1
    • Default Value: 0
    • Explanation: Our system keeps a track of your API calls to understand which offers to send when an ‘incremental’ feed is called. If in case, you want to test the API while it is already being used on a live website, you can set this parameter to 1 in your test website. This way, your last extract time will not be updated in our system, and hence there will be no disturbance to your live website. Note that this call will still be counted in your daily limit.

Success Response:

  • result: (boolean) true

Error Response:

  • result: (boolean) false
  • error: (string) Reason for failure

Callback URL

This is a user defined HTTP callback URL, which CouponAPI will call to inform when the full feed file is ready. To keep things simple, we send the below information in with the GET method in query parameters.

  • API_KEY: You should compare this to the API KEY saved in your system to ensure the call is genuinely coming from the CouponAPI server.
  • filename: The name of the generated file
  • download_link: The complete URL of the generated file.

Steps to execute in Callback Script

  1. Return a 200 OK HTTP Status code to CouponAPI to inform that you have successfully received the info
  2. Clear the Staging table
  3. Fetch the file contents from download_link.
  4. Save all Coupons as-is in the staging table. (So staging table now contains all coupons that you have subscribed for)
  5. Compare and modify your actual Coupon Table
    1. Insert into coupon table: All coupons which are in staging table but not in your coupon table.
    2. Update columns of all coupons in your coupon table, which are also present in the staging table.
    3. Delete coupons from your coupon table, which are not present in the staging table.

Fields in Feed File

  • offer_id: (integer) A unique ID for the offer in CouponAPI Database
  • title: (string) Heading of the offer
  • description: (string) Detailed description about the offer
  • code: (string) Coupon Code required to avail the offer. This field will be empty if coupon code is not required.
  • featured: (string) Possible Values: Yes, No
  • source: (string) The name of the Affiliate Network/Program from where this offer was fetched
  • url: (url) Final landing page of the offer. May be blank if not provided at source.
  • affiliate_link: (url) Affiliate Link required to monetize the offer.
  • image_url: (url) url of the image to use with this offer. May be blank if not provided at source.
  • brand_logo: (url) url of the store logo fetched from brandlogos.org (If you do not have a premium subscription, then this response will be blank)
  • type: (string) Possible Values: Code, Deals
  • store: (string) Unique store name. In most cases, this will be the primary domain name of the merchant promoting this offer.
  • merchant_home_page: (url) The homepage URL of the merchant promoting this offer.
  • categories: (string) List of categories to which this offer belongs. Please note, this will only include custom names added to the Category Mapping table in your account. If you have not mapped any custom category to the categories added for this offer by source, then this field will be blank in your response.
  • start_date: (date) Start date of the offer in yyyy-mm-dd format
  • end_date: (date) End date of the offer in yyyy-mm-dd format
  • primary_location: (string) List of Countries in which this offer is to be promoted. Usually mapped to the countries in this merchant has allowed the affiliate campaign.
  • rating: (integer) Numeric rating of the offer. Higher number signifies better rating.
  • label: (string) Short label for offer. (This feature is available only for premium plan subscribers)
  • language: (string) Language of the offer in ISO 639-1 format (2 char). (This feature is available only for premium plan subscribers)
  • deeplink: (string) The name of the Affiliate Network/Program via which the offer is monetized.
  • cashback_link: (url) Cashback affiliate link required to monetize the offer and has your affiliate network's sub id parameter.

Sample Code (PHP, MySQL)

Staging Table

CREATE TABLE `staging`(
`offer_id` INT NULL DEFAULT NULL,
`title` MEDIUMTEXT NOT NULL,
`description` MEDIUMTEXT NOT NULL,
`label` VARCHAR(50) NULL DEFAULT NULL,
`code` VARCHAR(30) NOT NULL,
`featured` VARCHAR(3) NOT NULL,
`source` VARCHAR(50) NOT NULL,
`deeplink` VARCHAR(50) NOT NULL,
`affiliate_link` MEDIUMTEXT NULL,
`cashback_link` MEDIUMTEXT NULL,
`url` MEDIUMTEXT NULL,
`image_url` MEDIUMTEXT NULL,
`brand_logo` MEDIUMTEXT NULL,
`type` VARCHAR(4) NOT NULL,
`store` VARCHAR(50) NOT NULL,
`merchant_home_page` MEDIUMTEXT NULL,
`categories` TEXT NULL,
`start_date` DATE NULL DEFAULT NULL,
`end_date` DATE NULL DEFAULT NULL,
`status` VARCHAR(10) NULL,
`primary_location` VARCHAR(300) NULL,
`language` VARCHAR(10) NOT NULL,
`rating` INT NOT NULL
);

Coupons Table

CREATE TABLE `couponapi`.`coupons` (
`id` INT NOT NULL,
`offer_id` INT NULL DEFAULT NULL,
`title` MEDIUMTEXT NOT NULL,
`description` MEDIUMTEXT NOT NULL,
`label` VARCHAR(50) NULL DEFAULT NULL,
`code` VARCHAR(30) NOT NULL,
`featured` VARCHAR(3) NOT NULL,
`source` VARCHAR(50) NOT NULL,
`deeplink` VARCHAR(50) NOT NULL,
`affiliate_link` MEDIUMTEXT NULL,
`cashback_link` MEDIUMTEXT NULL,
`url` MEDIUMTEXT NULL,
`image_url` MEDIUMTEXT NULL,
`brand_logo` MEDIUMTEXT NULL,
`type` VARCHAR(4) NOT NULL,
`store` VARCHAR(50) NOT NULL,
`merchant_home_page` MEDIUMTEXT NULL,
`categories` TEXT NULL,
`start_date` DATE NULL DEFAULT NULL,
`end_date` DATE NULL DEFAULT NULL,
`status` VARCHAR(10) NULL,
`primary_location` VARCHAR(300) NULL,
`language` VARCHAR(10) NOT NULL,
`rating` INT NOT NULL
);

-- Indexation
ALTER TABLE `coupons` ADD PRIMARY KEY (`id`);
ALTER TABLE `coupons` ADD UNIQUE `unique` (`offer_id`); 
ALTER TABLE `coupons` CHANGE `id` `id` INT NOT NULL AUTO_INCREMENT;

PHP Script to Trigger Full Feed

<?php

// ========== CONFIG ==========
$API_KEY = '[YOUR_API_KEY]'; // Enter your API Key
$format = 'json';
$off_record= 0; // If set to true, system will not update your last extract time. This is useful for debugging pupose. Please note, this will still count in your API Usage limit
$callback = '[URL_OF_CALLBACK.PHP_SCRIPT]';

// ========== CALL FULL FEED API ==========
$rawResponse = file_get_contents('https://couponapi.org/api/getFullFeed/?API_KEY='.$API_KEY.'&callback='.$callback.'&format='.$format.'&off_record='.$off_record);
$response = json_decode($feed,true);

if($response['result']) {
    exit('Full Feed Requested');
} else {
    die('Full Feed could not be requested. Error:'.$response['error']);
}

?>

Callback Script

<?php

// ============= SET CONNECTION VARIABLES =============
$db_server = "";
$db_name = "";
$db_user = "";
$db_password = "";
$secret_key = "[Your API KEY]";

// Remove script timeout. We don't want our script to die before completion of process. We could have 1000s of coupons to process.
set_time_limit(0);

// ============ GET DATA FROM CALLBACK HOOK ============
$filename = $_GET['filename'];
$api_key = $_GET['api_key'];
$download_link = $_GET['download_link'];

// ============ ERROR HANDLING ============
function myErrorHandler($errNo, $errMsg) {
// send Error Msg to your team by Email or log them to a file or database
// Send 400 HTTP Code so that CouponAPI will re-try to send data
http_response_code(400);
    die($errMsg);
}
set_error_handler("myErrorHandler");

// COMPARE API_KEY TO MAKE SURE THE CALL IS FROM COUPONAPI
if($api_key != $secret_key){
    trigger_error("Unauthorized access");
}

$con = mysqli_connect($db_server, $db_user, $db_password, $db_name);
if (!$con) {
    trigger_error("Could not connect to DB");
}

// Clear Staging Table
mysqli_query($con, "DELETE FROM `staging`");

// Fetch file contents
$rawResponse = file_get_contents($download_link);
$response = json_decode($rawResponse, true);
if(!$response['result']) {
    trigger_error($response['error']);
}

$offers = $response['offers'];

//Save all Coupons as-is in the staging table. (So staging table will contain all coupons that we have subscribed for)

foreach($offers as $offer){

// INSERT OFFER INTO STAGING TABLE HERE
    $offer_id = $offer['offer_id'];
    $title = mysqli_real_escape_string($con, $offer['title']);
    $description = mysqli_real_escape_string($con, $offer['description']);
    $label = mysqli_real_escape_string($con, $offer['label']);
    $code = mysqli_real_escape_string($con, $offer['code']);
    $featured = $offer['featured'];
    $source =  $offer['source'];
    $deeplink = $offer['deeplink'];
    $affiliate_link = mysqli_real_escape_string($con, $offer['affiliate_link']);
    $cashback_link = mysqli_real_escape_string($con, $offer['cashback_link']);
    $url = mysqli_real_escape_string($con, $offer['url']);
    $image_url = mysqli_real_escape_string($con, $offer['image_url']);
    $brand_logo = mysqli_real_escape_string($con, $offer['brand_logo']);
    $type = $offer['type'];
    $store = mysqli_real_escape_string($con, $offer['store']);
    $merchant_home_page = mysqli_real_escape_string($con, $offer['merchant_home_page']);
    $categories = mysqli_real_escape_string($con, $offer['categories']);
    $start_date = ($offer['end_date'] ? "'" . $offer['end_date'] . "'" : 'NULL');
    $end_date = ($offer['end_date'] ? "'" . $offer['end_date'] . "'" : 'NULL');
    $status = $offer['status'];
    $primary_location = $offer['primary_location'];
    $language = $offer['language'];
    $rating = $offer['rating'];

    $insert_sql = "INSERT INTO `staging`(`offer_id`, `title`, `description`, `label`, `code`, `featured`, `source`, `deeplink`, `affiliate_link`, `cashback_link`, `url`, `image_url`, `brand_logo`, `type`, `store`, `merchant_home_page`, `categories`, `start_date`, `end_date`, `status`, `primary_location`, `language`, `rating`) VALUES ('$offer_id','$title','$description','$label','$code','$featured','$source','$deeplink','$affiliate_link','$cashback_link','$url','$image_url','$brand_logo','$type','$store','$merchant_home_page','$categories',$start_date,$end_date,'$status','$primary_location','$language','$rating')";

    if(!mysqli_query($con, $insert_sql)){
        trigger_error("Failed to save offer ID ".$offer['offer_id']." to database.");
    }

}

// If data is inserted successfully in staging table, then we can send 200 response to CouponAPI. We now have all required data is our Database
ob_start();
header('Connection: close');
header("Content-Encoding: none");
header('Content-Length: '.ob_get_length());
echo 'OK';
ob_end_flush();
@ob_flush();
flush();
//fastcgi_finish_request(); //uncomment this if you are using PHP-FPM

// Start processing offers from staging table
$results = mysqli_query($con, "SELECT * FROM staging");
$row = mysqli_fetch_assoc($results);
if (mysqli_num_rows($results) > 0) {

    // INSERT ALL OFFERS INTO PRODUCTION TABLE OR UPDATE FIELDS IF ALREADY PRESENT
     $insert_sql = "INSERT INTO coupons (`offer_id`, `title`, `description`, `label`, `code`, `featured`, `source`, `deeplink`, `affiliate_link`, `cashback_link`, `url`, `image_url`, `brand_logo`, `type`, `store`, `merchant_home_page`, `categories`, `start_date`, `end_date`, `status`, `primary_location`, `language`, `rating`)
     SELECT `offer_id`, `title`, `description`, `label`, `code`, `featured`, `source`, `deeplink`, `affiliate_link`, `cashback_link`, `url`, `image_url`, `brand_logo`, `type`, `store`, `merchant_home_page`, `categories`, `start_date`, `end_date`, `status`, `primary_location`, `language`, `rating`
    FROM  staging
    ON DUPLICATE KEY UPDATE 
        offer_id = VALUES(offer_id),
        title = VALUES(title),
        description = VALUES(description),
        label = VALUES(label),
        code = VALUES(code),
        featured = VALUES(featured),
        source = VALUES(source),
        deeplink = VALUES(deeplink),
        affiliate_link = VALUES(affiliate_link),
        cashback_link = VALUES(cashback_link),
        url = VALUES(url),
        image_url = VALUES(image_url),
        brand_logo = VALUES(brand_logo),
        type = VALUES(type),
        store = VALUES(store),
        merchant_home_page = VALUES(merchant_home_page),
        categories = VALUES(categories),
        start_date = VALUES(start_date),
        end_date = VALUES(end_date),
        status = VALUES(status),
        primary_location = VALUES(primary_location),
        language = VALUES(language),
        rating = VALUES(rating)";
    if(!mysqli_query($con, $insert_sql)){
        trigger_error("Failed to insert/update new in coupons table.");
    }

    // DELETE ALL PRODUCTION OFFERS WHICH ARE NOT IN STAGING
    $delete_sql = "DELETE FROM coupons WHERE offer_id NOT IN (SELECT offer_id FROM staging)"; 
    if(!mysqli_query($con, $delete_sql)){
        trigger_error("Failed to delete suspended data from coupons table.");
    }

}

// Kill the script as we have used set_time_limit(0) on top.
exit("Process completed");