> ## 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.

# Authorize (V2)

> Browser-facing consent page for the AUTH V2 authorization code flow. **This is not an API call** -- open it in the user's browser (or a system web view) and let Simkl redirect back to you.

This page is on `simkl.com`. Pointing it at `api.simkl.com` returns a 404, which is the single most common mistake when wiring up OAuth.

You do not have to hardcode that host. Simkl publishes an RFC 8414 discovery document at `/.well-known/oauth-authorization-server`, and its `authorization_endpoint` always names the right one. Point a compatible library at the issuer `https://simkl.com` and it resolves this URL, the token URL and the supported PKCE methods for itself. See [Discovery](/api-reference/auth-v2#discovery).

PKCE is mandatory: `code_challenge` is required and `code_challenge_method` must be `S256`. See [PKCE in AUTH V2](/api-reference/oauth2-pkce).

### What comes back

On approval Simkl redirects to your `redirect_uri` with `code`, your `state` echoed byte-for-byte, and `iss` (RFC 9207). On refusal it redirects with `error=access_denied` instead.

Errors split by whether the redirect target can be trusted. A bad `client_id` or an unregistered `redirect_uri` renders a JSON error and **never redirects**, which prevents your app being used as an open redirect. Everything else redirects back with `error` set.

`redirect_uri` is validated before PKCE, so while the redirect URI is wrong you will not be told that your PKCE parameters are also missing.

After approval Simkl may show a brief interstitial before redirecting. That is deliberate and gives the authorization code time to replicate between regions.



## OpenAPI

````yaml /openapi.json get /oauth2/authorize
openapi: 3.1.0
info:
  title: Simkl API
  version: 1.0.0
  description: >-
    The **Simkl API** lets you build apps that track Movies, TV Shows, and Anime
    — scrobble playback, sync watch history, and pull rich metadata.


    All requests use HTTPS and return JSON. The base URL is
    `https://api.simkl.com`.


    **Every request needs three URL parameters and a `User-Agent` header:**


    ```

    /endpoint?client_id=YOUR_CLIENT_ID&app-name=my-app&app-version=1.0

    ```


    See [Headers and required parameters](/conventions/headers) for the full
    reference. Endpoints that read or modify a user's data also need an
    `Authorization: Bearer <token>` header — see [OAuth
    2.0](/api-reference/oauth) or the [PIN flow](/api-reference/pin).


    > ⚠️ **About the auto-rendered cURL examples on each endpoint page:** they
    omit `?client_id=…&app-name=…&app-version=…` from the URL for brevity. **You
    must add them yourself when copy-pasting**, or use the interactive **"Try
    it"** playground (it fills them in for you). This is a Mintlify rendering
    convention — every Mintlify-built API doc behaves the same way.


    **Get started**


    - [Quickstart](/quickstart) — first request in 60 seconds

    - [API rules](/api-rules) — what's allowed, what isn't

    - [Standard media objects](/conventions/standard-media-objects) — the shapes
    every endpoint speaks

    - [Errors](/conventions/errors) — every status code Simkl returns
  contact:
    name: Simkl Developer Support
    url: https://support.simkl.com
  termsOfService: https://simkl.com/about/policies/terms/
  license:
    name: Simkl API Terms of Use
    url: https://simkl.com/about/policies/terms/
  x-logo:
    url: https://i.simkl.com/img_tv/apiary_logo_api.png
    backgroundColor: '#0E5DAB'
    altText: Simkl
servers:
  - url: https://api.simkl.com
    description: Production API
  - url: https://data.simkl.in
    description: CDN for static, public data files (Calendar + Trending). No auth required.
security:
  - clientId: []
  - simklApiKey: []
tags:
  - name: OAuth V2
    description: >-
      Standards-compliant OAuth 2.0 with PKCE, scopes and refresh tokens. The
      recommended way to authenticate new apps.
  - name: OAuth 2.0
    description: >-
      OAuth 2.0 authorization-code flow for web and mobile apps. The user is
      redirected to Simkl, signs in, approves your app, and is redirected back
      with a `code` you exchange for an `access_token`. Long-lived tokens — no
      refresh-token flow needed.
    externalDocs:
      description: OAuth 2.0 walkthrough
      url: https://api.simkl.org/api-reference/oauth
  - name: PIN
    description: >-
      Device flow for TVs, consoles, smart watches, CLI tools — anywhere typing
      a URL is hard. Show a 5-character code; user enters it on simkl.com/pin;
      you poll for the access token. **No `client_secret` required.**
    externalDocs:
      description: PIN flow walkthrough
      url: https://api.simkl.org/api-reference/pin
  - name: Redirect
    description: >-
      Helper redirects for one-click "mark as watched", trailers, sharing, and
      more.
  - name: Search
    description: Find shows, movies, and anime by ID, text query, file name, or randomly.
    externalDocs:
      description: Search guide
      url: https://api.simkl.org/guides/search
  - name: Movies
    description: >-
      Browse the Simkl movies catalog: details, premieres, top-of-best, and
      genre filters.
  - name: TV
    description: >-
      Browse the Simkl TV catalog: details, episodes, what's airing, premieres,
      top-of-best, and genre filters.
  - name: Anime
    description: >-
      Browse the Simkl anime catalog: details, episodes, what's airing,
      premieres, top-of-best, and genre filters.
  - name: Ratings
    description: >-
      Read Simkl's average community rating, rank, drop rate, and external
      ratings (IMDB, MAL) for any item, or for every item in a user's lists.
  - name: Scrobble
    description: >-
      Report real-time playback to Simkl with `start`, `pause`, and `stop`. At ≥
      80 % progress Simkl marks the item as watched automatically; below 80 %
      the session is saved as a paused playback the user can resume from any
      device.


      See [Standard media objects](/conventions/standard-media-objects) for the
      supported ID keys.


      <!-- IDS_TABLE_START -->


      ### Supported ID keys


      Inside any `ids` object, pass as many of these as you have. Simkl resolves
      to the canonical record.


      | ID key | Type | Example |

      |---|---|---|

      | `simkl` | integer | `49108`. Simkl's canonical ID. Most reliable. |

      | `imdb` | string | `tt1520211` |

      | `tmdb` | integer | `76757` (for TV, specify `type`) |

      | `tvdb` | int / string | `153021` or `the-walking-dead` |

      | `mal` | integer | `4246` (MyAnimeList) |

      | `anidb` | integer | `10846`. Specifying just this is enough for anime
      lookups. |

      | `anilist` | integer | `21` |

      | `kitsu` | integer | `12` |

      | `anisearch` | integer | `2227` |

      | `animeplanet` | string | `one-piece` |

      | `livechart` | integer | `321` |

      | `letterboxd` | string | `the-truman-show` |

      | `netflix` | integer | `70210890` (movie ID) |

      | `traktslug` | string | `john-wick-chapter-4-2023` |


      > 📖 Full reference: [Standard media
      objects](/conventions/standard-media-objects)


      <!-- IDS_TABLE_END -->
    externalDocs:
      description: Scrobble guide
      url: https://api.simkl.org/guides/scrobble
  - name: Sync
    description: >-
      Use Simkl as a cloud backup for the user's watch history and lists
      (Watching, Plan to Watch, On Hold, Dropped, Completed). **Always check
      [`/sync/activities`](/api-reference/simkl/get-activities) first** and sync
      only the lists that have moved.


      All write endpoints accept arrays — batch aggressively. See [Standard
      media objects](/conventions/standard-media-objects) for the supported ID
      keys.


      <!-- IDS_TABLE_START -->


      ### Supported ID keys


      Inside any `ids` object, pass as many of these as you have. Simkl resolves
      to the canonical record.


      | ID key | Type | Example |

      |---|---|---|

      | `simkl` | integer | `49108`. Simkl's canonical ID. Most reliable. |

      | `imdb` | string | `tt1520211` |

      | `tmdb` | integer | `76757` (for TV, specify `type`) |

      | `tvdb` | int / string | `153021` or `the-walking-dead` |

      | `mal` | integer | `4246` (MyAnimeList) |

      | `anidb` | integer | `10846`. Specifying just this is enough for anime
      lookups. |

      | `anilist` | integer | `21` |

      | `kitsu` | integer | `12` |

      | `anisearch` | integer | `2227` |

      | `animeplanet` | string | `one-piece` |

      | `livechart` | integer | `321` |

      | `letterboxd` | string | `the-truman-show` |

      | `netflix` | integer | `70210890` (movie ID) |

      | `traktslug` | string | `john-wick-chapter-4-2023` |


      > 📖 Full reference: [Standard media
      objects](/conventions/standard-media-objects)


      <!-- IDS_TABLE_END -->
    externalDocs:
      description: Sync guide
      url: https://api.simkl.org/guides/sync
  - name: Users
    description: User profile, settings, and watch statistics.
  - name: Lists
    description: >-
      Custom lists, read-only and in beta. Requires a Simkl PRO or VIP access
      token.
externalDocs:
  description: Simkl API documentation
  url: https://api.simkl.org
paths:
  /oauth2/authorize:
    get:
      tags:
        - OAuth V2
      summary: Authorize (V2)
      description: >-
        Browser-facing consent page for the AUTH V2 authorization code flow.
        **This is not an API call** -- open it in the user's browser (or a
        system web view) and let Simkl redirect back to you.


        This page is on `simkl.com`. Pointing it at `api.simkl.com` returns a
        404, which is the single most common mistake when wiring up OAuth.


        You do not have to hardcode that host. Simkl publishes an RFC 8414
        discovery document at `/.well-known/oauth-authorization-server`, and its
        `authorization_endpoint` always names the right one. Point a compatible
        library at the issuer `https://simkl.com` and it resolves this URL, the
        token URL and the supported PKCE methods for itself. See
        [Discovery](/api-reference/auth-v2#discovery).


        PKCE is mandatory: `code_challenge` is required and
        `code_challenge_method` must be `S256`. See [PKCE in AUTH
        V2](/api-reference/oauth2-pkce).


        ### What comes back


        On approval Simkl redirects to your `redirect_uri` with `code`, your
        `state` echoed byte-for-byte, and `iss` (RFC 9207). On refusal it
        redirects with `error=access_denied` instead.


        Errors split by whether the redirect target can be trusted. A bad
        `client_id` or an unregistered `redirect_uri` renders a JSON error and
        **never redirects**, which prevents your app being used as an open
        redirect. Everything else redirects back with `error` set.


        `redirect_uri` is validated before PKCE, so while the redirect URI is
        wrong you will not be told that your PKCE parameters are also missing.


        After approval Simkl may show a brief interstitial before redirecting.
        That is deliberate and gives the authorization code time to replicate
        between regions.
      operationId: get-oauth2-authorize
      parameters:
        - name: client_id
          in: query
          required: true
          schema:
            type: string
          description: Your app's client ID. Must be registered for OAuth V2.
        - name: redirect_uri
          in: query
          required: true
          schema:
            type: string
          description: >-
            Must match a URI registered on your app. Matching is exact, with two
            relaxations: loopback hosts (`127.0.0.1`, `::1`, `localhost`) ignore
            the port, and apps registered as **Mobile, desktop & browser apps**
            may use a registered `*.local` host if the ports match. A fragment
            is always rejected. A registered `https://app/cb` does not match a
            requested `https://app/cb?x=1` -- query strings only work via exact
            match.
        - name: response_type
          in: query
          required: false
          schema:
            type: string
            enum:
              - code
          description: >-
            Always `code`. Required by [RFC 6749 section
            4.1.1](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1)
            and sent automatically by every conformant OAuth library. Simkl does
            not currently reject a request that omits it, but send it anyway --
            it is the only value the authorization endpoint supports, and
            relying on the omission being tolerated is not something to build
            on.
        - name: code_challenge
          in: query
          required: true
          schema:
            type: string
          description: base64url SHA-256 of your `code_verifier`, no padding.
        - name: code_challenge_method
          in: query
          required: true
          schema:
            type: string
            enum:
              - S256
          description: Must be `S256`. `plain` is rejected.
        - name: scope
          in: query
          required: false
          schema:
            type: string
            enum:
              - media:read
              - media:read media:write
          description: >-
            Space-separated scopes. **Omitting this grants `media:read` only**,
            so an app that writes must ask for `media:write` explicitly. An
            unrecognised scope string is silently treated as read-only rather
            than rejected, so a typo costs you write access with no error.
            Always check the `scope` in the token response.
        - name: state
          in: query
          required: false
          schema:
            type: string
          description: >-
            Opaque CSRF value, echoed back byte-for-byte. Generate one per flow,
            store it, and reject the callback if it does not match.
      responses:
        '302':
          description: >-
            Redirect to your `redirect_uri`, carrying either `code` (plus
            `state` and `iss`) or `error`.
        '400':
          description: >-
            Untrusted redirect target, so the error is rendered instead of
            redirected.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuth2Error'
              example:
                error: invalid_client
                error_description: Your client_id is wrong.
      security:
        - {}
      servers:
        - url: https://simkl.com
          description: The consent page is hosted on simkl.com, not api.simkl.com.
      x-codeSamples:
        - lang: Browser
          label: Open this URL in the user's browser
          source: |-
            https://simkl.com/oauth2/authorize
              ?client_id=YOUR_CLIENT_ID
              &redirect_uri=YOUR_REDIRECT_URI
              &response_type=code
              &scope=media:read%20media:write
              &state=RANDOM_CSRF_TOKEN
              &code_challenge=YOUR_CODE_CHALLENGE
              &code_challenge_method=S256
components:
  schemas:
    OAuth2Error:
      type: object
      description: >-
        RFC 6749 section 5.2 error envelope. `error` is a fixed machine-readable
        code; `error_description` is human-readable and may change, so branch on
        `error` only.
      required:
        - error
      properties:
        error:
          type: string
          description: Machine-readable error code.
          enum:
            - invalid_request
            - invalid_client
            - invalid_grant
            - invalid_scope
            - unsupported_grant_type
            - expired_token
            - authorization_pending
            - slow_down
            - server_error
        error_description:
          type: string
          description: >-
            Human-readable explanation. For display and logging, not for
            branching.
  securitySchemes:
    clientId:
      type: apiKey
      in: query
      name: client_id
      description: >-
        Preferred form: your `client_id` as a URL query parameter on every
        request. Self-describing in logs and curl commands. See [Headers and
        required parameters](/conventions/headers).
      x-default: YOUR_CLIENT_ID
    simklApiKey:
      type: apiKey
      in: header
      name: simkl-api-key
      description: >-
        Optional alias for the `client_id` query parameter. Simkl accepts your
        `client_id` either as the `simkl-api-key` request header **or** as the
        `?client_id=…` query parameter — pick one. The query-parameter form is
        preferred because it makes the request fully self-describing in URL
        form.
      x-default: YOUR_CLIENT_ID

````