API documentation

The API allows you as a client to send content to Besedo’s Implio for content moderation services. We at Besedo will then apply the agreed editorial rules and either accept, refuse or optionally edit the content.

Usage

Introduction.

The Implio API is built on a RESTful HTTP architecture where the client (your application) makes HTTP requests to perform specific functions within the Implio system. All data must be passed as JSON. All requests are authenticated with an API key, which is verified by the API server before allowing any operations. All communication with the Besedo API is done over SSL. In addition to the RESTful HTTP API, we also support webhooks for receiving processed ads which also is the recommended integration method for retrieving ads.

Authentication.

To be able to interact with the Implio system you need to be authenticated. Each request is signed by you the caller using a predefined API key, which is verified by Implio before allowing any operation. You will need to add the key in the header to each of your HTTP call. We use the key to both verify that you are allowed to send in content to us and to identify customers to make sure that only you can access your information.

Since the API is stateless there is no session that you need to keep track of at your side, instead each request should include the API key in the header.

Headers.

To be able to communicate with the Implio System these two headers need to be set.

HeaderValue
Content-Typeapplication/json
X-Api-KeyAPI key provided by Besedo

Example POST content to Implio Engine API

curl "https://api.implio.com/v1/ads" -H "X-Api-Key:
XhETCYeYJSaN4YQKucIXdDWlUBWIsAmREsZn3kDzS3tnvR" -H "content-type: 
application/json" -d '[ 
   { 
     "id": "23445", 
     "content": { 
       "title": "My title", 
       "body": "I want to sell XYZ." 
     } 
   }
 ]'

Available Resources

To be able to communicate with the Implio System these two headers need to be set.

GET/_health Success status: 200

A check to make sure that the service is up and is accepting calls.

{ 
   status: alive 
}
POST/ads Success status: 202

Send in a batch of content in the format of a classified ad to us for moderation. Body should be formatted as an array of objects containing the ads (see Ad format)

 [{id:22, content…},{id:23, content…}]

Once we have accepted the ads in our system and begun processing them we will send back a response with an array of objects each containing your id and the id we put on the content in our system.

We will attach a batchId to be able to identify each unique batch.

The maximum amount of ads in one batch is set to 1000 and the maximum payload size is set to 1mb

Detailed error reports for invalid data:

By default the result will detail the first error spotted with invalid ads sent in (one entry per rejected ad under “rejected”). By setting query parameter verboseErrors like so.

/ads?verboseErrors=true

..one may receive a more detailed report for all JSON schema validation errors, instead of merely the first one. This is very handy when integrating with the end point, debugging problems etc.

Note: verboseErrors should not be utilised in actual production or for larger posts as it consumes more resources server-side and results in noticeably longer response times. Be sure not to make use of ?verboseErrors=true for anything except initially upon testing integration etc.

{ 
  "batchId": "b5ecef", 
  "accepted":[
    { 
      "clientId": "22", 
      "taskId": "2f138" 
    }, 
    {
      "clientId": "23", 
      "taskId": "2f138" 
    } 
  ], 
  "rejected":[ ] 
}
GET/ads?timestamp=[milliseconds since unix epoch] Success status: 200

Get ads which are processed after the given timestamp (unix/epoch time). Only ads with a more recent (higher) timestamp than the timestamp provided will be included in the response. The maximum amount of ads returned per request is 1000.

timestamp is specified in milliseconds since unix epoch.

The response is an object containing array of objects where each object is the complete ad in the same format as passed to Implio. If any field has been changed the new value will then be set on the ad object (e.g category changes or cleaning out dirty words).

The proposed status is added to the response body.

If the result is refused, the reasons will be added to the output.

Optionally a moderator can select to append feedback to the ad. In this case it is added in the result.feedback array. Currently the only possible feedback is the one shown in the example to the right.

matchingFilters contains information on which filters that has been matched on the provided response body.

A matched filter can contain an optional notice and wordHighlighting property. These features are controlled through the user interface.

There is a packedAt property, which is the time when the ad was packed and ready for delivery back to the customer.

