4 Distribution API

The Adility Distribution API is a tool to monetize consumer applications with local offers. The Adility Distribution API is as well capable to work for platforms that host consumer applications for others, like daily deal white label providers, advertising networks and more. The basic flow is simple. You query offers from Adility, promote them to your audience, for prepaid offers you charge the consumer and maintain a revenue share from each sale/transaction.

Basic Flow

  • Query Offers. You query offers by a number of filters. You have to set a location and radius as mandatory parameters of the query. Location can either be set as lat/lng, postal_code or city/state_code. Also, you can add categories and types parameters to your query. You can sort the result via the sort_by parameter of the query. This section explains how to handle queries.
  • Get Offer Details. The result set from offer queries doesn't contain certain attributes for offers such as public_phone of  advertiser and address_line_1/address_line_2 of redemption_locations. In order to get these additional attributes you need to make another API call using offer_id
  • Clip Coupon. If you distribute coupons to your customers they will clip coupons in your application and you make an API call for each clip to get a voucher code and present it to the customer.
  • Place Order. In order to get a deal or a gift card customers pre-pay and your application processes the transaction. Orders are created on your end and you notify us of these sales so they can be fulfilled.
  • Cancel Order. Your customer may request a refund after you placed an order to Adility. You may decide to refund the customer and cancel the order in Adility so you are not charged for it by Adility. This section considers different options for such requests.
  • Cancel Voucher. Customers may want to get a partial refund. For example, a customer buys 3 vouchers for one offer and decided to cancel one voucher and reduces the order to 2 vouchers only. 

There're also more advanced use cases:

Advanced Cases
  • Accounts. Designed for platforms that host multiple applications (publishers). Accounts help separate resources such as Order and Reservation between publishers on the same platform.
  • Reservations. Offers are shared between publishers. You can reserve a certain number of vouchers and they are no more available for others. Read more in this section.
  • Promotions. If you are successful in selling offers which is good The Adility team can oblige you to provide a deal schedule if this is applicable to your workflow. Promotion is designed to represent a unit in your deal schedule. Read more about it in this section.
  • Instant Offers. You can build an application set to promote instant offers to consumers. Instant offers can be acquired by consumers only within a certain time frame along the day. For example, an advertiser can provide a great discount at morning hours when the foot trafic is low. Instant offers is a good fit for mobile geo applications. Read more in this section.
  • Bundle Deals. This type of offers is suppose to entice customers come to advertiser location more then once. From consumers prospective bundle deals have a few coupons with different discounts. These coupons are presented by BundleItem resource and listed as items attribute of the offer. Read this section to find out details. 
  • Checkin Coupons. Offers of this type again entice customers to return to advertiser location. Customer obtains a checkin coupon only after he checks in at a location a few times. Read this section if you plan to distribute this type of offers.


Basic Workflow 

Query Offers

GET /offers?query_parameters

Returns a list of offers from The Adility matching the query parameters.

Query Parameters

You can run queries with a combination of 3 parameter groups:
  • filtering
  • pagination
  • sorting
Filtering
This set of query parameters allows you to get offers matching your conditions.
  • location parameters / radius. Mandatory query parameter pair. Radius is measured in miles and should be between 0 and 100.
  • categories. A list of category ids separated by comma.
  • types. A list of offer types separated by comma.
  • class. Specifies Offer class (A or B). Class A contains non-verified offers, while B - verified ones.
  • instant_offers. Specifies whether instant offers should be included to the result set. Can be true or false.
  • recently_published. Maximum number of days offers are published. Can't be greater then 5.
  • recently_updated. Maximum number of days offers are updated. Can't be greater then 5.
  • recently_closed. Maximum number of days offers are closed. Can't be greater then 5.
where location parameters are:
  • lng / lat. A pair of latitude and longitude. Read more about geographic coordination system on wikipedia.
  • city / state_code / country_code. Determines a city. Default value for country_code is US.
  • postal_codecountry_code. Determines a postal code.
