rolllog

Docs

The rolllog API

Film stock data as JSON: the same data as the website, every value with the datasheet or source it came from. Read-only, no key, no sign-up. Free for non-commercial use; see the terms.

Basics

Base URL
https://rolllog.io/api/v1
Auth
None. Send a User-Agent that says who you are, so we can reach you if something breaks.
Rate limit
60 requests in a burst, 120 per minute per IP. Over that you get 429 with Retry-After.
Caching
Responses carry an ETag; send it back as If-None-Match and you get 304 when nothing changed. Film data changes on deploys, prices once a day.
Lists
{ data: [...], meta: { total, limit, offset } }. Page with limit (max 100) and offset.
Ids
Films and developers are kebab-case slugs (kodak-portra-400). Film aliases and product codes resolve to the same film.
Sources
Every value has a source: the datasheet (code, revision) or a named page. Nothing is estimated.
Prices
In each shop's own currency, never converted; taxIncluded says whether VAT is in. Shipping is separate.
CORS
Open, so it works from a browser.

Examples

Find films GET /api/v1/films?type=bw_negative&iso=400&limit=5

ISO 400 black-and-white negative films. Each result links to its full document.

const res = await fetch('https://rolllog.io/api/v1/films?type=bw_negative&iso=400&limit=5')
if (!res.ok) throw new Error(`rolllog: ${res.status}`)
const body = await res.json()
console.log(body)
Response (today, trimmed)
{
  "data": [
    {
      "id": "bergger-pancro-400",
      "name": "Pancro 400",
      "brand": "Bergger",
      "manufacturer": {
        "id": "bergger",
        "name": "Bergger"
      },
      "type": "bw_negative",
      "iso": 400,
      "inProduction": true,
      "formats": [
        "135",
        "120",
        "4x5",
        "5x7",
        "13x18cm",
        "8x10"
      ],
      "processes": [
        "B&W"
      ],
  …

One film GET /api/v1/films/ilford-hp5-plus

Every value for one film, each with its source. Aliases work too: 400TX, RVP50, 5219.

const res = await fetch('https://rolllog.io/api/v1/films/ilford-hp5-plus')
if (!res.ok) throw new Error(`rolllog: ${res.status}`)
const body = await res.json()
console.log(body)
Response (today, trimmed)
{
  "id": "ilford-hp5-plus",
  "manufacturer": {
    "id": "harman-technology",
    "name": "HARMAN technology",
    "country": "GB"
  },
  "brand": "Ilford",
  "name": "HP5 Plus",
  "type": "bw_negative",
  "description": "Fast, general-purpose black-and-white negative film. Rated ISO 400 and usable from EI 400 up to EI 3200 with extended development.",
  "speed": {
    "iso": 400,
    "din": 27,
    "dxCoded": true
  },
  "colorBalance": null,
  "base": {
    "material": "acetate",
    "remjet": false
  },
  "technology": [],
  "status": {
    "inProduction": true,
  …

Development times GET /api/v1/films/ilford-hp5-plus/dev-times?developer=ilford-ilfotec-hc&ei=400

HP5 Plus in Ilfotec HC at box speed: every dilution, temperature and agitation.

const res = await fetch('https://rolllog.io/api/v1/films/ilford-hp5-plus/dev-times?developer=ilford-ilfotec-hc&ei=400')
if (!res.ok) throw new Error(`rolllog: ${res.status}`)
const body = await res.json()
console.log(body)
Response (today, trimmed)
{
  "data": [
    {
      "developer": {
        "id": "ilford-ilfotec-hc",
        "name": "ILFORD ILFOTEC HC"
      },
      "format": null,
      "dilution": "1+15",
      "ei": 400,
      "tempC": 20,
      "timeSec": 210,
      "timeSecMax": null,
      "agitation": "intermittent",
      "contrastIndex": null,
      "source": {
        "kind": "datasheet",
        "label": "HARMAN technology HP5 PLUS Technical Information (2018-11)",
        "url": null,
        "verifiedAt": "2026-10-14",
        "datasheet": {
          "code": "HP5 PLUS Technical Information",
          "revision": "2018-11"
        }
  …

Shop prices GET /api/v1/films/kodak-portra-400/prices?country=NL

Today's prices for Portra 400 in Dutch shops, cheapest per roll first.

const res = await fetch('https://rolllog.io/api/v1/films/kodak-portra-400/prices?country=NL')
if (!res.ok) throw new Error(`rolllog: ${res.status}`)
const body = await res.json()
console.log(body)
Response (today, trimmed)
{
  "data": [
    {
      "id": 303,
      "shop": {
        "id": "fotofilmfabriek",
        "name": "FotoFilmFabriek",
        "country": "NL",
        "url": "https://fotofilmfabriek.nl",
        "currency": "EUR",
        "taxIncluded": true,
        "shipping": null,
        "freeShippingFrom": null,
        "affiliate": false
      },
      "film": "kodak-portra-400",
      "format": "135",
      "exposures": 36,
      "sheets": null,
      "packSize": 5,
      "title": "Kodak Professional Portra 400 Kleinbeeldfilm - 135/36",
      "gtin": "00086806031677",
      "url": "https://fotofilmfabriek.nl/product/kodak-portra-400-kleinbeelfilm/",
      "price": 26.6,
  …

Reference

All GET. :id takes a slug or an alias. Unknown ids return 404, bad parameters 400 with what's wrong.

EndpointReturns
/api/v1/filmsSearch and filter film summaries.Parameters: q, type, manufacturer, iso, isoMin, isoMax, process, tag, inProduction, basedOn, format, limit (≤100), offset
/api/v1/films/:idOne film document: speed, exposure, latitude, reciprocity, processing, formats, barcodes, handling, grain, datasheet. Every value with its source.
/api/v1/films/:id/dev-timesDevelopment times: developer × dilution × EI × temperature × agitation.Parameters: developer, dilution, ei, format
/api/v1/films/:id/curvesDigitized datasheet curves as [x, y] points, where available.Parameters: kind, channel
/api/v1/films/:id/pricesToday's shop prices, cheapest per roll first, in each shop's own currency.Parameters: country, currency, format, exposures, shop, inStock
/api/v1/films/:id/prices/historyDaily price per offer.Parameters: days (≤365, default 90) and the price filters
/api/v1/developersEvery developer, with the number of films that have times in it.
/api/v1/developers/:idOne developer and every film with times in it.
/api/v1/reciprocityEvery film with long-exposure data, with its datasheet rows and formulas.
/api/v1/based-onFilms made from another stock (rebrands, cine-derived), each with its source.
/api/v1/prices/filmsFilms with fresh prices and their lowest in-stock price.
/api/v1/prices/dealsIn-stock offers well below their own 30-day median.Parameters: country, minDrop (default 0.1), limit
/api/v1/prices/shopsShops the price watch checks, with currency, tax and shipping.
/api/v1This list, as JSON.

MCP server

For AI assistants (Claude, ChatGPT, Cursor and other MCP clients): the same data as tools, at https://rolllog.io/mcp (streamable HTTP, no key). Add it to your client's config:

{
  "mcpServers": {
    "rolllog": {
      "type": "http",
      "url": "https://rolllog.io/mcp"
    }
  }
}

Tools: search_films, get_film, get_dev_times, list_developers, get_curves, get_prices, get_price_deals.

Using the data

Personal projects, study and research: go ahead. Building something commercial on it needs a licence; ask at hello@icangetnosaasisfaction.com. Keep the sources with values you republish, and a "Data: rolllog.io" credit is appreciated. Found a wrong value? Same address.