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

# Créer un token de surveillance | API Didit

> POST /monitoring-token/ (API Didit) échange un jeton d'accès contre un identifiant d'appareil de 15 minutes lié au vendor_data et au navigateur.

> [!WARNING]
>
> L'authentification est une nouveauté, et cet endpoint reste désactivé tant que Didit ne l'active pas : jusque-là, il répond `503 monitoring_unavailable`.

Les SDK pour navigateur et les SDK natifs appellent cet endpoint depuis l'appareil de la personne ; votre serveur n'en a pas besoin. Chaque événement envoyé avec l'identifiant est enregistré dans le `vendor_data` de la personne, quelles que soient les informations que déclare l'appareil.


## OpenAPI

````yaml fr/openapi-authentication.json POST /monitoring-token/
openapi: 3.0.3
info:
  title: Didit Authentication API
  version: 1.0.0
  description: >-
    Les endpoints côté serveur de Didit Authentication, le produit de connexion
    pour les utilisateurs finaux de votre application. Authentication est
    **nouveau** et arrive en production dans la version 2026-11-01.


    ## URL de base


    Chaque application constitue son propre émetteur OpenID Connect, et chaque
    endpoint ci-dessous est servi à la racine de cet émetteur :


    - `https://<name>.auth.didit.me` pour une application en production, ou
    `https://<name>.sandbox.auth.didit.me` pour une application en sandbox.

    - Votre propre domaine personnalisé, une fois actif. Il remplace alors
    l'hôte par défaut en tant qu'émetteur : les nouveaux tokens l'indiquent dans
    `iss`, la découverte pointe vers lui et la clé publiable change. Les tokens
    d'accès émis sous l'hôte par défaut échouent sur `/session/`, `/step-up/` et
    `/monitoring-token/` tant qu'ils ne sont pas rafraîchis.


    La production et le sandbox sont des applications distinctes ; ce sont donc
    des émetteurs distincts disposant de clés distinctes. La clé publiable est
    `pk_live_` (production) ou `pk_test_` (sandbox), suivie de l'encodage
    base64url sans remplissage de l'émetteur, sans barre oblique finale :
    décodez-la pour retrouver l'émetteur. Il s'agit d'un identifiant public, pas
    d'un identifiant d'authentification.


    Les mêmes endpoints JSON sont également servis sous
    `https://apx.didit.me/auth/v2/authentication/{application_id}/`. Les tokens
    indiquent toujours l'émetteur ci-dessus, quelle que soit l'adresse qui les a
    émis.


    ## Identifiants


    Ces endpoints n'acceptent jamais votre clé API Didit ni un token de console.


    - La découverte, le JWKS et `POST /token/` ne prennent aucun identifiant.
    Les clients sont publics : il n'y a pas de secret client, et un code
    d'autorisation est lié à son vérificateur PKCE (`S256`). `client_id` est
    l'identifiant de votre application.

    - `/session/`, `/step-up/` et `/monitoring-token/` prennent le token d'accès
    de la personne : `Authorization: Bearer <access_token>`. Chaque appel réussi
    compte comme une activité sur la session, ce qui réinitialise le délai
    d'inactivité de la session.


    ## Corps de requête


    Chaque endpoint acceptant un corps prend en charge les corps au format JSON,
    au format formulaire et multipart. Ce document liste le format JSON, ainsi
    que le format encodé en formulaire pour `POST /token/` tel que les clients
    OAuth l'envoient. Un champ que l'endpoint n'accepte pas renvoie `400
    {"<field>": "unknown_field"}`.


    ## Tokens


    - **Token d'accès** : un JWT ES256 avec l'en-tête `typ: at+jwt`, valide
    pendant au maximum 5 minutes et jamais plus longtemps que sa session.
    Revendications : `AccessTokenClaims`.

    - **Token d'identification** : un JWT ES256 avec l'en-tête `typ: JWT`.
    Revendications : `IDTokenClaims`. Il n'est jamais accepté en tant que token
    d'accès.

    - **Token d'actualisation** : une chaîne aléatoire renouvelée à chaque
    utilisation. Envoyer à nouveau un token d'actualisation déjà utilisé révoque
    la session.


    Vérifiez un token à l'aide des clés provenant de `GET
    /.well-known/jwks.json` : l'algorithme doit être `ES256`, `typ` doit
    correspondre au type de token, `iss` doit être égal à l'émetteur configuré
    et `aud` à l'identifiant de votre application. La vérification hors ligne ne
    détecte une session révoquée qu'une fois son token d'accès expiré ; `GET
    /session/` constitue la vérification instantanée.


    ## Erreurs


    | Corps | Quand |

    | --- | --- |

    | `{"error": "<code>"}` | Erreurs de `POST /token/`, toutes avec le statut
    `400`, au format de corps de la [section 5.2 de la RFC
    6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2) : `invalid_grant`,
    `invalid_client` et le `mfa_required` de Didit. Erreurs de service :
    `temporarily_unavailable`, `monitoring_unavailable`, `monitoring_disabled`.
    |

    | `{"<field>": ["<message>"]}` ou `{"<field>": "<code>"}` | La validation
    d'un champ de la requête a échoué. `non_field_errors` indique une règle
    s'appliquant à plusieurs champs, et `unknown_field` un champ que l'endpoint
    n'accepte pas. |

    | `{"detail": "<message>"}` | `401` (`invalid_token`), `403`
    (`origin_not_allowed`), `404` (application inconnue ou step-up inconnu) et
    `429` (limite de débit). Également `400` pour un corps impossible à analyser
    (`JSON parse error - ...`), `405` pour une méthode que l'endpoint ne prend
    pas en charge et `415` pour un `Content-Type` non pris en charge. |


    Une réponse `401` comporte également `WWW-Authenticate: Bearer`, et une
    réponse `429` comporte `Retry-After` en secondes.


    Deux refus ne sont pas au format JSON. Une adresse qui n'est pas un émetteur
    est refusée avant d'atteindre ces endpoints, par exemple avec une erreur
    `404` vide pour un nom `*.auth.didit.me` non utilisé. Un `step_up_id` qui
    n'est pas un UUID renvoie une page `404`.


    ## Limites de débit


    Une requête doit franchir deux couches.


    **Limites par endpoint**, comptabilisées par adresse IP cliente, par
    application et par endpoint :


    - Découverte et JWKS : 1 200 requêtes par minute et 12 000 par heure.

    - Tous les autres endpoints : 30 requêtes par minute et 300 par heure. `GET`
    et `DELETE /session/` partagent le même décompte.


    En cas de dépassement de la limite : `429 {"detail": "Too many requests from
    this IP address. Please wait before trying again. Expected available in 60
    seconds."}`, ou `3600 seconds` pour la limite horaire.


    **Protection contre les bots**, sur chaque `POST` et `DELETE`. Ses
    compartiments sont partagés par toutes les requêtes `POST` et `DELETE` de
    l'application, y compris les étapes de connexion hébergées, et se
    remplissent en continu :


    - 60 requêtes par minute par adresse IP cliente.

    - 30 requêtes par minute par appareil, pour les requêtes qui identifient
    leur appareil, comme le font les SDK natifs et de navigateur.

    - 3 000 requêtes par minute pour l'ensemble de l'application, toutes
    adresses IP confondues. Les rafraîchissements de token (`POST /token/` avec
    `grant_type=refresh_token`) utilisent plutôt leur propre compartiment : 6
    000 par minute pour l'ensemble de l'application.


    En cas de dépassement d'un compartiment : `429 {"detail": "rate_limited
    Expected available in N seconds."}` (`1 second.` lorsque N vaut 1). Le
    compartiment par IP s'étend sur l'ensemble des endpoints ; ainsi, une
    adresse unique qui combine des appels de token, de step-up et de déconnexion
    peut le vider avant même d'atteindre la moindre limite par endpoint. Le
    compartiment applicatif prend en compte chaque client de l'application, y
    compris les navigateurs.


    Les deux couches répondent avant l'exécution de l'endpoint : une requête
    ayant reçu une réponse `429` n'a donc pas été exécutée. Réessayez-la après
    le délai indiqué par `Retry-After`, y compris pour un rafraîchissement.


    ## Requêtes de navigateur


    Une requête comportant un en-tête `Origin` doit provenir de l'une des
    origines propres à l'application ou de ses origines autorisées, sous peine
    de recevoir une erreur `403 origin_not_allowed`. Les requêtes de serveur à
    serveur n'envoient aucun en-tête `Origin`.


    ## Non traité ici


    Ces routes desservent les pages hébergées, les SDK natifs et de navigateur,
    ainsi que les agents IA. Elles ne font pas partie du contrat serveur, et les
    SDK serveur ne les appellent pas :


    - Étapes de connexion : `POST /authorize/`, `POST /password/`, `/email/*`,
    `/phone/*`, `/password-reset/*`, `/passkeys/*`, `/mfa/*`, `/social/*` et
    `/protection/complete/`.

    - Pages hébergées et rappels : `/sign-in`, `/magic`, `/invite`, `/reset`,
    `/verify/`, `/sso/*`, `/wallet/callback/`, `/logo/` et les fichiers
    d'association d'applications natives sous `/.well-known/`.

    - Accès pour les agents : `/agents/*` et `/grants/`, y compris `GET
    /agents/session/`, la vérification en direct du token d'accès d'un agent IA.
    L'accès des agents ne fait pas partie de cette version du contrat.

    - L'API de gestion de la console pour Authentication, qui requiert des
    sessions de console.


    Les événements d'Authentication ne sont pas encore transmis sous forme de
    webhooks ; ce document ne définit donc aucun webhook.
servers:
  - url: https://{issuer}
    description: 'L''émetteur de votre application : son origine de connexion.'
    variables:
      issuer:
        default: your-app.auth.didit.me
        description: >-
          L'hôte de l'émetteur : `<name>.auth.didit.me` (production),
          `<name>.sandbox.auth.didit.me` (sandbox) ou votre domaine personnalisé
          actif.
security: []
tags:
  - name: Issuer
    description: Clés de découverte et de signature, pour vérifier les tokens.
  - name: Tokens
    description: Les autorisations par code d'autorisation et de renouvellement.
  - name: Sessions
    description: Vérifier et terminer la session associée à un token d'accès.
  - name: Step-ups
    description: Vérification avant une action sensible.
  - name: Monitoring
    description: >-
      Informations d'authentification de l'appareil pour les événements de
      surveillance des transactions.
paths:
  /monitoring-token/:
    post:
      tags:
        - Monitoring
      summary: Créer un token de surveillance
      description: >-
        Échange le token d'accès de la personne contre un identifiant d'appareil
        éphémère, afin que le navigateur ou l'application de la personne puisse
        envoyer des événements d'activité à la surveillance des transactions
        sans passer par votre backend. L'identifiant est lié au `vendor_data` de
        la personne et à l'`Origin` de la requête.


        Les SDK navigateur et natifs appellent cet endpoint ; les SDK serveur ne
        le font pas. Il est désactivé tant que Didit ne l'a pas activé, et
        répond `503 monitoring_unavailable` d'ici là.
      operationId: authentication_create_monitoring_token
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MonitoringTokenRequest'
            example: {}
      responses:
        '201':
          description: Un identifiant d'appareil pour la personne.
          headers:
            Cache-Control:
              description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
              schema:
                type: string
                example: no-store
            Pragma:
              description: Toujours `no-cache`.
              schema:
                type: string
                example: no-cache
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MonitoringToken'
              examples:
                MonitoringToken:
                  summary: Un identifiant pour le navigateur de la personne
                  value:
                    monitoring_token: mt_2f8c1d9e7b6a5f4e3d2c1b0a
                    expires_at: '2026-10-17T10:56:14Z'
                    allowed_event_categories:
                      - session
                      - gameplay
                      - bonus
                      - affiliate
                      - payment
                      - dispute
                      - responsible_gambling
                      - custom
                    max_uses: 1000
                    bind_to_origin: https://app.example.com
                    vendor_data: user-42
        '400':
          description: Le corps contenait un champ. Envoyez un objet vide.
          headers:
            Cache-Control:
              description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
              schema:
                type: string
                example: no-store
            Pragma:
              description: Toujours `no-cache`.
              schema:
                type: string
                example: no-cache
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FieldErrors'
              examples:
                UnknownField:
                  summary: Un champ dans le corps
                  value:
                    vendor_data: unknown_field
        '401':
          $ref: '#/components/responses/InvalidToken'
        '403':
          $ref: '#/components/responses/OriginNotAllowed'
        '404':
          $ref: '#/components/responses/ApplicationNotFound'
        '409':
          description: >-
            La surveillance des événements est désactivée pour l'application.
            Activez l'ingestion d'événements dans les paramètres de surveillance
            des transactions.
          headers:
            Cache-Control:
              description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
              schema:
                type: string
                example: no-store
            Pragma:
              description: Toujours `no-cache`.
              schema:
                type: string
                example: no-cache
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthError'
              examples:
                MonitoringDisabled:
                  summary: Ingestion d'événements désactivée
                  value:
                    error: monitoring_disabled
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          description: >-
            Les tokens de surveillance ne sont pas activés, ou la surveillance
            n'a pas pu en émettre un (`monitoring_unavailable`), ou un service
            dont dépend la requête est temporairement indisponible
            (`temporarily_unavailable`). Réessayez plus tard.
          headers:
            Cache-Control:
              description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
              schema:
                type: string
                example: no-store
            Pragma:
              description: Toujours `no-cache`.
              schema:
                type: string
                example: no-cache
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthError'
              examples:
                MonitoringUnavailable:
                  summary: Indisponible
                  value:
                    error: monitoring_unavailable
                TemporarilyUnavailable:
                  summary: Réessayer plus tard
                  value:
                    error: temporarily_unavailable
      security:
        - AccessToken: []
components:
  schemas:
    MonitoringTokenRequest:
      type: object
      description: 'Vide : le token d''accès identifie la personne.'
      additionalProperties: false
      properties: {}
    MonitoringToken:
      type: object
      description: >-
        Un identifiant d'authentification d'appareil à courte durée de vie pour
        envoyer les événements d'activité de la personne vers la surveillance
        des transactions depuis son appareil. Il n'est pas lié à la session : il
        reste utilisable jusqu'à `expires_at`, même après la déconnexion.
      required:
        - monitoring_token
        - expires_at
        - allowed_event_categories
        - max_uses
        - bind_to_origin
        - vendor_data
      properties:
        monitoring_token:
          type: string
          description: >-
            L'identifiant d'authentification de l'appareil. Traitez-le comme un
            secret.
          example: mt_2f8c1d9e7b6a5f4e3d2c1b0a
        expires_at:
          type: string
          format: date-time
          description: Au maximum 15 minutes après son émission.
          example: '2026-10-17T10:56:14Z'
        allowed_event_categories:
          type: array
          items:
            type: string
          description: >-
            Les catégories d'événements qu'il peut envoyer. Les événements
            d'authentification et de sécurité proviennent toujours de Didit,
            jamais de l'appareil.
          example:
            - session
            - gameplay
            - bonus
            - affiliate
            - payment
            - dispute
            - responsible_gambling
            - custom
        max_uses:
          type: integer
          example: 1000
        bind_to_origin:
          type: string
          nullable: true
          description: >-
            L'origine de navigateur depuis laquelle l'identifiant fonctionne :
            l'`Origin` de la requête, ou `null` lorsqu'il n'y en avait pas.
          example: https://app.example.com
        vendor_data:
          type: string
          description: >-
            La personne pour laquelle chaque événement est enregistré,
            indépendamment de ce que l'appareil envoie.
          example: user-42
    FieldErrors:
      title: Field errors
      type: object
      description: >-
        Erreurs de validation par champ. Une valeur est une liste de messages ou
        un code unique (`unknown_field`, `invalid_redirect_uri`).
        `non_field_errors` contient les règles transversales aux champs.
      additionalProperties:
        oneOf:
          - type: string
          - type: array
            items:
              type: string
    OAuthError:
      title: OAuth error
      type: object
      description: Une erreur OAuth (RFC 6749 section 5.2) ou une erreur de service.
      required:
        - error
      properties:
        error:
          type: string
          example: invalid_grant
    Detail:
      type: object
      required:
        - detail
      properties:
        detail:
          type: string
          example: invalid_token
  responses:
    InvalidToken:
      description: >-
        Le token d'accès est manquant, malformé, expiré, signé par un autre
        émetteur ou une autre clé, est un token d'ID, un token d'agent, ou a été
        remplacé par un rafraîchissement ; ou sa session a été révoquée, a
        expiré pour cause d'inactivité, a dépassé sa durée de vie ou ne respecte
        plus votre politique MFA, ou la personne a été bloquée ou son e-mail
        n'est plus vérifié. Renvoyez la personne vers la connexion.
      headers:
        WWW-Authenticate:
          description: '`Bearer`.'
          schema:
            type: string
            example: Bearer
        Cache-Control:
          description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Toujours `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Detail'
          examples:
            InvalidToken:
              summary: Token d'accès rejeté
              value:
                detail: invalid_token
    OriginNotAllowed:
      description: >-
        La requête contenait un `Origin` qui n'est ni celui de l'application ni
        dans ses origines autorisées. Les requêtes serveur n'envoient pas de
        `Origin`.
      headers:
        Cache-Control:
          description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Toujours `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Detail'
          examples:
            OriginNotAllowed:
              summary: Origine non autorisée
              value:
                detail: origin_not_allowed
    ApplicationNotFound:
      description: >-
        L'adresse appartient à une application, mais Authentication n'est pas
        actif pour celle-ci ; sur l'adresse `apx.didit.me`, l'identifiant de
        l'application est inconnu. Une adresse n'appartenant à aucune
        application est refusée avant d'atteindre l'endpoint, et cette réponse
        n'est pas en JSON.
      headers:
        Cache-Control:
          description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Toujours `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Detail'
          examples:
            ApplicationNotFound:
              summary: Application inconnue
              value:
                detail: No Configuration matches the given query.
    RateLimited:
      description: >-
        Trop de requêtes issues de cette adresse IP pour cet endpoint, ou, sur
        un `POST` ou `DELETE`, un compartiment de protection contre les robots
        est vide. Rien n'a été exécuté : attendez `Retry-After` secondes, puis
        réessayez.
      headers:
        Retry-After:
          description: Secondes à attendre avant de réessayer.
          schema:
            type: integer
            example: 60
        Cache-Control:
          description: 'Toujours `no-store` : ne jamais mettre cette réponse en cache.'
          schema:
            type: string
            example: no-store
        Pragma:
          description: Toujours `no-cache`.
          schema:
            type: string
            example: no-cache
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Detail'
          examples:
            RateLimited:
              summary: Limite du endpoint
              value:
                detail: >-
                  Too many requests from this IP address. Please wait before
                  trying again. Expected available in 60 seconds.
            BotProtection:
              summary: Limite de protection contre les bots (POST et DELETE)
              value:
                detail: rate_limited Expected available in 2 seconds.
  securitySchemes:
    AccessToken:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Le token d'accès de la personne issu de `POST /token/` : un JWT ES256
        avec l'en-tête `typ: at+jwt`, valide pendant au plus 5 minutes. Il ne
        s'agit pas de votre clé API Didit.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.