Take a look at a few sample queries below.

Recently closed deals in San Francisco:
GET /offers?city=san%20francisco&state_code=CA&radius=23&types=deal&recently_closed=5

curl -k -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers?city=san%20francisco&state_code=CA&radius=23&types=deal&recently_closed=5'

Recently published gift cards and deals from fitness centers and spa salons in London:
GET /offers?lat=51.508608&lng=-0.128349&radius=20&categories=1587367777,1765435254&types=gift_card,deal&recently_published=3

curl -k -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers?lat=51.508608&lng=-0.128349&radius=20&categories=1587367777,1765435254&types=gift_card,deal&recently_published=3'

Coupons for golf around Delta, Canada:
GET /offers?postal_code=V4E%202A9&country_code=CA&radius=100&categories=658203330&types=coupon

curl -k -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers?postal_code=V4E%202A9&country_code=CA&radius=100&categories=658203330&types=coupon'

Class B deal in Atlanta:
GET /offers?city=atlanta&state_code=GA&radius=10&types=deal&class=B

curl -k -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers?city=atlanta&state_code=GA&radius=10&types=deal&class=B'

Pagination
You can break result set onto pages by setting two pagination parameters:
  • per_page. A number of offers per page in the result set. Default value is 100.
  • page. Index of a current page in the result set.  Default value is 1 which points to a first page in the result set.
Sorting
By setting a query parameter sort_by you define sorting for the result set. You can sort by the following offer attribute:
  • price
  • value
  • quantity_in_stock
  • start_date
  • end_date
  • published_at
  • updated_at
Each attribute can be followed by +asc or +desc keys to set the order. The key +asc is used be default. All sorting parameters are separated by comma. Check queries with sorting parameters below.

Sample 1
GET /offers?{filtering}&per_page=20&page=8&sort_by=price+desc,quantity_in_stock

curl -k -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers?city=atlanta&state_code=GA&radius=10&per_page=20&page=8&sort_by=price+desc,quantity_in_stock'

Sample 2
GET /offers?{filtering}&sort_by=published_at+desc,end_date+desc,value+desc

curl -k -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers?city=atlanta&state_code=GA&radius=10&sort_by=published_at+desc,end_date+desc,value+desc'

Result Set 
Sample in XML

<?xml version="1.0" encoding="UTF-8"?>
<response>
    <status>OK</status>
    <page>3</page>
    <per_page>100</per_page> 
    <total_pages>10</total_pages> 
    <total_items>948</total_items> 
    <sort_by>sort_by=published_at+desc,end_date+desc,value+desc</sort_by>
    <offers>
        ...
     </offers>
</response>

You can examine the following attributes for number of pages and number of items in the result set:
  • total_pages
  • total_items

Missing Offer Attributes

Offers in the result set don't contain attributes related to contact information of an advertiser. All missing attributes go under advertiser attribute of offers:
  • website_url
  • public_phone
  • public_email
  • address_line_1 of redemption_location
  • address_line_2 of redemption_location
  • public_phone of redemption_location
  • references of redemption_location
In order to get these attributes for a specific offer you need to query the offer by offer_id.

Get Offer Details

GET /offers/<offer_id>

curl -k -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers/<offer_id>'

When you query an offer by offer_id the result set contains all attributes of the offer including those that are missing in general query.

Place Order

When a customer purchases an offer your application creates an order on your end for your records as well as passes the order along to Adility. Aside to secondary attributes the order should contain offer_id and quantity which define the offer and how many vouchers for it has been bought by the customer.

In general, customers can purchase more then one offer within a single order. That's why orders have the items attribute of OrderItem which represents a single offer within the order.

Request

JSON

{
    "order": { 
        "order_number": "1234-234",
        "customer_name": "John Smith",
        "items": [
            {
                "offer_id": "0a3f749808c168528ba01a911ea63ee99a1eee3a7a6787dbd2159ebb6f4d372b",
                "quantity": "3"
            }
        ]
    }
}

