Booko's API v1

v1 is still in service. New integrations should start with the v3 API.

Last updated · what changed

Access to the Booko API requires authentication. The API Endpoint currently in production is:

https://api.booko.info/api/v1/

Authentication

There are two methods to authenticate. Unless there's a specific reason, you should use the JWT Authentication Header method.

Bearer Authenticaion Header

Generate a Javascript Web Token, encoding the user_id with an iat (Issued At) claim, an exp( Expiry ) claim 5 minutes from, using the API key as the key, using encryption algorithm HS256

Note: exp is currently required. Please include iat as the API will switch to requiring iat, rather than exp.

Add an Authentiation header with your request,

Authorization: Bearer <token>

Ruby Example

def token(user_id, key)
  in_5_minutes = Time.now + 60 * 5
  exp = (in_5_minutes).to_i
  JWT.encode({user_id: user_id, exp: exp}, key: key, 'HS256')
end

URL Signature

This method is deprecated.

  • api_user

    Booko User ID with permission to access resource

  • ts

    Unix Time stamp

  • signature

    SHA1 HMAC of the request path.

The Time stamp is used to ensure API calls aren't replayed. Use the current time for the time stamp.

Example

      api_user = 44
      api_key  = 'hSe7Km6D'
      gtin     = '9780748109999'

      path     = "/api/v1/products/#{gtin}?api_user=#{api_user}&ts=#{Time.now.to_i}"
      => "/api/v1/products/9780748109999?api_user=44&ts=1374894665"

      digest   = OpenSSL::Digest.new('sha1')
      res      = OpenSSL::HMAC.digest(digest, api_key, path)
      sig      = [res].pack('m').chomp

      url      = "https://api.booko.info#{path}&signature=#{sig}"
      => "https://api.booko.info/api/v1/products/9780748109999?api_user=44&ts=1374894665&signature=9O6VKp0rau4ODJYKPubYctHaQ6A="
      

Using the above path and api_key variables, you should be able to generate the example signature.

Caching

The Booko API should return one of, or both, the headers "Last Modified and "ETag" with responses. Using these values in your requests ( ie, headers 'If-None-Match: ""' and/or 'If-Modified-Since: some date' ) means you get 304 - Not Modified when appropriate, cutting down on traffic and speeding response times.

Product Search

https://api.booko.info/api/v1/products/search?q=Cryptonomicon

Optionally restrict results to one product type with query_type (ptype and product_type are accepted as aliases). Pass either the name or the id:

https://api.booko.info/api/v1/products/search?q=Amadeus&query_type=video
  • 1 book — own index
  • 2 video — own index
  • 3 ebook — filtered from the book index
  • 4 audiobook — filtered from the book index
  • 5 toy — live shop search only
  • 6 lego — own index
  • 7 pop — own index
  • 8 graphic_novel — filtered from the book index
  • 9 box_set — filtered from the book index
  • 10 music — live shop search only
  • 11 ereader — live shop search only
  • 12 table_top_game — live shop search only
  • 13 food_stuff — live shop search only
  • 99 other — live shop search only

Books, videos, LEGO and POP! vinyls each have a search index of their own, and a search restricted to one of those types queries that index directly.

Ebooks, audiobooks, graphic novels and box sets have no index of their own. They are answered from the book index, which is keyed on title, author and series rather than on product type — so the query runs untyped and the results are filtered to your requested type afterwards. That works well when you are searching for a specific title, because the edition you want hangs off a work the index already knows. It works poorly as a way to browse a type: a broad query returns the most relevant works regardless of type, and filtering those down to, say, box sets alone can legitimately leave you with nothing. Box sets are the thinnest of the four — they are not attached to a work, so they are only indexed when the product itself carries a title, an author and a publication date.

The remaining types are sourced from the shops we search live, so they return fewer results and take longer.

Product Data

https://api.booko.info/api/v1/products/9780748109999

Collection Data

https://api.booko.info/api/v1/series/1
https://api.booko.info/api/v1/works/4
https://api.booko.info/api/v1/parts/1

To queue prices for works, include a region id.

https://api.booko.info/api/v1/works/4?region=1

Product Prices

https://api.booko.info/api/v1/products/9780748109999/prices?region=1

Region is an optional parameter. It will default to region 1

Regions

Booko will respond to regional queries
  • Region 1 Australia
  • Region 2 United Kingdom
  • Region 3 United States
  • Region 4 New Zealand
  • Region 5 Canada
  • Region 6 Finland
  • Region 7 Spain
  • Region 8 Ireland
  • Region 9 France
  • Region 10 Italy
  • Region 11 Norway
  • Region 12 Sweden
  • Region 13 Japan
  • Region 14 Germany
  • Region 15 Singapore
  • Region 16 China
  • Region 17 Taiwan
  • Region 18 Philippines
  • Region 19 Malaysia
  • Region 20 Argentina
  • Region 21 Chile
  • Region 22 Israel
  • Region 23 Hong Kong

Price States

Price / Shop links should be in the form

http://booko.com.au/prices/#{price.UID}?api_user=api_user.id

The response keys at the top level correspond to price state:

Price states are as below

  • 0 Loading: Price grabber is actively looking for the price
  • 1 Found: Price was successfully found
  • 2 Not Found: Shop does not sell this book
  • 3 No Response: Shop error / Timeout
  • 4 Error: Booko Error
  • 5 Not Available: Product is not available
  • 6 Out of Stock: Product is for sale, but not in stock
  • 7 Out of Region: Shop doesn't support client region

