Open Cinema Project

The "GTFS for Cinemas"

The open standard for indie cinema showtimes

Developers

Build with the Open Cinema Platform API. Free, open, and no commercial restrictions. Sign up below for a key and you're querying live indie & repertory cinema data in under a minute.

Default limits: 60 req/min and 10,000 req/day. Need more? Email hi@opencinemaproject.com.

2. Quickstart

curl

curl -H "Authorization: Bearer YOUR_KEY" \
  "https://opencinemaproject.com/api/v1/public/screenings?lat=40.7128&lon=-74.006&radius_km=10"

JavaScript (fetch)

const res = await fetch(
  'https://opencinemaproject.com/api/v1/public/screenings?radius_km=10&lat=40.7128&lon=-74.006',
  { headers: { Authorization: 'Bearer YOUR_KEY' } }
);
const { screenings, pagination } = await res.json();

Python (requests)

import requests

resp = requests.get(
    "https://opencinemaproject.com/api/v1/public/screenings",
    params={"lat": 40.7128, "lon": -74.006, "radius_km": 10},
    headers={"Authorization": "Bearer YOUR_KEY"},
    timeout=10,
)
resp.raise_for_status()
data = resp.json()
for s in data["screenings"]:
    print(s["start_time"], s["film_title"], "@", s["theater_name"])

# Paginate
while data["pagination"]["has_more"]:
    resp = requests.get(
        "https://opencinemaproject.com/api/v1/public/screenings",
        params={"lat": 40.7128, "lon": -74.006, "radius_km": 10,
                "cursor": data["pagination"]["next_cursor"]},
        headers={"Authorization": "Bearer YOUR_KEY"},
    )
    data = resp.json()

Pagination

Every list endpoint returns a pagination.next_cursor. Pass it as ?cursor=… on the next request to get the next page. Default page size is 50, max 200.

Errors

All errors share the same envelope so they're easy to handle:

{
  "error": {
    "code": "invalid_api_key",
    "message": "API key is invalid or revoked. Get a free key at /developers.",
    "request_id": "req_abc123def456"
  }
}

Common code values: missing_api_key, invalid_api_key, rate_limited, invalid_coordinates, film_not_found, method_not_allowed, internal_error.

3. Endpoint reference

Full machine-readable spec: openapi.yaml. Interactive explorer below.

MethodPathDescription
GET/api/v1/public/theatersList theaters by geo / id list / alphabetical, with cursor pagination.
GET/api/v1/public/screeningsList upcoming screenings filtered by geo, date, theater, film, format, accessibility.
GET/api/v1/public/films/{filmId}Film details enriched with TMDB metadata (poster, synopsis, trailer, cast).
GET/api/v1/public/statusScraper fleet health snapshot.
POST/api/v1/public/report-linkSubmit a broken purchase-link report.
POST/api/v1/public/keysSelf-service API key issuance (this page calls it).
GET/api/v1/public/keysAuthenticated: view your own key + 14-day usage stats.
DELETE/api/v1/public/keysAuthenticated: immediately revoke ALL active keys for the signed-in email (including any key still in its 24h rotation grace window).
POST/api/v1/public/keys/rotateAuthenticated: issue a fresh key; old key keeps working for 24h.
POST/api/v1/public/keys/loginRequest a magic-link sign-in email for the dashboard.
GET/api/v1/public/calendar.icsLocation iCal feed. No key required (calendar apps cannot send Authorization).
GET/api/v1/public/theaters/{id}/calendar.icsPer-theater iCal feed. No key required.
GET/api/v1/public/films/{filmId}/calendar.icsPer-film iCal feed. No key required.
GET/api/v1/public/changesIncremental sync: rows changed since ?since=<iso8601>, paginated.
GET/api/v1/public/webhooksList your webhook subscriptions (scoped to your API key).
POST/api/v1/public/webhooksSubscribe a URL to push events; signing secret returned once.
DELETE/api/v1/public/webhooks?id={id}Delete a webhook subscription.
POST/api/mcpModel Context Protocol endpoint for AI assistants (Claude, ChatGPT, …). Anonymous, IP rate-limited.

4. Versioning & deprecation policy

  • This is the v1 API, indicated by the /api/v1/ URL prefix.
  • Additive changes (new optional fields, new endpoints, new query params, new error codes) ship anytime without warning. Build defensively: ignore unknown fields.
  • Breaking changes (removing fields, renaming, changing types, tightening validation) only ship in a new major version (/api/v2/).
  • v1 deprecation: when v2 ships, v1 stays available for at least 6 months. We'll email every active key holder when the deprecation clock starts and again 30 days before shutdown. Sunset date will also appear in a Sunset: response header per RFC 8594.
  • Status & changelog: follow /status for incidents and our GitHub for changelog.

5. Interactive explorer

Browse every endpoint, parameter, response shape, and example below. Loaded from /openapi.yaml.

Connect to AI assistants (MCP)

Open Cinema speaks the Model Context Protocol. Drop the URL below into Claude, ChatGPT, Cursor, or any MCP-aware client and ask it what's playing near you tonight — no key required, rate limited per IP.

https://opencinemaproject.com/api/mcp

Claude

Open Claude → Settings → Connectors ↗ and add a custom connector with the URL above. For Claude Desktop, paste this into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%/Claude/claude_desktop_config.json (Windows), then restart Claude:

{
  "mcpServers": {
    "open-cinema": {
      "url": "https://opencinemaproject.com/api/mcp"
    }
  }
}

ChatGPT

Create a Custom GPT ↗ or open ChatGPT → Settings → Connectors ↗ and add an HTTP MCP server with URL https://opencinemaproject.com/api/mcp. Auth: None.

Cursor, Continue, Gemini, Copilot

Any MCP-aware client takes the same shape: add a server with URL https://opencinemaproject.com/api/mcp and no auth headers.

Available tools

  • search_screenings — upcoming showtimes by location, date, theater, or film.
  • search_theaters — theaters near a point (or by id list).
  • lookup_film — film details enriched with TMDB metadata when available.
  • get_status — scraper-fleet freshness snapshot.
  • report_broken_link — flag a dead ticket URL; queues a re-scrape and notifies webhook subscribers.

Browsable resources

  • opencinema://theaters — full list (capped 200).
  • opencinema://theaters/{theater_id} — one theater.
  • opencinema://films/{film_id} — one film, TMDB-enriched.

Optional: lift rate limits with a key

Anonymous MCP gets 30 req/min and 200 req/day per IP. Issue a free key in the Get an API key tab and add this header to your MCP connector config to get 60 req/min and 10000 req/day:
Authorization: Bearer oc_live_…

Full quickstart and example transcripts: docs/MCP.md. Discovery manifest: /.well-known/mcp.json.

iCal feeds (.ics) don't need a key

Apple Calendar, Google Calendar, and Outlook can't attach an Authorization header when polling a subscription. Calendar feeds are key-free by design and rate-limited per IP instead. See the quickstart on each theater or film page for the webcal:// link.

Fair use

  • This data exists thanks to a small nonprofit team and many indie cinemas. Please credit "Open Cinema Project" when you display it.
  • Cache where you can — most fields update at most a few times a day.
  • If you're building something cool, tell us! We love hearing about it: hi@opencinemaproject.com.
  • If you're abusing the API or scraping aggressively to resell, we will revoke your key and ask politely. Then less politely.