Response

JSON

HTTP/1.1 200 OK
{
    "status": "OK",
    "order": { 
        "id": "680da8eb1d01505570bed1887f0f3952d5e2ec8345469d34872c9541ec0600e8",
        "order_number": "1234-234",
        "customer_name": "John Smith",
        "status": "active",
        "purchased_at": "2011-03-11 10:36:51",
        "items": [
            {
                "offer_id": "0a3f749808c168528ba01a911ea63ee99a1eee3a7a6787dbd2159ebb6f4d372b",
                "quantity": "3",
                "vouchers": [
                    {
                        "id": "3cc77d348d873abe7355f026015295d5fc6baf6109d01c72fd1f9c1e95ed8a2c", 
                        "offer_id": "0a3f749808c168528ba01a911ea63ee99a1eee3a7a6787dbd2159ebb6f4d372b",
                        "redemption_code": "576339",
                        "status": "acquired",
                        "acquired_at": "2011-03-11 10:36:51",
                        "barcode": {
                            "url": "...",
                            "width": "...",
                            "height": "..."
                        },
                        "print_url": "..."
                    },
                    {
                        "id": "ae7a16ae25dfb2852341eb8232cb9b05426c5414cab65e637976efbc9048da67", 
                        "offer_id": "0a3f749808c168528ba01a911ea63ee99a1eee3a7a6787dbd2159ebb6f4d372b",
                        "redemption_code": "089032",
                        "status": "acquired",
                        "acquired_at": "2011-03-11 10:36:51",
                        "barcode": {
                            "url": "...",
                            "width": "...",
                            "height": "..."
                        },
                        "print_url": "..."
                    },
                    {
                        "id": "85b3b0d995262dfbf3386c0c290e96558c1d5609ca5c46ea755f5404377651c2", 
                        "offer_id": "0a3f749808c168528ba01a911ea63ee99a1eee3a7a6787dbd2159ebb6f4d372b",
                        "redemption_code": "740092",
                        "status": "acquired",
                        "acquired_at": "2011-03-11 10:36:51",
                        "barcode": {
                            "url": "...",
                            "width": "...",
                            "height": "..."
                        },
                        "print_url": "..."
                    }
            }
        ]

    }
}

See order placing examples at Order resource page.

Clip Coupon

POST /offers/<offer_id>/clips

curl -k -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers/<offer_id>/clips' -d '{
    "clip": {}
}'

When a customer clips a coupon in your application you create a clip in Adility and get a voucher for your customer.

Request

{
    "clip": {}
}

Response

HTTP/1.1 200 OK
{
    "status": "OK",
    "clip": {
        "voucher": {
            "id": "d8ee308f3a8463fcffc08e7af1b6e37b0cdd085fcb9e65a97bd6d47fefd5b456", 
            "offer_id": "0a3f749808c168528ba01a911ea63ee99a1eee3a7a6787dbd2159ebb6f4d372b",
            "redemption_code": "589233",
            "status": "acquired",
            "acquired_at": "2011-02-18 18:39:21",
            "activation_date": "2011-02-18",
            "expiration_date": "2012-01-31",
            "barcode": {
                "url": "...",
                "width": "...",
                "height": "..."
            },
            "print_url": "..."
        }
    }
}

Cancel Order

Sometimes you need to cancel an order. You can do it by setting the order status to cancelled.

{
    "order": {
        "status": "cancelled"
    }
}

After the order cancellation all vouchers purchased within this order are marked as cancelled as well.

See order canceling examples at Order resource page.

Cancel Voucher

{
    "voucher": {
        "status": "cancelled"
    }
}

You can cancel a single voucher. 

PUT /offers/<offer_id>/vouchers/<voucher_id>

curl -k -X PUT -H "Content-Type: application/json" -H "Accept: application/json" -H "X-ADILITY-API-KEY: <your_api_key>" 'http://testapi.adility.com/distribution/beta/offers/<offer_id>/vouchers/<voucher_id>' -d '{
    "voucher": {
        "status": "cancelled"
    }
}'

Advanced Cases

Aside to the basic flow of Distribution API Adility supports a number of advanced features.
  • Accounts. Designed for platforms that host consumer facing applications.
  • Reservations. Reservation is designed to allow you reserve a certain number of vouchers and they are no more available for others.
  • Promotions. Promotion is designed to represent a unit in your deal schedule.
  • Instant Offers. Instant offers can be acquired by consumers only within a certain time frame along the day.
  • Bundle Deals. This type of offers is suppose to entice customers come to advertiser location more then once.
  • Checkin Coupons. Customer obtains a checkin coupon only after he checks in at a location a few times.
These features use specific resources and some extra attributes in basic resources.

Manage Accounts

If you host customer facing applications for publishers you may need accounts in order to assign reservations and orders to a specific publisher on your end.

Create Account

POST /accounts

Creates an account.

{
    "account": {
        "name": "Spas Magazine",
        "website_url": "http://www.spas-magazine.com"
    }
}

Account status is pending after creation. Adility team reviews the account and sets the status to active.

{
    "status": "OK",
    "account": {
        "id": "680da8eb1d01505570bed1887f0f3952d5e2ec8345469d34872c9541ec0600e8",
        "name": "Spas Magazine",
        "website_url": "http://www.spas-magazine.com",
        "status": "pending"
    }
}

You can not assign any objects to the account until it is activated.

Update Account

You can change the account attributes name and website_url. Also, you can cancel an account by setting the status to cancelled.

{
    "account": {
        "status": "cancelled"
    }
}

Delete Account

Account can be deleted if there is no object assigned to it. Otherwise you will get an error.

DELETE /accounts/<account_id>

If you don't need an account but you already have objects assigned to it you should cancel the account.

Manage Reservations

Offers mostly are shared between distributors and there is no guarantee that the offer that you have chosen and scheduled for tomorrow is actually gonna be available tomorrow. It may just be sold out. Reservation is designed to help you protect yourself from missing offers. You reserve a certain number of vouchers by creating Reservation and they are no more available for others.

By default reservations are disabled for distributors. If you think you want to use this feature send us a request to api@adility.com.

Create Reservation

POST /offers/<offer_id>/reservations

You should take into account following restrictions:
  • start_date can't be more then 7 days from creation_date.
  • end_date can't be more then 14 days from creation_date.
  • quantity_reserved can't be greater then maximum_reservation_quantity set to you.
  • quantity_reserved can't be greater then 75% of quantity_in_stock on the offer.
You can read about maximum_reservation_quantity in User.

Request

{
    "reservation": {
        "offer_id": "...",
        "quantity_reserved": "100",
        "start_date": "2011-03-13",
        "end_date": "2011-0319"
    }
}

Reservation can not be made for a period of time longer then 7 days. Also, start_date can't be more then 7 days from creation_date.

Response

{
    "status": "OK"
    "reservation": {
        "id": "15f479054487b5297e3b1a1288ced592a4c4eba913b4ef3b8c2765533c1ef5c4",
        "offer_id": "...",
        "quantity_reserved": "100",
        "quantity_in_stock": "100",
        "start_date": "2011-03-13",
        "end_date": "2011-03-19",
        "creation_date": "2011-03-12",
        "status": "active"
    }
}

Update Reservation

You can update start_date, end_date and quantity_reserved. All restrictions above are applicable. 

Use Reservation in Orders

If you want to use a reservation for a specific order you should set reservation_id for the corresponding order item.

{
    "order": {
        "items": [
            {
                ...
                "reservation_id": "15f479054487b5297e3b1a1288ced592a4c4eba913b4ef3b8c2765533c1ef5c4"
            }
        ]
    }
}

Delete Reservation

Reservation can be deleted only if it was not used for any order.

DELETE /reservations/<reservation_id>

Manage Promotions

