Every MCU movie, TV show and character — in one API that knows the order.
A free REST API for the Marvel Cinematic Universe: every movie and TV show,
the characters and the actors who played them, and the chronology that orders it
all — including the X-Men and Sony continuities the MCU keeps pulling in.
No key, no signup, CORS open to any origin.
GET https://mcuapi.up.railway.app/api/v1/movies — no Authorization header
GET /api/v1/timeline
Release order is not watch order.
The catalogue isn't one universe either. Every title carries a continuity and an
Earth designation, and /timeline
returns them grouped and ordered by in-story chronology, so you can build a watch
order without maintaining one by hand. Hover a mark to read it; pick a branch to
load it in the console.
Hover any mark to read the title and its chronology position. Movie TV show
Marks are positioned by chronology_order within each branch, not by release date.Snapshot embedded · refreshing from live API…
Live request console
Try it against production, right here.
These calls hit mcuapi.up.railway.app
from your browser — same URL your app will use. Every
href in the response is
clickable, because the API is hypermedia-driven: you can crawl the whole graph
without hardcoding a single path.
READY——Showing a cached example response. Press Send for a live one.
HATEOAS · click any href above to follow it
Three resources, one graph
Everything a record carries.
No partial payloads and no second call to hydrate a title. Every field below is
on the resource by default — trim it with ?columns=
when you want less. Fields marked with a dot are nullable.
Movie
57 records
GET /api/v1/movies · /movies/{id}
id
title
release_date
box_office
duration
overview
cover_url
trailer_url
directed_by
phase
saga
chronology
post_credit_scenes
imdb_id
studio
continuity
multiverse_designation
is_mcu
type
timeline_chronology_order
updated_at
TV show
56 records
GET /api/v1/tvshows · /tvshows/{id}
id
title
release_date
last_aired_date
season
number_episodes
overview
cover_url
trailer_url
directed_by
phase
saga
chronology
imdb_id
studio
continuity
multiverse_designation
is_mcu
type
timeline_chronology_order
updated_at
Character
302 records
GET /api/v1/characters · /characters/{id}
id
name
alias
description
image_url
played_by
continuity
multiverse_designation
variant_of
first_appearance_movie_id
first_appearance_tvshow_id
created_at
updated_at
Recasts and variants
played_by is per character record, and variant_of points a
character at the version they are a variant of — so a recast or a multiverse double
is a real edge in the graph, not a duplicate row you have to reconcile.
Collections
List endpoints wrap results as { data, total, page, limit, _links }
with first, prev, next and last
that preserve every filter you passed in.
Filtering
?filter=column=value for a case-insensitive match,
?order=column,DESC to sort, and ?continuity= or
?is_mcu=false to scope to one branch of the multiverse.
GET /api/v1/characters/{id}/movies
One name, several people, several earths.
Civilian names live on name and hero
names on alias, so the search hits both —
Captain America returns two different people. Every record carrying the term comes back,
including the variants each continuity casts separately, which is why
played_by
sits on the character and not on the title. Pick one and the page follows that record's own
_links.movies and
_links.tvshows to the titles it
appears in. No join table to maintain on your side.
Loading characters from the live API…
Variants are joined by variant_of; each one carries its own played_by.Querying /characters…
Three lines to first data
No key. No setup. Client optional.
# Every Phase 4 movie, newest first, three fields only
curl "https://mcuapi.up.railway.app/api/v1/movies?filter=phase=4&order=release_date,DESC&columns=id,title,release_date"# The full chronological timeline for one branch
curl "https://mcuapi.up.railway.app/api/v1/timeline?multiverse=Earth-10005"
const API = 'https://mcuapi.up.railway.app/api/v1';
// List endpoints return { data, total, page, limit, _links }const res = await fetch(`${API}/movies?filter=title=Spider&limit=5`);
const page = await res.json();
// Follow the hypermedia link instead of building a pathconst cast = await fetch(page.data[0]._links.characters.href)
.then(r => r.json());
import requests
API = "https://mcuapi.up.railway.app/api/v1"# Walk the MCU in chronological order
branches = requests.get(f"{API}/timeline?multiverse=Earth-616").json()
for entry in branches[0]["entries"]:
print(entry["chronology_order"], entry["title"], entry["type"])
# Optional — the API needs no client at all
npm i mcuapi-client
import { MCUAPI } from'mcuapi-client';
const mcu = new MCUAPI();
// Fully typed. box_office is a string — Postgres bigint,// so the compiler stops you treating it as a number.const ironMan = await mcu.movies.get(1);
// Walks every page for you by following _links.nextforawait (const c of mcu.characters.all()) {
console.log(c.name, c.played_by);
}
AuthNone. No key, no hash, no referrer allow-list.
MethodsRead-only — every route is a GET.
Paginationlimit defaults to 10, capped at 100. Collections carry first, prev, next, last.
Rate limit100 requests per minute per IP, with RateLimit-* headers and a 429 past it.
CachingCache-Control: public, max-age=3600 plus an ETag. Send If-None-Match for a 304.
CORSAccess-Control-Allow-Origin: * — call it straight from the browser.
Open source · issues welcome
Built it because the data should stay reachable.
Express, TypeScript, TypeORM and Postgres, organised as clean-architecture
modules. If a title is missing, a cover is broken, or you want a field that
isn't there yet, open an issue — the dataset is maintained by hand and every
correction lands for everyone.