In the response there is also pollingInfo object sent back. It contains the two properties

  • newTimestamp , timestamp in milliseconds since unix epoch of the last ad returned, this should be stored in the customers system and be used as input for the next polling.
  • newerAdsExist a boolean property that is true if there is currently newer ads in the system that can be collected.
{ 
   "pollingInfo": { 
     "newTimestamp": 1445518700257, 
     "newerAdsExist": false 
 }, 
 "ads": [ 
   { 
     "packedAt": 1445518700257,
     "ad": { 
       "id": "1", 
       "batchId": "b5ecef", 
       "taskId": "2f138f", 
       "content": { 
         "title": "Super cute Rabbit", 
         "body": "A fine rabbit." 
     } 
   }, 
   "result": { 
     "actorId": "name@email.com",
     "outcome": "approved", 
     "reasons": [], 
     "feedback": [ 
       { 
         id: "suggestImprovements", 
         name: "Suggest improvements to user." 
       } 
   ], 
   "matchingFilters": [ 
     { 
        "id": "5636ff91a14f7601009d2189", 
        "name": "refuse all", 
        "vote": "REFUSE", 
        "wordHighlighting": [ 
          { 
            "variableName": "$text", 
              "words": [ 
                {
                  "word": "test", 
                  "regex": "/\\btest\\b/gi" 
                }
             ]
          } 
        ], 
        "notice": { 
          "text": "My Notice Text", 
          "severity": "GOOD" 
        } 
     }
    ] 
   } 
  } 
 ] 
}
Outcome.

There are three possible outcomes from the moderation:

  1. approved
  2. refused
  3. no decision

If the outcome is refused the reasons is also sent back.

Ad Format

Content are passed into the API and retrieved from the API in JSON, see full example described below. Most fields are optional, see section on Mandatory fields for more info. But the structure of the ad is important and is described below. The structure is fixed but there is some flexibility to send custom fields, see the section on Customer specific fields.

Example Ad

{ 
  "id": "63137115", 
  "customerSpecific": {}, 
  "content": { 
    "title": "Super cute Rabbits", 
    "body": "4 cute rabbits born the 4:th of June for sale.", 
    "url": "http://best.ads.se/Stockholm/63137115.html", 
    "price": { 
      "amount": 100, 
      "currency": "SEK" 
    }, 
    "type": { 
      "id": "s", 
      "name": "For sale" 
    }, 
    "category": { 
      "id": "6083", 
      "name": "Rodents & Rabbits" 
    }, 
    "images": [ 
      { 
        "src": "http://best.ads.se/static/0/images/16/1608376350.jpg" 
      } 
    ], 
    "status": "published", 
    "createdAt": "2015-06-15T10:15:16.000Z", 
    "publishedAt": "2015-06-15T10:15:16.000Z", 
    "customerSpecific": {} 
  }, 
  "user": { 
    "id": "123456", 
    "name": "John Doe", 
    "phoneNumbers": [ 
      "070-123456" 
    ], 
    "emailAddresses": [ 
      "john.doe@gmail.com" 
    ], 
    "customerSpecific": {} 
  }, 
  "location": { 
    "city": "Stockholm", 
    "postalCode": "111 57", 
    "region": "Stockholm", 
    "countryCode": "SE", 
    "ipAddress": "192.168.0.1", 
    "customerSpecific": {} 
  } 
}
Mandatory fields.

The only mandatory fields are id , title & body . All other fields are optional, but you need to follow the structure. A minimal viable structure to send in would look like this:

Minimal moderation job example

[    
   {       
     "id": "63137115",     
     "content": 
       {         
         "title": "Super cute Rabbits",      
         "body": "4 cute rabbits born the 4:th of June for sale."     
       } 
   } 
]
Structure.

The ad is structured into four different sections:

  1. root
  2. content
  3. user
  4. location
root
PropertyTypeDescriptionRequired
idstringYour internal id for the adYes
customerSpecificobjectHere you can put your custom metadata, see below for more infoNo
content
PropertyTypeDescriptionRequired
titlestringHeading for your adYes
bodystringText body for your adYes
urlstringUrl to the ad on your web siteNo
priceobjectPrice infoNo
typeobjectType infoNo
categoryobjectCategory infoNo
imagesarray of objectsImage info objectsNo
statusstringStatus of the ad in your systemNo
createdAtdate string with time zoneDate when ad was created in your system (date time ISO 8601)No
updatedAtdate string with time zoneDate when ad was latest updated by user or admin on your site (date time ISO 8601)No
publishedAtdate string with time zoneDate when ad was public on your site (date time ISO 8601)No
adminUrlstringURL to the item in your control panelNo
customerSpecificobjectHere you can put your custom metadata, see below for more infoNo
content.price