If you sell more then 50 vouchers a day per offer and you have a kind of schedule for offers in your application you will be obliged to create Promotion each time you feature an offer. This requirement comes from advertiser operations as advertisers need time to get prepared for customers you might bring to them.

Create Promotion

POST /promotions

Creates a promotion for specific dates. You also can set reservation_id and account_id if you have them.

{
    "promotion": {
        "offer_id": "0a3f749808c168528ba01a911ea63ee99a1eee3a7a6787dbd2159ebb6f4d372b",
        "start_date": "2011-03-16",
        "end_date": "2011-03-18",
        "reservation_id": "15f479054487b5297e3b1a1288ced592a4c4eba913b4ef3b8c2765533c1ef5c4",
        "account_id": "680da8eb1d01505570bed1887f0f3952d5e2ec8345469d34872c9541ec0600e8"
    }
}

Update Promotion

You can update only start_date and end_date for promotions.

{
    "promotion": {
        "id": "w8e6r8sd6f86wer86986gw8e6f98w6fd9g8gw68g6f88wgr6we9r8768w76r592e",
        "start_date": "2011-03-17",
        "end_date": "2011-03-19"
    }
    
}

Delete Promotion

Promotion can be deleted if it was not assigned no any other objects like OrderItem.

DELETE /promotions/<promotion_id>

Selling Instant Offers

You can build an application set to promote instant offers to consumers. Instant offers can be shown to consumers and acquired by them only within a certain time frame along the day. For example, an advertiser can provide a great discount at morning hours when the foot trafic is low. Instant offers is a good fit for mobile geo applications.

If you want to query only instant offers you should set the query parameter instant_offers to true. If you set this parameter to false instant offers won't be included in the result set. If the instant_offers parameter is not used in the query the result set contains all offers regardless if they are instant or not.

Instant offers have restrictions defined by time_frames attribute of offer restrictions.

{
    "offer": {
        "restrictions": {
            "time_frames": [
                {
                    "week_day": "Mon"
                    "from": "10AM"
                    "to": "11AM"
                },
                {
                    "from": "4:30PM"
                    "to": "6:00PM"
                }
            ]
        }
    }
}

Neither placing an order nor clipping a coupon will succeed at a time different then the time frames.

Selling Bundle Deals

This type of offers is suppose to entice customers to come to advertiser location more then once. From consumers prospective bundle deals have a few coupons with different discounts. These coupons are presented by BundleItem resource and listed as items attribute of the offer. The main difference in placing orders for bundle deals is that you get more then one voucher for an offer. 

For example, there's a bundle deal with 3 bundle items in it. When you place an order with quantity 2 for this offer you get 6 vouchers in the response which is 2x3.  

Checkin Coupons

Offers of this type entice customers to return to advertiser location. Customer obtains a checkin coupon only after he checks in at a location a few times. The number of times required to get a checkin coupon is set by the checkins_required attribute of an offer.

Check In at a Location

When a customer is at the advertiser location he can check in in your application and your application creates a checkin in Adility.

POST /offers/<offer_id>/checkins

You need to pass lat/lng attributes of the current customer location as well as customer_id uniquely identifying the customer in your system.

{
    "checkin": {
        "offer_id": "...",
        "location": {
            "lat": "",
            "lng": ""
        },
        "customer_id": "3423437"
    }
}

you get the checkins_remained attribute in the response. If it equals to 0 you can clip the coupon and provides a voucher to the customer.

{
    "status": "OK",    
    "checkin": {
        "offer_id": "...",
        "location": {
            "lat": "",
            "lng": ""
        },
        "customer_id": "3423437",
        "registered_at": "2011-03-11 11:03:29",
        "checkins_remained": "0"
    }
}

Clip a Checkin Coupon

If the checkins_remained of the checkin equals to 0 you can clip the coupon for the customer.

{
    "clip": {
        "customer_id": "3423437"
    }
}

After the coupon is clipped checkins counter for the customer is set back to checkins_required of the offer.

Next Step: User API.

Comments