Overview Edit the file on GitHub

Table of Contents

Authorization

To access any API v3 resource an access_token is necessary. Get one using OAuth 2.0 Authorization.

Schema

All API access is over HTTPS, and accessed from the api.skroutz.gr domain. All data is sent and received as JSON.

A list of all the example requests in this documentation as a Postman collection can be found here.

curl -XGET https://api.skroutz.gr/categories/999999999 \
  -H 'Accept: application/vnd.skroutz+json; version=3.1' \
  -H 'Authorization: Bearer your_access_token_here'

HTTP/1.1 404 NOT FOUND
Server: nginx
Content-Type: application/json; charset=utf-8
Vary: Accept-Encoding
Status: 200 OK
X-UA-Compatible: IE=Edge,chrome=1
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 1475076950
X-Runtime: 0.011315
X-DNS-Prefetch-Control: off
X-App: benjy
Transfer-Encoding: chunked
Date: Tue, 24 Sep 2013 10:49:50 GMT
X-Varnish: 1475076950
Age: 0
Via: 1.1 varnish
X-Origin: varnish2
X-Cache: MISS

[]

Blank fields are included as null instead of being omitted.

All timestamps are returned in ISO 8601 format:

YYYY-MM-DDTHH:MM:SSZ

Linked Resources

When you see Linked resources: some_resource in any of our resources it means you may choose to include/embed it as follows:

Example

Resource Foo has "Linked resources: bar"

Case: embed
  GET /foos/42?embed=bars
{
  "foo": {
    "id": 42,
    "bars": [
      {
        "id": 1,
        "baz": 42
      }
    ]
  }
}
Case: embed_ids
  GET /foos/42?embed_ids=bars
{
  "foo": {
    "id": 42,
    "bars": [1,2,3,4]
  }
}
Case: include
  GET /foos?include=bars
{
  "foos": [
    {
      "id": 42,
      "bars": [1,4]
    },
    {
      "id": 43,
      "bars": [3,4]
    }
  ],
  "bars": [
    {
      "id": 1,
      "baz": 42
    },
    {
      "id": 3,
      "baz": 42
    }
  ]
}

Pagination

Requests that return multiple items will be paginated to 25 items by default. You can specify further pages with the page parameter. You can also set a custom page size to 10 with the per parameter.

$ curl https://api.skroutz.gr/categories?page=2&per=10 \
  -H 'Accept: application/vnd.skroutz+json; version=3.1' \
  -H 'Authorization: Bearer your_access_token_here'

When there are other pages the response will contain the Link header.

Link

<https://api.skroutz.gr/categories?page=508&per=4>; rel="last",
<https://api.skroutz.gr/categories?page=3&per=4>; rel="next"

Note that page numbering is 1-based and that ommiting the page parameter will return the first page.

Rate Limiting

You can make up to a certain amount of requests for each OAuth token associated with your application.

We currently allow up to 100 requests per minute.

You can check the returned HTTP headers of any API request to see your current rate limit status:

$ curl -i https://api.skroutz.gr/categories/1440 \
  -H 'Accept: application/vnd.skroutz+json; version=3.1' \
  -H 'Authorization: Bearer your_access_token_here'

HTTP/1.1 200 OK
Date: Mon, 01 Jul 2013 17:27:06 GMT
Status: 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1465285680

The headers tell you everything you need to know about your current rate limit status:

X-RateLimit-Limit
The maximum number of requests that the consumer is permitted to make per minute.
X-RateLimit-Remaining
The number of requests remaining in the current rate limit window.
X-RateLimit-Reset
The time at which the current rate limit window resets in UTC epoch seconds.

If you need the time in a different format, any modern programming language can get the job done. For example, if you open up the console on your web browser, you can easily get the reset time as a JavaScript Date object.

new Date(1372700873 * 1000)
// => Mon Jul 01 2013 13:47:53 GMT-0400 (EDT)

Once you go over the rate limit you will receive an error response:

$ curl -i https://api.skroutz.gr/categories/1440 \
  -H 'Accept: application/vnd.skroutz+json; version=3.1' \
  -H 'Authorization: Bearer your_access_token_here'

HTTP/1.1 403 Forbidden
Date: Tue, 20 Aug 2013 14:50:41 GMT
Status: 403 Forbidden
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1377013266

{
  "message": "API rate limit exceeded. See http://developer.skroutz.gr/api/v3/#rate-limiting for details."
}

Daily limit

Besides the above limit, there is also a daily limit which at the time of this writting it is set to 1000 calls.
If this limit is exceeded, all oauth2 tokens associated with that client will be expired and the creation of new ones will be disabled until the beginning of the following day.

Conditional Requests