Within each state, an array of the prices is returned. Empty price states are not returned. IE, if there are no "Out Of Stock" books, there'll be no result set "6".

There is a price result per shop. If a shop sells both new and used products, there will be two prices.

Offer Condition

Offers for books may be New or Used
  • 0 New Price
  • 1 Used Price

Product Images

Within the Product response, image_url holds the URL for cover art and image_url_jxl holds the same cover in JPEG XL. Prefer the JXL if you can decode it — it is roughly 30% smaller for the same picture — and fall back to image_url.

"image_url":     "https://cdn.booko.info/variants-production/73f95226ad27ec3d/600.jpeg"
"image_url_jxl": "https://cdn.booko.info/variants-production/73f95226ad27ec3d/1024.jxl"

Both URLs are public, unsigned and safe to cache. Prefer the URL as we send it. If you need a different size, every rendition of a cover sits under the same /variants-production/<hash>/ prefix, so you can swap the filename — but check the response and fall back to the URL we sent, because variants are generated when we ingest a cover and not every cover has the full set.

These are the renditions, each in .jpeg and .jxl:

  • 600, 800, 1024 — aspect ratio kept. The number is the maximum width, not the longest edge: a 2:3 cover at 600.jpeg is 600×900 and at 800.jpeg is 800×1200. We never upscale, so a cover whose source is 344px wide comes back 344×500 at all three — 600.jpeg and 1024.jpeg are then the same image. Plenty of our covers are smaller than 800px wide, so treat these as ceilings.
  • 120x120, 160x160, 240x240, 500x750, 666x1000 — cropped to fill exactly those pixel dimensions, so the square sizes trim a portrait cover. 500x750 and 666x1000 are 2:3, the shape most book covers already are.

The size is the whole filename: there is no 120.jpeg — the small square is 120x120.jpeg. For a small cover-shaped thumbnail use 500x750.jxl; for a small square use 120x120.jxl.

Cover art is not regional: one CDN serves every region. If you are still holding per-region cover hosts such as covers.booko.com.au, they are retired and can be dropped.

Shops

Collection

https://api.booko.info/api/v1/shops

Single

https://api.booko.info/api/v1/shops/1

Popular Products

https://api.booko.info/api/v1/widgets/popular

List View

User lists can be retreived with

GET https://api.booko.info/api/v1/lists

Public lists can be created with the end point

POST https://api.booko.info/api/v1/lists
ParameterDescription
gtinsRequired. Comma separated lists of GTINS. No spaces or hypens allowed.
regionOptional. For this list, prices will be calculated in the specificed region. Defaults to 1.
nameOptional. Name of the list to create. Defaults to "Anonymous Public List".
emailOptional. Email address of the account to attach the list to.
passwordOptional. Password associated with the account.

User Login

Actions requiring authenticated users, such as viewing and modifiying lists, require the auth_token. The request requires user's email and password. These values should not be stored by the App once the auth_token has been retreived.

GET https://api.booko.info/api/v1/users/auth_token
ParameterDescription
UserRequired. Email address of the account to retrieve auth_token for.
PasswordRequired.

Response will be 401, Unauthenticated when credentials are incorrect.

Changelog

Notable changes to the v1 API. Changes affecting v3 are listed on the v3 page.

  • A series is no longer dropped from a typed search. Asking for one product type discarded any series where a single member work lacked an edition of that type — so a ten-book series with nine ebooks was thrown away over the tenth — and a series that survived that was then dropped anyway, because the filter looked only at editions attached directly to the series rather than to its works. In practice a query_type other than book returned no series at all. Both are fixed; searches without a query_type were never affected.
  • Which types have a search index is now documented honestly. This page said books, ebooks, audiobooks, graphic novels, box sets and videos "each have a search index behind them". Only books, videos, LEGO and POP! vinyls do. The other three are answered from the book index and filtered to your requested type afterwards, which finds a known title well but browses a type poorly. The Product Search section above now says so, and lists which is which. Nothing changed at our end — the documentation was overstating it.

  • Search honours the product type again. /products/search read only query_type, so a request filtering on any other spelling was silently unfiltered and came back with books whatever you asked for. It now accepts query_type, ptype and product_type alike, as either the type name (video) or its id (2).
  • DVDs are searchable. query_type=2 now has a search index behind it. Previously the only discs search could reach were ones attached to a work; standalone editions were in no index at all.
  • stale_details? can now go false. The field answers "is it worth asking for this product again", rather than reporting staleness no client could ever clear. If you have been seeing it true on every product on every request, that is why: from August 2022 to August 2026 nothing wrote the timestamp behind it, so it was a constant. No change is needed at your end — the field keeps its name, and now means what you already assumed it meant.
  • When stale_details? goes false. Either we have something worth showing you — a title and cover art — or we have looked and there is nothing more coming. A product whose publisher never sent us data will settle as false rather than asking to be fetched forever. Fetching a product also queues the detail lookup now, so polling gets somewhere.
  • New field image_url_jxl on product responses — the same cover in JPEG XL at the largest rendition we hold. Prefer it if you can decode it, and fall back to image_url.
  • The cover art documented here was wrong. This page gave the host as c.booko.info and the path as /covers/<hash>/v/800.jpeg; neither has existed for some time. Covers are served from cdn.booko.info, and the Product Images section above now lists the renditions that actually exist. Nothing changed at our end — the documentation was stale.
  • Regions 18 to 23 were missing from this page. Philippines, Malaysia, Argentina, Chile, Israel and Hong Kong have been valid region values for a while and were simply never listed.