> ## Documentation Index
> Fetch the complete documentation index at: https://api.simkl.org/llms.txt
> Use this file to discover all available pages before exploring further.

# API rules

> Read this before you ship. The short list of what's required, what's free, and when you need a commercial license.

<Note>
  ### Help us keep the Simkl API at 100% uptime — optimise your app's requests

  The limits below are generous and most apps never hit them. The ones that do are almost always parallelizing calls to endpoints that should be sequential, or polling [`/sync/all-items`](/api-reference/simkl/get-all-items) without gating behind [`/sync/activities`](/api-reference/simkl/get-activities). The patterns on this page keep your app fast **and** keep the API healthy for every other developer building on Simkl.
</Note>

These are the rules of the road for using the Simkl API. They're short, they're real, and they exist for good reasons. Read once, agree, and ship.

By using the Simkl API, you also agree to the full [Simkl Terms](https://simkl.com/about/policies/terms/).

<Warning>
  **Don't get your `client_id` suspended.** The Simkl API caps every app at **10 GET/sec and 1 POST/sec** per `client_id` and per user token — generous, and most apps never hit them. The ones that do are almost always either parallelizing calls to uncached endpoints, or polling [`GET /sync/all-items`](/api-reference/simkl/get-all-items) on a timer without first checking [`GET /sync/activities`](/api-reference/simkl/get-activities) for changes. Apps that sustain overage get their `client_id` suspended **without warning, no appeal** — we see the traffic pattern and turn the key off.

  See [**Rate limits**](/resources/rate-limits) for the full caps, when parallel requests are allowed (only on Cloudflare-cached endpoints), and the sequential-by-default pattern. The two-phase sync model in [Rule 7 → Sync incrementally](#7-be-a-good-api-citizen) shows the correct loop in code.
</Warning>

## 1. Link back to Simkl

Wherever Simkl data appears in your app, link back to the Simkl page for **that specific item** — not just a generic homepage link. Better for users (they can dive into ratings, episodes, related titles, reviews), better for Simkl, and trivial to implement.

<Tabs>
  <Tab title="Movie">
    `https://simkl.com/movies/:simkl_id/:slug` — [example](https://simkl.com/movies/2059585/superman)
  </Tab>

  <Tab title="TV show">
    `https://simkl.com/tv/:simkl_id/:slug` — [example](https://simkl.com/tv/1076658/the-witcher)
  </Tab>

  <Tab title="Anime">
    `https://simkl.com/anime/:simkl_id/:slug` — [example](https://simkl.com/anime/38636/one-piece)
  </Tab>
</Tabs>

Both `ids.simkl` and `ids.slug` are returned on every [standard media object](/conventions/standard-media-objects), so the slug is **free** — you already have it in the response you just parsed.

<Tip>
  **Always include the slug when you have it.** It's technically optional — bare numeric URLs like `simkl.com/movies/53536` still work — but Simkl has to run a database lookup and `301`-redirect to the slugged URL, costing your user an extra round-trip and Simkl an extra search query. The slug is right there in `ids.slug`; pass it through and everyone wins.
</Tip>

<Warning>
  **The `simkl` ID is the only stable identifier — slugs are not unique.** Multiple titles can share the same slug (e.g. three different *Superman* movies live at `/movies/2059585/superman`, `/movies/260740/superman`, `/movies/951252/superman`). Always build links with the numeric ID first; the slug is purely a human-readable URL hint. Never key your cache or do a lookup by slug alone.
</Warning>

```js title="build-simkl-url.js" theme={"theme":{"light":"github-light","dark":"vesper"}}
function simklUrl(item) {
  const section = { movie: 'movies', anime: 'anime' }[item.type] || 'tv';
  return 'https://simkl.com/' + section + '/' +
    (item.ids.simkl || item.ids.simkl_id) + '/' +
    (item.ids.slug || '');
}

simklUrl(movieDetails);   // → https://simkl.com/movies/1306562/project-hail-mary
simklUrl(tvDetails);      // → https://simkl.com/tv/967226/the-boys
simklUrl(animeDetails);   // → https://simkl.com/anime/1885096/tongari-boushi-no-atelier

// No slug? URL ends with /:
simklUrl({ type: 'movie', ids: { simkl: 53536 } });
// → https://simkl.com/movies/53536/
```

Notes on the moving parts:

* TV detail responses set `item.type = "show"` even though the URL section is `/tv/`. The map deliberately only lists `movie` and `anime`; anything else (including `"show"` and the empty `type` returned by `/search/*` and `/{movies|tv|anime}/trending`) falls through to `/tv/` — Simkl will 301 to the correct section if needed, but you should set `item.type` yourself when you already know it (e.g. on `/movies/trending` results) to skip that hop.
* The id key is either `ids.simkl` (detail endpoints, `/sync/*` responses, request bodies) or `ids.simkl_id` (`/search/*`, `/trending`, `/calendar`, `/genres`, `/best`, `/premieres`, episode-level detail). The same integer; the key name differs by endpoint family — `simkl || simkl_id` covers both. See [Standard media objects → Supported ID keys](/conventions/standard-media-objects#supported-id-keys).

<Note>
  **Don't have a Simkl ID yet?** If all you have is an external ID — IMDB, TMDB, TVDB, MAL, AniDB, etc. — drop a [`/redirect`](/api-reference/redirect) URL **straight into your `<a href>`**. No request, no parsing, no JSON — the browser follows the `301` for you and the user lands on the canonical Simkl page.

  ```html theme={"theme":{"light":"github-light","dark":"vesper"}}
  <a href="https://api.simkl.com/redirect?to=simkl&imdb=tt0944947&client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0">
    View on Simkl
  </a>
  ```

  [Click to try it](https://api.simkl.com/redirect?to=simkl\&imdb=tt0944947\&client_id=YOUR_CLIENT_ID\&app-name=my-app-name\&app-version=1.0) → lands on [`https://simkl.com/tv/17465/game-of-thrones`](https://simkl.com/tv/17465/game-of-thrones).
</Note>

<AccordionGroup>
  <Accordion title="Where to put the link in your UI" icon="map-pin">
    Six placements that count as proper attribution:

    * **Detail page** — a "View on Simkl" button or `Source: Simkl` line under the cover art.
    * **List / grid rows** — make the cover or title clickable directly to the item's Simkl page.
    * **Hover cards / tooltips** — include a "More on Simkl →" link inside the popover.
    * **Footer / About** — a one-time `Movie, TV and anime data from Simkl` line.
    * **Trending sections** — the title must say "Simkl" (see [rule 6](#6-attribute-simkl-in-trending-ui)) **and** items should deep-link to their Simkl page.
    * **Empty / loading states** — "Powered by Simkl" line linking to [simkl.com](https://simkl.com) when no specific item is in view yet.
  </Accordion>

  <Accordion title="Fallback when per-item links genuinely aren't possible" icon="circle-dot">
    For a one-line text widget or a watch ticker where you only have room for a single link, a visible link to [simkl.com](https://simkl.com) is the minimum.
  </Accordion>

  <Accordion title="What does NOT count as attribution" icon="circle-xmark">
    * A `simkl.com` link buried in your privacy policy with no visible UI attribution.
    * An unbranded `<a href="https://simkl.com">More info</a>` that doesn't say "Simkl".
    * Fetching Simkl data into your own database and dropping the link entirely.
  </Accordion>

  <Accordion title="Example attribution snippets" icon="code">
    <Note>
      **These are just illustrative samples — not visual requirements.** Match the colours, shape, type, and density to your own design system. The only attribution rules are the substantive ones above: Simkl is named, the brand mark is visible, and the link goes to the per-item page with the slug.
    </Note>

    Two brand-mark assets are available — the **colored PNG** for full-colour brand badges and the **monochrome SVG** (transparent "S" cutout) for icons that recolour with their parent via CSS `filter`:

    | Asset          | URL                                                        |
    | -------------- | ---------------------------------------------------------- |
    | Colored PNG    | `https://us.simkl.in/img_favicon/v2/favicon-192x192.png`   |
    | Monochrome SVG | `https://us.simkl.in/img_favicon/v2/safari-pinned-tab.svg` |

    <Frame caption="Four drop-in attribution patterns — pick whichever fits your UI or create your own">
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '20px', alignItems: 'center', justifyContent: 'center', padding: '24px 16px' }}>
        <a href="https://simkl.com/movies/53536/terminator-3-rise-of-the-machines" style={{ display: 'inline-flex', alignItems: 'center', gap: '8px', padding: '6px 12px', border: '1px solid currentColor', borderRadius: '999px', textDecoration: 'none', color: 'inherit' }}>
          <img src="https://us.simkl.in/img_favicon/v2/favicon-192x192.png" width="18" height="18" alt="Simkl" style={{ borderRadius: '3px' }} />

          <span style={{ color: '#FBBF24', fontSize: '14px', lineHeight: 1 }}>★</span>
          <span style={{ fontWeight: 700, fontSize: '14px' }}>7.8</span>
        </a>

        <a href="https://simkl.com/movies/53536/terminator-3-rise-of-the-machines" style={{ display: 'inline-flex', alignItems: 'center', gap: '10px', padding: '8px 14px', border: '1px solid #3B82F6', borderRadius: '10px', textDecoration: 'none', color: 'inherit', background: 'rgba(59,130,246,0.06)' }}>
          <img src="https://us.simkl.in/img_favicon/v2/favicon-192x192.png" width="22" height="22" alt="Simkl" style={{ borderRadius: '4px' }} />

          <span style={{ color: '#FBBF24', fontSize: '15px', lineHeight: 1 }}>★</span>
          <span style={{ fontWeight: 700, fontSize: '15px' }}>7.8</span>
          <span style={{ opacity: 0.65, fontSize: '13px' }}>on Simkl</span>
          <span style={{ marginLeft: '4px', opacity: 0.5 }}>→</span>
        </a>

        <a href="https://simkl.com/movies/53536/terminator-3-rise-of-the-machines" style={{ display: 'inline-flex', alignItems: 'center', gap: '6px', padding: '8px 12px', textDecoration: 'none', color: 'inherit', fontSize: '14px' }}>
          <img src="https://us.simkl.in/img_favicon/v2/favicon-192x192.png" width="16" height="16" alt="Simkl" style={{ borderRadius: '3px' }} />

          <span>More on Simkl →</span>
        </a>

        <a href="https://simkl.com" style={{ display: 'inline-flex', alignItems: 'center', gap: '8px', padding: '8px 14px', background: '#000', color: 'white', borderRadius: '999px', textDecoration: 'none', fontSize: '13px', fontWeight: 600 }}>
          <img src="https://us.simkl.in/img_favicon/v2/safari-pinned-tab.svg" width="14" height="14" alt="Simkl" style={{ filter: 'brightness(0) invert(1)' }} />

          <span>Powered by Simkl</span>
        </a>
      </div>
    </Frame>

    <CodeGroup>
      ```html Minimal rating pill (PNG) theme={"theme":{"light":"github-light","dark":"vesper"}}
      <a href="https://simkl.com/movies/53536/terminator-3-rise-of-the-machines"
         style="display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; border: 1px solid currentColor; border-radius: 999px; text-decoration: none; color: inherit;">
        <img src="https://us.simkl.in/img_favicon/v2/favicon-192x192.png" width="18" height="18" alt="Simkl" style="border-radius: 3px;">
        <span style="color: #FBBF24;">★</span>
        <span style="font-weight: 700;">7.8</span>
      </a>
      ```

      ```html Rating badge (PNG) theme={"theme":{"light":"github-light","dark":"vesper"}}
      <a href="https://simkl.com/movies/53536/terminator-3-rise-of-the-machines"
         style="display: inline-flex; align-items: center; gap: 10px; padding: 8px 14px; border: 1px solid #3B82F6; border-radius: 10px; text-decoration: none; color: inherit; background: rgba(59,130,246,0.06);">
        <img src="https://us.simkl.in/img_favicon/v2/favicon-192x192.png" width="22" height="22" alt="Simkl" style="border-radius: 4px;">
        <span style="color: #FBBF24;">★</span>
        <span style="font-weight: 700;">7.8</span>
        <span style="opacity: 0.65; font-size: 13px;">on Simkl</span>
        <span style="margin-left: 4px; opacity: 0.5;">→</span>
      </a>
      ```

      ```html Inline "More on Simkl" (PNG) theme={"theme":{"light":"github-light","dark":"vesper"}}
      <a href="https://simkl.com/movies/53536/terminator-3-rise-of-the-machines"
         style="display: inline-flex; align-items: center; gap: 6px; text-decoration: none; color: inherit;">
        <img src="https://us.simkl.in/img_favicon/v2/favicon-192x192.png" width="16" height="16" alt="Simkl" style="border-radius: 3px;">
        <span>More on Simkl →</span>
      </a>
      ```

      ```html "Powered by Simkl" pill (SVG) theme={"theme":{"light":"github-light","dark":"vesper"}}
      <a href="https://simkl.com"
         style="display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; background: #000; color: white; border-radius: 999px; text-decoration: none; font-weight: 600;">
        <img src="https://us.simkl.in/img_favicon/v2/safari-pinned-tab.svg" width="14" height="14"
             alt="Simkl" style="filter: brightness(0) invert(1);">
        <span>Powered by Simkl</span>
      </a>
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

<Note>
  Not sure how to implement this for your specific app? [DM us on Discord](https://discord.gg/MJsWNE4) or visit [support.simkl.com](https://support.simkl.com) — we'll help you find the right placement.
</Note>

## 2. Tracker apps must offer Simkl sync

If your app or service is a Movie / TV / Anime / Manga **tracker** that already syncs with another tracker, you may use the Simkl API only if you also offer **Simkl login and sync** alongside.

In other words: the catalog and discovery endpoints are not a free metadata source for a competing tracker that doesn't integrate Simkl. If you're integrating Simkl as one of multiple supported services in a media app, you're good. If you're using Simkl's catalog without offering Simkl sync, [contact us first](/support).

## 3. Use TVDB / TMDB for raw metadata

If you need a generic metadata host, please use [TVDB](https://thetvdb.com) and [TMDB](https://themoviedb.org) APIs from their original sources. Simkl is built for **tracking and discovery**, not as a CDN for the world's metadata.

## 4. Keep your `client_secret` secret

<Warning>
  `client_secret` is a credential — treat it like a password. Never commit it to a public repo, and never embed it in code that ships to a user's device (mobile apps, single-page apps, browser extensions, desktop binaries). On a server, store it in an environment variable; in CI, store it as an encrypted secret — every CI provider supports this natively. A leaked secret lets anyone authenticate as your app, eats into your rate-limit quota, and forces you to rotate from your [app settings](https://simkl.com/settings/developer/) and re-auth every user.

  `client_id` is **not** a secret — it's a public identifier that appears in every API URL and is fine to include in client-side code. The thing to protect is `client_secret`.
</Warning>

For client-side apps that can't keep a secret, pick the flow that matches your platform — both work without `client_secret`:

* **Mobile, single-page app, browser extension, desktop binary** — use [Public PKCE](/api-reference/oauth-pkce). Same browser-based UX as the standard OAuth flow, with a one-time `code_verifier` instead of a shipped secret.
* **TV, console, smartwatch, CLI tool, media-server plugin** — use the [PIN flow](/api-reference/pin). Show a 5-character code, the user enters it on their phone.

## 5. Free for non-commercial use, and under \$150 / month

The Simkl API is **free** for:

* Non-commercial apps and personal projects.
* Commercial apps and services that generate **less than \$150 / month in revenue**.

If your app generates **\$150 / month or more**, you must obtain a **commercial license** before continuing to use the API. [Reach out via Discord](https://discord.gg/MJsWNE4) to discuss terms.

<Note>
  Running the API at scale costs us real money in DNS, routing, health checks, CDN, server hosting, failover, and ops. Commercial fees cover those costs proportional to your usage.
</Note>

## 6. Attribute Simkl in trending UI

If you display [Trending data](/api-reference/trending), you must use a section title that names Simkl — for example, `Simkl Trending Today`, `Trending on Simkl This Week`, `Simkl Trending Movies`. Full rules and examples on the [Trending page](/api-reference/trending#attribution-required).

## 7. Be a good API citizen

These are the habits well-built apps share. They keep your app fast, keep your users happy, and keep your traffic well clear of the rate-limit and overage patterns that trip the suspension warning at the top of this page.

<AccordionGroup>
  <Accordion title="Cache aggressively">
    Most metadata never changes. Cache by URL on the device — minutes for user data, hours for catalogs, **forever** for [images](/conventions/images).
  </Accordion>

  <Accordion title="Use the CDN files where you can">
    The [Trending](/api-reference/trending) and [Calendar](/api-reference/calendar) JSON files don't count against your `client_id` quota and are cached at the edge. Always prefer them over per-user catalog calls.
  </Accordion>

  <Accordion title="Sync incrementally">
    **Never call watchlist endpoints without first checking [`/sync/activities`](/api-reference/simkl/get-activities).** And never run unconditional background polling timers without active user interaction.

    Use a two-phase pattern:

    1. **Initial sync (one time per user)** — pull the full library, no `date_from` on this pass.
       * **Multi-type apps:** call `/sync/all-items/shows`, `/sync/all-items/movies`, `/sync/all-items/anime` **sequentially** (not in parallel — back-to-back massive payloads spike your CPU and ours).
       * **Single-type apps** (anime-only, movie-only, TV-only): call only the one type you care about.
    2. **Continuous sync (every poll after that)** — call `/sync/activities` first; if every timestamp matches what you stored locally, skip. Otherwise:

       * **Multi-type apps:** `/sync/all-items?date_from=YOUR_SAVED_TIMESTAMP` — pulls deltas across all types and statuses in one response.
       * **Single-type apps:** `/sync/all-items/{your_type}?date_from=YOUR_SAVED_TIMESTAMP` — same delta semantics, scoped to one type so you don't transfer data you'll discard.

       Save the new `activities.all` timestamp for next time.

    Triggers — sync **on user-visible events**, not timers:

    * **Mobile / TV apps** — app start, wake-from-background, pull-to-refresh. Throttle to once per 15–30 min.
    * **Media servers (Plex, Kodi, Jellyfin)** — library-scan-completed events, or when a playback session ends.

    Full walkthrough with code: [Sync guide](/guides/sync).
  </Accordion>

  <Accordion title="Batch writes">
    `POST /sync/history`, `POST /sync/history/remove`, `POST /sync/ratings`, and `POST /sync/add-to-list` all accept arrays. Send 50 items in one call, not 50 calls.
  </Accordion>

  <Accordion title="Set a User-Agent">
    Identify your app: `myapp/1.0`. It helps us tell legitimate clients apart from bad actors and keeps you out of any accidental blocks.
  </Accordion>

  <Accordion title="Retry transient errors with backoff">
    On `429`, `500`, `502`, `503`: wait, retry, double the wait, cap at 60s, give up after 5 attempts. See [Errors](/conventions/errors).
  </Accordion>
</AccordionGroup>

## More

<CardGroup cols={3}>
  <Card title="Rate limits" icon="gauge" href="/resources/rate-limits">
    The full set of limit signals and how to handle them.
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/conventions/errors">
    Every status code Simkl returns and what to do about it.
  </Card>

  <Card title="Get help" icon="life-ring" href="/support">
    Discord, email, GitHub — pick your favorite.
  </Card>
</CardGroup>