Most responses return ETag headers. You can use the value of the ETag header to make subsequent requests to those resources using the If-None-Match header.If the resource has not changed, the server will return a 304 Not Modified.

Note

Making a conditional request and receiving a 304 HTTP response still counts against your Rate Limit. It only saves on bandwidth.

Case: Request without If-None-Match header
$ curl -i https://api.skroutz.gr/categories/1440 \
  -H 'Accept: application/vnd.skroutz+json; version=3.1' \
  -H 'Authorization: Bearer your_access_token_here'

HTTP/1.1 200 OK
Cache-Control: private, max-age=60
ETag: "644b5b0155e6404a9cc4bd9d8b1ae730"
Status: 200 OK
Vary: Accept, Authorization, Cookie
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1372700873
Case: Request with If-None-Match header
$ curl -i https://api.skroutz.gr/categories/1440 \
  -H 'If-None-Match: "644b5b0155e6404a9cc4bd9d8b1ae730"' \
  -H 'Accept: application/vnd.skroutz+json; version=3.1' \
  -H 'Authorization: Bearer your_access_token_here'

HTTP/1.1 304 Not Modified
Cache-Control: private, max-age=60
ETag: "644b5b0155e6404a9cc4bd9d8b1ae730"
Status: 304 Not Modified
Vary: Accept, Authorization, Cookie
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 98
X-RateLimit-Reset: 1372700873

HTTP Redirects

API v3 uses HTTP redirection where appropriate. Clients should assume that any request may result in a redirection. Receiving an HTTP redirection is not an error and clients should follow that redirect. Redirect responses will have a Location header field which contains the URI of the resource to which the client should repeat the request.

301
Permanent redirection. The URI you used to make the request has been superseded by the one specified in the Location header field. This and all future requests to this resource should be directed to the new URI.
302, 307
Temporary redirection. The request should be repeated verbatim to the URI specified in the Location header field but clients should continue to use the original URI for future requests.

Other redirection status codes may be used in accordance with the HTTP 1.1 spec.

Versioning

The version argument in the accept header can include a minor version.
Below is how an example version (3.1.2) is broken down in our version scheme:

Major Minor Patch
3 1 2

Major versions are reserved for big architectural changes, minor versions are bumped
when incompatible changes are introduced and patch versions are added for backwards-compatible fixes.

Note

We do not follow semantic versioning.

Patch versions are implictly included and as such they should not be passed in the API (they will be silently ignored).
This means that by passing 3.1 in the API, we always get the latest bug fixes and improvements found in the 3.1.X series.

Example call using minor versions:

$ curl -i https://api.skroutz.gr/categories/1440 \
  -H 'Accept: application/vnd.skroutz+json; version=3.1' \
  -H 'Authorization: Bearer your_access_token_here'

In order to ensure backwards compatibility, we enforce the following invariants:

  • When version is unspecified, return the latest API version
  • When minor version is unspecified, return the oldest API version
  • When minor version is specified
    • Return the matched API version
    • If no match is found, return the previous API version

Each row from the table tell us the version requested and the checkmark on the columns tell us the version returned.

API v3.0.X v3.1.X v3.3.X
-    
version=3    
version=3.0    
version=3.1    
version=3.2    
version=3.3    
version=3.4    

Error Handling

The way to check for errors is to look at the HTTP status code. If the code is in 4xx or 5xx range
you can look at the body to find more info.

Below is an example error. The format is kept the same across our API.

{
  "errors": [
      {
          "code": "RecordNotFound",
          "messages": [
              "Couldn't find Sku with 'id'=452056"
          ]
      }
  ]
}
Status Code: 400

Bad request. This error indicates that a required parameter is missing or incorrect.

Status Code: 401

Unauthorized. Either you didn't send send OAuth2 credentials, or the ones you sent were invalid.

Status Code: 404

Not Found. Resource does not exist.

Status Code: 422

Unprocessable Entity. This error indicates that the creation / update of a resource failed validation.

Status Code: 500

Internal Server Error. Something is broken and we are notified.

Status Code: 501

Not Implemented. The requested action is not implemented.

Sparse fieldsets

Sparse fieldsets are a way for clients to request specific json fields from the server response.
The response is reduced, saving bandwidth and CPU time on both ends. Everybody wins, so use them when you get the chance!
We follow the JSON API Sparse Fieldsets format, using root as a special value to denote the main resource (top object) returned by the server.

Here is an example response from a product with an embedded shop:

GET https://api.skroutz.gr/products/25809770?embed=shop

