Quick start
Ask for the published times of a film in a developer. Everything lives under https://35mm.org/api/public/v1; answers are JSON with snake_case keys and ISO 8601 dates in UTC.
curl "https://35mm.org/api/public/v1/development-times?film=ilford-hp5-plus&developer=ilford-id-11"
Each time comes with its source: what kind it is, its title and its address as stored. Where none is recorded the fields are null — nothing is filled in. Only published data is served: drafts, suggestions and anything about people never are.
Keys
Anonymous requests need nothing. For a higher limit, ask for an API key and send it as a bearer token:
curl -H "Authorization: Bearer 35mm_…" "https://35mm.org/api/public/v1/films"
A key that is wrong or has been revoked is answered 401 — it is never quietly treated as anonymous. Keys are for servers and tools: do not put one in a web page, where anyone can read it.
Keys are issued by hand, on request.
Rate limits
- Without a key: 60 requests a minute for each address.
- With a key: its own allowance, 600 a minute unless agreed otherwise.
- Past the limit the answer is 429 with a Retry-After header (seconds to wait). Every answer carries X-RateLimit-Limit and X-RateLimit-Remaining.
Addresses are counted in a cache and never stored. A key’s use is counted per day — a number, nothing more.
Attribution
Every response has an attribution object. Please link back to 35mm.org wherever you show our data — the url of a film, developer or time points at its page — and show each time’s source with it: a development time without its source is only a number.
The data has no stated licence yet. Link back, keep each time’s source with it, and ask if you are unsure.
Endpoints
All of them are GET. The examples below are real answers for a small test catalogue, not production data.
GET /films
Films, A to Z, each with its maker, formats and the number of published times.
curl "https://35mm.org/api/public/v1/films?manufacturer=ilford"
| Parameter | Meaning |
|---|---|
| q | Search the name or the maker, ignoring punctuation: hp5, ilford hp5. |
| manufacturer | A manufacturer’s slug, such as ilford. |
| format | A format’s slug, such as 135 or 120. |
| process | The process: bw, c41, e6, ecn2 … |
| type | The kind of film: bw_negative, color_negative, color_reversal … |
| still_made | 1 for films still in production, 0 for the rest. |
| has_times | 1 for films with a published time, 0 for those without. |
| page, per_page | See pagination below. |
Example response
{
"data": [
{
"id": 101,
"slug": "ilford-hp5-plus",
"name": "HP5 Plus",
"full_name": "Ilford HP5 Plus",
"manufacturer": {
"slug": "ilford",
"name": "Ilford"
},
"iso": 400,
"type": "bw_negative",
"process": "bw",
"is_chromogenic_bw": false,
"status": "in_production",
"still_made": true,
"formats": [
{
"slug": "135",
"name": "35mm (135)"
}
],
"respool_of": null,
"published_times_count": 2,
"url": "https://35mm.org/film/ilford-hp5-plus",
"api_url": "https://35mm.org/api/public/v1/films/ilford-hp5-plus",
"updated_at": "2026-10-01T12:00:00Z"
}
],
"links": {
"first": "https://35mm.org/api/public/v1/films?manufacturer=ilford&page=1",
"last": "https://35mm.org/api/public/v1/films?manufacturer=ilford&page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 50,
"from": 1,
"to": 1,
"total": 1
},
"attribution": {
"text": "Data from 35mm.org — each time with its source. Please link back to 35mm.org.",
"url": "https://35mm.org"
}
}
GET /films/{slug}
One film with its specification and every published development time.
curl "https://35mm.org/api/public/v1/films/ilford-hp5-plus"
Example response
{
"data": {
"id": 101,
"slug": "ilford-hp5-plus",
"name": "HP5 Plus",
"full_name": "Ilford HP5 Plus",
"manufacturer": {
"slug": "ilford",
"name": "Ilford"
},
"iso": 400,
"type": "bw_negative",
"process": "bw",
"is_chromogenic_bw": false,
"status": "in_production",
"still_made": true,
"formats": [
{
"slug": "135",
"name": "35mm (135)"
}
],
"respool_of": null,
"published_times_count": 2,
"url": "https://35mm.org/film/ilford-hp5-plus",
"api_url": "https://35mm.org/api/public/v1/films/ilford-hp5-plus",
"updated_at": "2026-10-01T12:00:00Z",
"base": null,
"emulsion_type": null,
"spectral_sensitivity": null,
"has_remjet": false,
"first_released_year": 1989,
"discontinued_year": null,
"grain_rms": 14.0,
"resolving_power_lpmm": null,
"dmax": null,
"latitude_stops_under": null,
"latitude_stops_over": null,
"datasheet_url": null,
"image_url": null,
"development_times": [
{
"id": 501,
"film": {
"slug": "ilford-hp5-plus",
"name": "HP5 Plus",
"url": "https://35mm.org/film/ilford-hp5-plus"
},
"developer": {
"slug": "ilford-id-11",
"name": "ID-11",
"url": "https://35mm.org/developer/ilford-id-11"
},
"dilution": {
"label": "Stock",
"is_stock": true
},
"format": "any",
"ei": 400,
"temperature_c": 20.0,
"time_seconds": 450,
"time": "7:30",
"agitation": "10 s at the start, then 10 s every minute",
"process_type": "tank",
"confidence": "verified",
"notes": "Tank, 10 s initial agitation.",
"source": {
"type": "manufacturer_datasheet",
"title": "ILFORD HP5 PLUS technical information, 2023",
"url": "https://example.com/ilford-hp5-plus-datasheet.pdf"
},
"inherited_from": null,
"url": "https://35mm.org/film/ilford-hp5-plus/developed-in/ilford-id-11",
"updated_at": "2026-10-01T12:00:00Z"
},
{
"id": 502,
"film": {
"slug": "ilford-hp5-plus",
"name": "HP5 Plus",
"url": "https://35mm.org/film/ilford-hp5-plus"
},
"developer": {
"slug": "ilford-id-11",
"name": "ID-11",
"url": "https://35mm.org/developer/ilford-id-11"
},
"dilution": {
"label": "1+1",
"is_stock": false
},
"format": "any",
"ei": 800,
"temperature_c": 20.0,
"time_seconds": 600,
"time": "10:00",
"agitation": null,
"process_type": "tank",
"confidence": "community",
"notes": null,
"source": {
"type": "community",
"title": null,
"url": null
},
"inherited_from": null,
"url": "https://35mm.org/film/ilford-hp5-plus/developed-in/ilford-id-11",
"updated_at": "2026-10-01T12:00:00Z"
}
]
},
"attribution": {
"text": "Data from 35mm.org — each time with its source. Please link back to 35mm.org.",
"url": "https://35mm.org"
}
}
GET /developers
Developers and other chemistry.
curl "https://35mm.org/api/public/v1/developers?manufacturer=ilford"
| Parameter | Meaning |
|---|---|
| q | Search the name or the maker. |
| manufacturer | A manufacturer’s slug. |
| type | The kind of chemistry: bw_developer, c41_kit, fixer … |
| still_made | 1 for those still in production, 0 for the rest. |
| page, per_page | See pagination below. |
Example response
{
"data": [
{
"id": 201,
"slug": "ilford-id-11",
"name": "ID-11",
"full_name": "Ilford ID-11",
"manufacturer": {
"slug": "ilford",
"name": "Ilford"
},
"type": "bw_developer",
"form": "powder",
"status": "in_production",
"still_made": true,
"reuse": "depends",
"is_one_shot": false,
"is_replenishable": null,
"reuse_source": {
"title": "ILFORD PERCEPTOL, ID-11 AND MICROPHEN FILM DEVELOPERS",
"url": "https://www.ilfordphoto.com/wp/wp-content/uploads/2024/09/ILFORD-POWDER-CHEM-190824.pdf"
},
"published_times_count": 2,
"url": "https://35mm.org/developer/ilford-id-11",
"api_url": "https://35mm.org/api/public/v1/developers/ilford-id-11",
"updated_at": "2026-10-01T12:00:00Z"
}
],
"links": {
"first": "https://35mm.org/api/public/v1/developers?manufacturer=ilford&page=1",
"last": "https://35mm.org/api/public/v1/developers?manufacturer=ilford&page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 50,
"from": 1,
"to": 1,
"total": 1
},
"attribution": {
"text": "Data from 35mm.org — each time with its source. Please link back to 35mm.org.",
"url": "https://35mm.org"
}
}
GET /developers/{slug}
One developer with its dilutions and the films it has published times for.
curl "https://35mm.org/api/public/v1/developers/ilford-id-11"
Example response
{
"data": {
"id": 201,
"slug": "ilford-id-11",
"name": "ID-11",
"full_name": "Ilford ID-11",
"manufacturer": {
"slug": "ilford",
"name": "Ilford"
},
"type": "bw_developer",
"form": "powder",
"status": "in_production",
"still_made": true,
"reuse": "depends",
"is_one_shot": false,
"is_replenishable": null,
"reuse_source": {
"title": "ILFORD PERCEPTOL, ID-11 AND MICROPHEN FILM DEVELOPERS",
"url": "https://www.ilfordphoto.com/wp/wp-content/uploads/2024/09/ILFORD-POWDER-CHEM-190824.pdf"
},
"published_times_count": 2,
"url": "https://35mm.org/developer/ilford-id-11",
"api_url": "https://35mm.org/api/public/v1/developers/ilford-id-11",
"updated_at": "2026-10-01T12:00:00Z",
"shelf_life_unopened_months": 24,
"shelf_life_opened_months": 3,
"capacity_rolls_per_litre": 10.0,
"datasheet_url": null,
"dilutions": [
{
"label": "Stock",
"is_stock": true,
"parts_developer": 1.0,
"parts_water": 0.0
},
{
"label": "1+1",
"is_stock": false,
"parts_developer": 1.0,
"parts_water": 1.0
}
],
"films": [
{
"slug": "ilford-hp5-plus",
"name": "HP5 Plus",
"published_times_count": 2,
"times_url": "https://35mm.org/api/public/v1/development-times?film=ilford-hp5-plus&developer=ilford-id-11"
}
]
},
"attribution": {
"text": "Data from 35mm.org — each time with its source. Please link back to 35mm.org.",
"url": "https://35mm.org"
}
}
GET /development-times
Search published times. A respool with no times of its own answers with its parent stock’s, marked inherited_from.
curl "https://35mm.org/api/public/v1/development-times?film=ilford-hp5-plus&developer=ilford-id-11&ei=400"
| Parameter | Meaning |
|---|---|
| film | A film’s slug. |
| developer | A developer’s slug. |
| dilution | A dilution’s label as published: Stock, 1+1 … |
| ei | The exposure index the film was rated at. |
| temperature | The temperature in °C. |
| format | The format the time is for: 135, 120, sheet or any. |
| page, per_page | See pagination below. |
Example response
{
"data": [
{
"id": 501,
"film": {
"slug": "ilford-hp5-plus",
"name": "HP5 Plus",
"url": "https://35mm.org/film/ilford-hp5-plus"
},
"developer": {
"slug": "ilford-id-11",
"name": "ID-11",
"url": "https://35mm.org/developer/ilford-id-11"
},
"dilution": {
"label": "Stock",
"is_stock": true
},
"format": "any",
"ei": 400,
"temperature_c": 20.0,
"time_seconds": 450,
"time": "7:30",
"agitation": "10 s at the start, then 10 s every minute",
"process_type": "tank",
"confidence": "verified",
"notes": "Tank, 10 s initial agitation.",
"source": {
"type": "manufacturer_datasheet",
"title": "ILFORD HP5 PLUS technical information, 2023",
"url": "https://example.com/ilford-hp5-plus-datasheet.pdf"
},
"inherited_from": null,
"url": "https://35mm.org/film/ilford-hp5-plus/developed-in/ilford-id-11",
"updated_at": "2026-10-01T12:00:00Z"
}
],
"links": {
"first": "https://35mm.org/api/public/v1/development-times?film=ilford-hp5-plus&developer=ilford-id-11&ei=400&page=1",
"last": "https://35mm.org/api/public/v1/development-times?film=ilford-hp5-plus&developer=ilford-id-11&ei=400&page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 50,
"from": 1,
"to": 1,
"total": 1
},
"attribution": {
"text": "Data from 35mm.org — each time with its source. Please link back to 35mm.org.",
"url": "https://35mm.org"
}
}
A development time
| Field | Meaning |
|---|---|
| time_seconds, time | The time in whole seconds, and as m:ss. |
| ei, temperature_c | The exposure index and the temperature in °C the time is for. |
| source | Always present: type (manufacturer_datasheet, own_test, third_party, community), title and url as stored — null where none is recorded. |
| confidence | verified, community, unverified or disputed: how far the time has been checked against its source. |
| inherited_from | The slug of the parent stock when a respool takes its times, otherwise null. |
Paging
Lists are paged with page and per_page (50 by default, at most 100). links has the first, last, prev and next addresses — null where there is none — and meta has current_page, last_page, per_page, from, to and total. Follow links.next until it is null.
Caching
Answers carry ETag and Last-Modified and Cache-Control: public, max-age=300. Send the ETag back in If-None-Match and an unchanged answer returns 304 with no body — it is still counted as a request. Please cache on your side too: the catalogue does not change by the minute.
Browsers on any site may read these routes (CORS: GET from any origin).
Errors
Errors share one shape, with details for a refused parameter:
{
"error": {
"code": "invalid_parameter",
"message": "One or more parameters are not valid.",
"details": { "per_page": ["The per page field must not be greater than 100."] }
}
}
| HTTP | code | Meaning |
|---|---|---|
| 401 | invalid_api_key | The key is wrong or has been revoked. |
| 404 | not_found | No film or developer with that slug. |
| 405 | method_not_allowed | The API is read-only: use GET. |
| 422 | invalid_parameter | A parameter is not a valid value. |
| 429 | rate_limited | Too many requests: wait for Retry-After seconds, or ask for a key. |
OpenAPI
The whole API is described in an OpenAPI 3.1 file: /api/public/v1/openapi.json. Import it into Postman, Insomnia or a code generator.
Embed a time card
Blogs and forums can show one development time as a small card: film, developer, dilution, speed, temperature, the time and its source, with a link back to 35mm.org. It is a plain page — no cookies, no scripts, nothing loaded from other sites — made to be framed.
<iframe src="https://35mm.org/embed/time?film=ilford-hp5-plus&developer=ilford-id-11&dilution=Stock&ei=400&temp=20" width="100%" height="214" style="border:0;max-width:440px" loading="lazy" title="HP5 Plus in ID-11 — 35mm.org"></iframe>
| Parameter | Meaning |
|---|---|
| film, developer | The film’s and the developer’s slugs. |
| dilution, ei, temp | Narrow it down to one time. Left out, the time at box speed is shown. |
| id | Or one time by its id, from the API. |
| theme | light or dark. Left out, the card follows the reader’s colour scheme. |
| lang | en, pl or uk. |
If no published time matches, the card says so and links to the film — it never shows a near match. The Embed button on any film × developer page makes the code for you, with a preview.
We count how often a card is shown, per day, per site (the host of the page it is on, nothing longer) and per combination. No cookies, no addresses.