NOTE: this is work in progress
The first version of the API will be available under /api/v0/
.
Requests that fail return the appropriate HTTP status codes, with JSON response body describing the error in more detail.
An example error object:
{
"error": {
"message": "Some message describing the failure, that can be displayed to the user."
}
}
In the future, more fields can be added to the "error" object. E.g status codes, back traces, form validation information, etc. If possible, keep the fields the same as https://google-styleguide.googlecode.com/svn/trunk/jsoncstyleguide.xml#Reserved_Property_Names_in_the_error_object
The standard HTTP error codes we use:
Status | Description |
---|---|
400 | Bad request. Probably some required field or query string parameter is missing from the request. |
401 | Authentication required. Typically sent when no Authorization header is present in a request, or if it is invalid. If the token is valid, but doesn't give access to the requested resource, a 403 is returned. |
403 | Permission denied. Returned if a user requests a resource that his/her role does not give access to. E.g. a designer trying to operate on dynamic inputs. |
404 | File not found. Returned if an object does not exist. |
405 | Method not allowed. In case the method is not implemented. |
500 | Generic error in case something is wrong on the server. These conditions should be tracked down and fixed. |
All requests except a few authorization-related requests require an Authorization
header with the "lemonpi"
scheme, containing a token. These tokens are returned by the /login
and /refreshtoken
endpoints described below.
Path | Method | Description |
---|---|---|
/login | POST | Data should have email and password fields. E.g. {"email": "mechiel.lukkien@bluemango.nl", "password": "test1234"} . Returns an object with fields "user" and "token". The "user"-value is the user object that was logged in. The "token"-value is a string that should be passed in later Authorization headers. The token is of the form v0.<userid>.<expiration-time>.<signature> . "v0" is a version, userid is a number, expiration-time is a base 10 epoch time, signature is an opaque string. Tokens are valid for a relatively short time (24 hours currently), and a fresh token can be retrieved by calling the /refreshtoken endpoint. |
/refreshtoken | POST | No body needs to be sent. The authorization token contains the user id for which a new token should be given out. The response is the same as for /login . |
There is no logout endpoint. Tokens are stateless. Existing tokens can be invalidated by setting a new password.
Example use of a token $token
received from the login endpoint:
GET /some/api/endpoint
Authorization: lemonpi $token
Path | Method | Description |
---|---|---|
/advertisers | GET | Return list of advertisers. |
/advertisers | POST | Create new advertiser. |
/advertisers/:id | GET | Return advertiser. |
/advertisers/:id | PATCH | Save/update advertiser. Note that the active field cannot be changed through PATCH. |
/advertisers/:id/status | POST | Set new status. Body must be {"active": true} or {"active": false} . |
/advertisers/:id/adserveraccountconfigurations | GET | Return list of adserver account configurations. |
/advertisers/:id/adserveraccountconfigurations | POST | Create an adserver account configurations. |
/advertisers/:id/adserveraccountconfigurations/:id | DELETE | Removes an adserver account configurations. |
/advertisers/:id/adserveraccountconfigurations/:id | PATCH | Field to set: isDefault , apiAdvertiserId . If isDefault is set to true , the isDefault field of the existing default configuration is set to false. |
Field | Type | Description |
---|---|---|
id | number | Unique advertiser id. |
active | boolean | Whether advertiser is active. Bannersets, dynamic inputs, adsets, etc cannot be assigned to an inactive user. |
name | string | Descriptive name of advertiser. Must be unique. |
code | string | Short code for advertiser, used in URLs. Must be unique. |
adminEmail | string | E-mail address that will receive automated emails about advertiser. E.g. error or analytics reports. Can be null. |
appnexusAdvertiserId | number | Advertiser ID for this advertiser in AppNexus. Can be null. |
{
"id": 1,
"active": true,
"name": "Vodafone",
"code": "vf",
"adminEmail": "tim.wijnen@bluemango.nl",
"appnexusAdvertiserId": 123
}
Path | Method | Description |
---|---|---|
/bannersets | GET | Return list of bannersets. Each bannerset includes stat* statistics. |
/bannersets | POST | Create new bannerset. |
/bannersets/:id | GET | Return single bannerset, including stat* statistics. |
/bannersets/:id | PATCH | Update bannerset. Fields that can be modified: name , approved . Changing the approved field also sets the fields of all creatives in the bannerset to the same value. |
/bannersets/:id | DELETE | Delete bannerset. Only allowed when not in use in an adset. |
/bannersets/:id/status | POST | Activate or deactivate the banner set. Body must be {"active": true} or {"active": false} . |
/bannersets/:id/livepreview | POST | Create a new live preview for the bannerset. The returned JSON object contains a field "previewId" that can be used for the /preview endpoint. The resulting object has fields for bannerset, advertiser, creatives, and input & proposition. |
/bannersets/:id/review | POST | Creates a new review for the bannerset. The request JSON specifies the initial selection for reviewing the bannerset e.g.: {"creativeId" : 1, "propositionIds" : [[1,2],[15,16]]} . The response JSON contains a sig that is valid for 2 hours and can be used to retrieve review data without logging in. |
/preview | GET | Returns the same object as returned by a POST on /bannersets/:id/livepreview or /adsets/:id/bannersets/:id/livepreview . A query string parameter previewId is required. No authentication is required for this endpoint. |
/bannersets/:id/creatives | POST | Add new creative to this set. The file named creative must be sent (a splash banner zip file). The response is the new banner object that has been added to the banner set. |
/bannersets/:id/creatives/:id | GET | Get single creative. |
/bannersets/:id/creatives/:id | PATCH | Update creative. Only field approved can be updated, and it may cause a change to approved for this creative's bannerset. |
/bannersets/:id/creatives/:id | DELETE | Completely remove creative. Only allowed when creative has never been published. This might also cause a change to the approved field on this creative's bannerset. |
/bannersets/:id/creatives/:id/preview | POST | Creative URL that returns live preview of creative, one that includes propositions to display. A JSON body should be posted that looks like this: {"type":"dynamic", "propositionIds":[[1], [123,234]]}, or like this: {"type":"fallback"}. The response is JSON like this: {"width":300,"height":200,"previewUrl":"..."}. The value of previewUrl can used as "src" for an iframe, that displays a live preview of the creative. |
/bannersets/:id/creatives/:id/livepreview | GET | Returns HTML that can be opened in an iframe, it will display the live preview. A query string parameter previewId is required. No authentication is required for this endpoint. |
{
"active": true,
"creativeIds": [
1,
2,
3
],
"advertiserId": 1,
"id": 1,
"name": "Promo Tatoo Variant1",
"approved": false,
"statCR": 0.04065040650406504,
"statCTR": 0.10569105691056911,
"statClicks": 13,
"statConversions": 5,
"statViews": 123,
"timeFirstActivation": 0,
"timeLastDeactivation": 1412778134
}
timeFirstActivation
and timeLastDeactivation
are epoch timestamps, used for daterange filtering. timeLastDeactivation
may come before timeFirstActivation
.
{
"active": true, # bannerset active?
"name": "name of bannerset",
"adset": {
"active": true,
"name": "name of adset"
}
"creatives": [
{
"name": "name of creative",
"width": 320,
"height: 240,
"url": "http://staticpreview.com/",
"liveUrl": "http://livepreview.com/"
},
...
]
}
Path | Method | Description |
---|---|---|
/dynamicinputtypes | GET | Get list of dynamic input types. |
/dynamicinputtypes/:id/keys | GET | Get list of valid keys for a single dynamic input type |
[
{
"code": "scraper",
"createdAt": 1450697876,
"id": 1,
"manualKeys": false,
"manualPropositions": false,
"name": "Scraper",
"updatedAt": 1450697876
},
{
"code": "geocountry",
"createdAt": 1450697876,
"id": 2,
"manualKeys": false,
"manualPropositions": true,
"name": "Geo by country",
"updatedAt": 1450697876
}
]
[
{
"createdAt": 1450697876,
"id": 1,
"key": "default",
"label": "Default",
"updatedAt": 1450697876
},
{
"createdAt": 1450697876,
"id": 2,
"key": "aw",
"label": "Aruba",
"updatedAt": 1450697876
},
...
{
"createdAt": 1450697876,
"id": 247,
"key": "za",
"label": "South Africa",
"updatedAt": 1450697876
},
{
"createdAt": 1450697876,
"id": 248,
"key": "zm",
"label": "Zambia",
"updatedAt": 1450697876
},
{
"createdAt": 1450697876,
"id": 249,
"key": "zw",
"label": "Zimbabwe",
"updatedAt": 1450697876
}
]
Path | Method | Description |
---|---|---|
/dynamicinputs | GET | Return list of dynamicinputs. |
/dynamicinputs | POST | Create new dynamicinput. Specify at least fields name , dynamicinputtypeId , advertiserId . Field active is optional, defaults to false. |
/dynamicinputs/:id | GET | Get single dynamicinput. |
/dynamicinputs/:id | PATCH | Save/update dynamicinput. advertiserId cannot be modified after creation. |
/dynamicinputs/:id | DELETE | Remove the dynamicinput. Only allowed if the dynamic input is not used in an adset. Any propositions will be removed as well. |
/dynamicinputs/:id/status | POST | Set new status. Body must be {"active": true} or {"active": false} . |
/dynamicinputs/:id/resetscrapes | POST | Reset scrape counts to 0 for all propositions. Only valid on scraper inputs. |
/dynamicinputs/:id/deletepropositions | POST | Delete all propositions in this input, also removing all statistics for these propositions in adsets, even historic data. Only valid on scraper inputs. |
/dynamicinputs/:id/propositions | GET | Get list of propositions. Pagination works on this list. Return stat* statistics, and statScrapes for number of scrapes. |
/dynamicinputs/:id/propositions | POST | Create new proposition. Only allowed for dynamicinputs for non-scrapers. active must be false, only after having uploaded an image can the proposition be activated. |
/dynamicinputs/:id/propositions/categories | GET | Retrieve all categories used by propositions in this dynamic input. An object with field categories is returned, its value is a list of strings. |
/dynamicinputs/:id/propositions/:id | GET | Get single proposition. |
/dynamicinputs/:id/propositions/:id | PATCH | Change fields in proposition. Not for scraper propositions. |
/dynamicinputs/:id/propositions/:id | DELETE | Remove proposition, including any statistics that are related to this proposition. The default proposition of a custom dynamic input cannot be removed. |
/dynamicinputs/:id/propositions/:id/status | POST | Set new status. Body must be {"active": true} or {"active": false} . |
/dynamicinputs/:id/propositions/:id/imageurl | POST | Upload new image (named image ) for this proposition. Only valid for non-scraper inputs. |
/dynamicinputs/:id/propositions/:id/imageurl | DELETE | Remove image for this proposition. Only valid for non-scraper inputs. |
/dynamicinputs/:id/propositions/:id/logourl | POST | Upload new logo (named image ) for this proposition. Only valid for non-scraper inputs. |
/dynamicinputs/:id/propositions/:id/logourl | DELETE | Remove logo for this proposition. Only valid for non-scraper inputs. |
/dynamicinputs/:id/errors | GET | Get list of errors. Pagination works on this list. |
{
"id": 1,
"name": "my dynamic input",
"dynamicinputtypeId": 1,
"key": "",
"active": true,
"advertiserId": 1,
"scraperScript": "(function() { ... })()",
"errorCount": 10,
"propositionCount": 100
}
{
"active": true,
"clickUrl": "http://click.me/",
"custom1": null,
"custom2": "some text",
"custom3": null,
"custom4": null,
"description": "awesome phone",
"dynamicinputId": 1,
"errorCount": 20,
"id": 1,
"imageUrl": "http://image.me/",
"key": "01deadbeef",
"logoUrl": null,
"priceDiscount": null,
"priceNormal": "123,45",
"statCR": 0.002,
"statCTR": 0.04,
"statClicks": 40,
"statConversions": 2,
"statScrapes": 500,
"statViews": 1000,
"stickerText": null,
"title": "somePhone"
}
{
"id": 1234,
"logLevel": "error",
"message": "a one-line descriptive error message",
"time": 1413599691,
"dynamicinputId": 123,
"propositionId": null
}
Valid values for logLevel
are: emergency
, alert
, critical
, error
, warning
, notice
, info
, debug
.
If propositionId
is null, the error is about the input in general, not a specific proposition.