View Response
Show Headers
Status: 200
{
  "product": {
    "id": 25809770,
    "name": "ALCATEL One Touch 1016G Grey EU",
    "sku_id": 10001441,
    "shop_id": 1153,
    "category_id": 40,
    "availability": "Άμεση παραλαβή / Παράδοση 1 έως 3 ημέρες",
    "click_url": "https://www.skroutz.gr/products/show/25809770?client_id=SbhE4wYENGn8ulFiBaXhDw%3D%3D&from=api",
    "shop_uid": "4909",
    "expenses": null,
    "web_uri": "https://www.skroutz.gr/products/show/25809770",
    "sizes": [

    ],
    "price": 16.12,
    "immediate_pickup": true,
    "shop": {
      "id": 1153,
      "name": "Mobilephones",
      "link": "http://www.mobile-phones.gr",
      "phone": "2321062262",
      "image_url": "https://c.scdn.gr/ds/shops/logos/1153/mid_20151119143428_88de70de.png",
      "thumbshot_url": "https://b.scdn.gr/ds/shops/screenshots/1153/09762fb7-1bb7-4831-8606-c9922fb3fc74.png",
      "reviews_count": 26,
      "latest_reviews_count": 4,
      "review_score": 5.0,
      "payment_methods": {
        "credit_card": false,
        "paypal": false,
        "bank": false,
        "spot_cash": true,
        "installments": ""
      },
      "shipping": {
        "free": false,
        "free_from": null,
        "free_from_info": null,
        "min_price": "5"
      },
      "web_uri": "https://www.skroutz.gr/m/1153/Mobilephones",
      "extra_info": {
        "time_on_platform": "3+ χρόνια",
        "orders_per_week": "50+"
      },
      "top_positive_reasons": [

      ]
    }
  }
}

Let's say we only wanted id & name from the product. We can use ?fields[root]=id,name to get just those two fields (along with the association).

GET https://api.skroutz.gr/products/25809770?embed=shop&fields[root]=id,name

View Response
Show Headers
Status: 200
{
  "product": {
    "id": 25809770,
    "name": "ALCATEL One Touch 1016G Grey EU",
    "shop": {
      "id": 1153,
      "name": "Mobilephones",
      "link": "http://www.mobile-phones.gr",
      "phone": "2321062262",
      "image_url": "https://c.scdn.gr/ds/shops/logos/1153/mid_20151119143428_88de70de.png",
      "thumbshot_url": "https://b.scdn.gr/ds/shops/screenshots/1153/09762fb7-1bb7-4831-8606-c9922fb3fc74.png",
      "reviews_count": 26,
      "latest_reviews_count": 4,
      "review_score": 5.0,
      "payment_methods": {
        "credit_card": false,
        "paypal": false,
        "bank": false,
        "spot_cash": true,
        "installments": ""
      },
      "shipping": {
        "free": false,
        "free_from": null,
        "free_from_info": null,
        "min_price": "5",
        "shipping_cost_enabled": false
      },
      "web_uri": "https://www.skroutz.gr/m/1153/Mobilephones",
      "extra_info": {
        "time_on_platform": "3+ χρόνια",
        "orders_per_week": "50+"
      },
      "top_positive_reasons": [

      ]
    }
  }
}

If we want to filter fields from the association, we can use the association name we used in the embed/include parameter (which is shop in this example).
So in order to fetch the review_score only from the shop we can use the following parameters fields[root]=id,name&fields[shop]=review_score.

GET https://api.skroutz.gr/products/25809770?embed=shop&fields[root]=id,name&fields[shop]=review_score

View Response
Show Headers
Status: 200
{
  "product": {
    "id": 25809770,
    "name": "ALCATEL One Touch 1016G Grey EU",
    "shop": {
      "review_score": 5.0
    }
  }
}

Up until now, we only specified the fields we wanted, but we can go the opposite way as well and exclude fields instead.
Here's how we could fetch just the id & name from the shop embedded resource, while excluding sizes from products: fields_except[root]=sizes&fields[shop]=id,name

GET https://api.skroutz.gr/products/25809770?embed=shop&fields_except[root]=sizes&fields[shop]=id,name

View Response
Show Headers
Status: 200
{
  "product": {
    "id": 25809770,
    "name": "ALCATEL One Touch 1016G Grey EU",
    "sku_id": 10001441,
    "shop_id": 1153,
    "category_id": 40,
    "availability": "Άμεση παραλαβή / Παράδοση 1 έως 3 ημέρες",
    "click_url": "https://www.skroutz.gr/products/show/25809770?client_id=SbhE4wYENGn8ulFiBaXhDw%3D%3D&from=api",
    "shop_uid": "4909",
    "expenses": null,
    "web_uri": "https://www.skroutz.gr/products/show/25809770",
    "price": 16.12,
    "immediate_pickup": true,
    "shop": {
      "id": 1153,
      "name": "Mobilephones"
    }
  }
}
Note

Combining fields & fields_except in the same resource (root or association) will exclude fields after the inclusion has been applied.