The value of content.price may either be null (denoting no price data) or a complete object specifying both amount and currency.

PropertyTypeDescriptionRequired
amountnumberThe price listed in the adYes
currencystringISO 4217 Currency Code.Yes
content.type

Type of ad, could be for example “For sale” or “For rent”

PropertyTypeDescriptionRequired
idstringid of the type in your systemYes
namestringDisplay name of the type e.g “For sale”Yes
content.category
PropertyTypeDescriptionRequired
idstringid of the category in your systemYes
namestringDisplay name of the category e.g “Cars”Yes
content.images

An array of image objects. Each image object have only one property “src”

PropertyTypeDescriptionRequired
srcstringUrl to public imageYes
user
PropertyTypeDescriptionRequired
idstringId of user in your systemNo
namestringDisplay name of the user in your systemNo
phoneNumbersarray of stringsArray of phone numbersNo
emailAddressesarray of stringsEmail addressesNo
adminUrlstringURL to the item in your control panelNo
customerSpecificobjectHere you can put your custom metadata, see below for more infoNo
location
PropertyTypeCityRequired
citystringCityNo
postalCodestringPostal (zip) codeNo
regionstringRegionNo
countryCodestringTwo-letter country code according to ISO 3166No
ipAddressstringIp adress from where the ad is postedNo
customerSpecificstringHere where you can put your custom metadata, see below for more infoNo
Customer specific.

Each section have a predefined set of properties that you can use to send in data. Each section also have a customerSpecific property which can be used by you to send us data that we have not specified in the structure. You can name your keys as you like as long as you follow our naming convention. A key must start with a letter. Subsequent characters can be letters but also be digits (0-9). Keys are case sensitive.

Example valid customerSpecific data

"customerSpecific":{      
  "fuelType": "gasoline",   
  "gearbox": "automatic",   
  "mileage": 14100,   
  "demoCar": true 
}
Time zone information.

We use the time zone notation from ISO 8601 and wants our customers to specify the time zone offset from UTC for example 2015-06-15T10:15:16.000Z . It makes it possible for us to give you the correct time for moderation events regardless of where your business resides geographically. If no time zone is specified we will assume UTC.

See more information about ISO 8601:
https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators

Web Hook

You may register an endpoint that will be used for sending finished ads as soon as they are moderated. We will use this endpoint to invoke a HTTP request with the content of the ad, and the outcome of the moderation process. Any 2xx response code to this request will consider the delivery to be valid. If the delivery fails, we will keep retrying up to 5 times while doubling the timeout between each new retry, for the first retry the timeout is 5 minutes. We highly recommend using a secure endpoint (HTTPS) for this, and it needs to use a valid non-self-signed certificate. We will in the headers use the same API key you use when sending in ads, so you can be sure that we are the sender of the information.

To add Web Hook URL follow: Settings -> Api Integration

Example of data in the hook

{ 
  "ad": { 
    "packedAt": 1445518700257, 
    "ad": { 
      "id": "1", 
      "batchId": "b5ecef", 
      "taskId": "2f138f", 
      "content": { 
        "title": "Super cute Rabbit", 
        "body": "A fine rabbit." 
      } 
    }, 
    "result": { 
      "outcome": "approved", 
      "reasons": [], 
      "feedback": [ 
         { 
          "id": "suggestImprovements", 
          "name": "Suggest improvements to user." 
         } 
      ], 
      "matchingFilters": [ 
        { 
          "id": "5636ff91a14f7601009d2189", 
          "name": "refuse all", 
          "vote": "REFUSE", 
          "wordHighlighting": [ 
            { 
              "variableName": "$text", 
              "words": [ 
                { 
                  "word": "test", 
                  "regex": "/\\btest\\b/gi" 
                } 
              ] 
            } 
          ], 
          "notice": { 
            "text": "My Notice Text", 
            "severity": "GOOD" 
          } 
        } 
      ] 
    }
  } 
}

Best Practices

Notify Implio on changes by the user
When a user change an item on your site you should send it to Implio again. This is to make sure the latest version is always moderated. Add the updatedAt field as it will make sure you do not get the same update twice if your service accidentally sends the request twice.

On error from Implio API queue and retry
When an item can not be published to Implio due to a 500 error in Implio, queue it and retry it within a minute

Web hook
Make sure to output something else than 200 OK from your system if you can not consume the request and we will try again.