Skip to content

Instantly share code, notes, and snippets.

@codeorelse
Created January 6, 2016 10:44
Show Gist options
  • Save codeorelse/687bf68eb592fba4bb4f to your computer and use it in GitHub Desktop.
Save codeorelse/687bf68eb592fba4bb4f to your computer and use it in GitHub Desktop.

NOTE: this is work in progress

The first version of the API will be available under /api/v0/.

Error handling

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.

Authentication

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

Advertiser

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.

Example advertiser

{
    "id": 1,
    "active": true,
    "name": "Vodafone",
    "code": "vf",
    "adminEmail": "tim.wijnen@bluemango.nl",
    "appnexusAdvertiserId": 123
}

Banner set

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.

Example bannerset

{
    "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.

Example response for the /preview endpoint

{
    "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/"
        },
        ...
    ]
}

Dynamic input types

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

Example list of dynamic input types

[
    {
        "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
    }
]

Example keys for a dynamic input type

[
    {
        "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
    }
]

Dynamic input

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.

Example dynamic input

{
    "id": 1,
    "name": "my dynamic input",
    "dynamicinputtypeId": 1,
    "key": "",
    "active": true,
    "advertiserId": 1,
    "scraperScript": "(function() { ... })()",
    "errorCount": 10,
    "propositionCount": 100
}

Example proposition

{
    "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"
}

Example error log

{
    "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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment