Overview

The Sellside API is a RESTful API to manage ads either for your own account or on behalf of other users. The base URLs for the API are:

Tenant

Env

Endpoint

Marktplaats

Sandbox

https://admarkt.demo.qa-mp.so/api/sellside

Production

https://admarkt.marktplaats.nl/api/sellside

Kijiji Canada

Sandbox

https://admarkt.qa10.kjdev.ca/api/sellside

Production

https://admarkt.kijiji.ca/api/sellside

2dehands Belgium

Sandbox

https://admarkt.demo-2dehands.qa-mp.so/api/sellside

Production

https://admarkt.2dehands.be/api/sellside

Kleinanzeigen.de

Sandbox

https://internet.ka.pre-prod.icas.io/api/sellside

Production

https://admarkt.kleinanzeigen.de/api/sellside

With this the full URL for retrieving ad 1234 for the current customer on Marktplaats Production becomes:

https://admarkt.marktplaats.nl/api/sellside/ad/1234

Authentication

Authentication is provided using OAuth2 tokens and the so called Authorization Code Grant which means that you need a client id and client secret to access the api with an access token that the API provides. It is not possible to use username and password to get an access token.

To request a client id and secret please ask your contact at the respective tenant (marktplaats, kijiji.ca, tweedehands). Your contact can also send you an invite for our Discord channel, where you can go for maintenance notifications and support.

See the Authentication section for the full details and also the OAuth 2.0 website.

Media Types

Each resource has a specific media type of the following form to support content negotiation and versioning:

application/sellside.{entity}-{version}+json;charset=utf-8

The version field is mandatory.

The media type is used for the Content-Type and Accept headers.

This allows us to change the structure of a response without breaking existing code since you have to request the new content type while the old version is still available for some time. For backwards compatible changes like adding a new field to an existing structure we will not change the version number.

Content-Type and Accept Headers

Every request must set the Accept header to:

<Expected Media Type>, application/json

This permits the server to generate the response in the format the caller expects. application/json is required to return the error response.

Additionally, each POST and PUT request must also set the Content-Type header to:

<Media Type of the body content>

Image Downloads

Images & feeds are downloaded from the following ip addresses. Ensure that all image URLs are accessible by these ip addresses and that there is no rate limit.

  • 5.255.156.110 (Production)

  • 5.255.156.126 (Production)

  • 3.64.37.25 (Production)

  • 18.194.96.182 (Production)

  • 3.72.155.39 (Production)

  • 34.253.123.82 (Production)

  • 34.246.217.218 (Production)

  • 52.214.29.214 (Production)

  • 3.98.109.128 (Production - Canada IP for Clients with Geo-blocking)

  • 3.99.27.64 (Production - Canada IP for Clients with Geo-blocking)

  • 3.97.250.121 (Production - Canada IP for Clients with Geo-blocking)

  • 3.68.139.10 (Sandbox)

  • 3.77.63.23 (Sandbox)

  • 3.77.131.63 (Sandbox)

  • 91.211.74.6 (Sandbox)

To reduce the latency when updating an ad we suggest that the response contains either an ETag and/or Last-Modified header which only changes when the image itself has changed. It should also be possible to check these headers using a HEAD request.

Keep in mind that when feeds are imported, we potentially have to download many images. Make sure your hosting can handle bursts of image downloads.

Feed Downloads

Feeds & images are downloaded following ip addresses. Ensure that all feed URLs are accessible by these ip addresses and that there is no rate limit.

  • 5.255.156.110 (Production)

  • 5.255.156.126 (Production)

  • 3.64.37.25 (Production)

  • 18.194.96.182 (Production)

  • 3.72.155.39 (Production)

  • 34.253.123.82 (Production)

  • 34.246.217.218 (Production)

  • 52.214.29.214 (Production)

  • 3.98.109.128 (Production - Canada IP for Clients with Geo-blocking)

  • 3.99.27.64 (Production - Canada IP for Clients with Geo-blocking)

  • 3.97.250.121 (Production - Canada IP for Clients with Geo-blocking)

  • 3.68.139.10 (Sandbox)

  • 3.77.63.23 (Sandbox)

  • 3.77.131.63 (Sandbox)

  • 91.211.74.6 (Sandbox)

We typically run our feed import at 07:00 in the morning (local time), but we can trigger additional import runs at any time if we deem it necessary (due to maintenance, tests, whutnot).

Feed files usually contain links for the images of the ads too, so make sure you have your whitelisting and/or rate limiting in order.

Customize response body

Every call which returns a response body can have this customized using _include and _exclude parameters. These parameters define which fields to include in or exclude from the response body. When both _include and _exclude have a value, the _exclude value will be ignored. By default, _include is set to all fields and _exclude is empty.

Using _include will require you to specify each key in the path of the data that you wish. For example, if you’re calling GET /ad v5 and you want the ad ID and title, you’ll have to provide _include=ads,id,title.

Here’s an example of the _include parameter used while calling GET /ad v5. The normal response has the following shape:

{
  "ads": [
    {
      "id": 42,
      "title": "Brother Fax voor 99,99",
      "status": "ACTIVE",
      ....
      <many more fields>
      ....
    },
    {
    "id": 46,
    "title": "Brother Printer voor 69,99",
    "status": "ACTIVE",
    ....
    <many more fields>
    ....
    },
    ....
    <many more ads>
    ...
  ],
  "count": 4241,
  "nextPageToken": "eyJpZCI6MTAwMTgzMTc1MCwic3RyaW5nX3ZhbHVlIjpudWxsLCJpbnQ2NF92YWx1ZSI6MTM0MDIxNzg1OTc5MH0"
}

If you want to paginate through all ads and only get the id & status then you should call GET /api/sellside/ad?_include=ads,id,status,nextPageToken to get the following result:

{
  "ads": [
    {
        "id": 42,
        "status": "ACTIVE",
    },
    {
        "id": 46,
        "status": "ACTIVE",
    },
    ....
    <many more ads with only id & status>
    ...
  ],
  "nextPageToken": "eyJpZCI6MTAwMTgzMTc1MCwic3RyaW5nX3ZhbHVlIjpudWxsLCJpbnQ2NF92YWx1ZSI6MTM0MDIxNzg1OTc5MH0"
}

and the next page, using the nextPageToken would become GET /api/sellside/ad?_include=ads,id,status,nextPageToken?pageToken=eyJpZCI6MTAwMTgzMTc1MCwic3RyaW5nX3ZhbHVlIjpudWxsLCJpbnQ2NF92YWx1ZSI6MTM0MDIxNzg1OTc5MH0

When providing _exclude then you don’t need to provide the full path; any element with a key that matches an element of the _exclude parameter will be omitted.

Furthermore, some calls allow for a _body parameter, defining whether there should be any data in the response body at all. Default of _body is true (returning data). When _body is false, _include and _exclude will be ignored.

Dates and Times

All date/time values are specified in ISO 8601 Combined date and time in UTC format.

Prices and Currencies

Monetary amounts like prices and budgets are currently undergoing changes; newer versions of endpoints mention whether the amount is either in cents or in micro units of the currency the local markets. If this is not mentioned, this is represented as (euro/dollar) cents. Currencies are specified as three character ISO 4217 code. 1 euro/dollar == 100 cents == 1000000 micros.

HTTP Response Codes and Error Handling

To retrieve, update and delete resources with the Sellside API you use the standard HTTP verbs GET and PUT. If the resource exists and the request was successful the server responds with 200 OK. If the resource does not exist the server responds with 404 Not Found.

To create a new resource you perform a POST request to which the server responds with 201 Created and a Location header containing the URL of the new resource.

All requests are validated before they are being executed by the server. If the validation fails the server responds with 400 Bad Request and an error response which contains a list of the errors. More information can be found under Error Handling.

Dry-Run Request Validation

The API supports dry-run validation of requests which modify resources. To validate a request without executing it add _validate=true to the request URL. If the validation succeeds the server returns 200 OK and an empty body. Otherwise, the server returns 400 Bad Request with the list of errors. The following endpoints support dry-run validation:

Vendor Ids

For ads and campaigns, it is possible to provide a so-called vendorId. The intention of this vendorId is to allow the API partner to use their own primary key on this ad or campaign. The API partner can also fetch the ad or campaign _by_ vendorId - see GET /ad/byVendor/{vendorId} and GET /campaign/byVendor/{vendorId} for details - to get the necessary primary key to perform other operations through the API. This means the API partner does not need to keep an explicit mapping between their own primary key and the one generated by our system, making integration simpler.

Such a vendorId cannot, once set, be changed or removed. It has become as strong as the primary key, in combination with the seller account that’s being used. This also means that within all ads of a seller, the vendorIds must be unique. Similarly, within all campaigns of a seller, the vendorIds must be unique.

Keep in mind that vendorId is case-insensitive and only allows windows-1252 (also known as Latin-1) characters. For example, an ad is created with vendorId “abc123”, and this ad can be retrieved by vendorId “Abc123”. If you want to create another ad with vendorId “aBc123”, the creation will fail. Because “abc123”, “Abc123” and “aBc123” are identical. The retrieval will have the same capitalization used on insertion. For example: an ad is created with vendorID “Abc123”, the ad can be retrieved by vendorID “abc123” (lower case A) but the payload will returned with vendorID “Abc123”, same case as insertion.

Page tokens

In some calls, while calling for a list of items, you get a response containing a nextPageToken. This encoded token is necessary for efficient pagination. To get the next list (page) of items, you repeat the exact same call, but you add the &pageToken=<encoded value> parameter to the call. In essence, it contains encoded information on where the returned result ended, so it can serve as additional filters in the call for the next result set, making that call more efficient. For the very first page, a pageToken should not be provided. For any following page, callers should use the exact same request with an added pageToken parameter. The value for the pageToken parameter for page N+1 is the nextPageToken field in the response of your call to fetch page N. When a response does not contain a nextPageToken you have reached the last page of results and there are no more to fetch.