{"openapi":"3.0.3","info":{"title":"SixForge API","description":"API de la plateforme communautaire GTA 6 — assets, lore, serveurs, monétisation, analytics, abonnements.","version":"0.1.0"},"components":{"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"sf_access"},"serverApiKey":{"type":"apiKey","in":"header","name":"x-api-key"}},"schemas":{}},"paths":{"/api/health":{"get":{"summary":"Healthcheck","tags":["system"],"responses":{"200":{"description":"Default Response"}}}},"/api/auth/register":{"post":{"summary":"Crée un compte utilisateur","tags":["auth"],"responses":{"200":{"description":"Default Response"}}}},"/api/auth/login":{"post":{"summary":"Authentifie un utilisateur et pose les cookies JWT","tags":["auth"],"responses":{"200":{"description":"Default Response"}}}},"/api/auth/refresh":{"post":{"summary":"Rotation de la paire de tokens à partir du cookie sf_refresh","tags":["auth"],"responses":{"200":{"description":"Default Response"}}}},"/api/auth/me":{"get":{"summary":"Retourne l'utilisateur courant","tags":["auth"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/auth/verify-email":{"post":{"summary":"Confirme une adresse email à partir du jeton reçu par lien","tags":["auth"],"description":"Non authentifié : le lien est ouvert depuis la boîte mail, souvent sur un autre appareil que celui où la session est ouverte. Le jeton est à usage unique et expire après 48 h.","responses":{"200":{"description":"Default Response"}}}},"/api/auth/verify-email/resend":{"post":{"summary":"Réémet le lien de vérification d'adresse du compte courant","tags":["auth"],"description":"Répond `{ sent: false }` sans erreur si l'adresse est déjà vérifiée.","security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/auth/password/forgot":{"post":{"summary":"Demande un lien de réinitialisation de mot de passe","tags":["auth"],"description":"Répond toujours 202 avec le même corps, que l'adresse existe ou non — une réponse différenciée ferait de cette route un oracle d'énumération de comptes.","responses":{"200":{"description":"Default Response"}}}},"/api/auth/password/reset":{"post":{"summary":"Pose un nouveau mot de passe à partir du jeton reçu par lien","tags":["auth"],"description":"Jeton à usage unique, valable 30 minutes. Révoque **toutes** les sessions du compte et détruit les cookies de la requête.","responses":{"200":{"description":"Default Response"}}}},"/api/auth/logout":{"post":{"summary":"Révoque la session et détruit les cookies d'authentification","tags":["auth"],"responses":{"200":{"description":"Default Response"}}}},"/api/assets/":{"get":{"summary":"Liste les assets du hub","tags":["assets"],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Publie un nouvel asset (créateur)","tags":["assets"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/assets/{id}":{"get":{"summary":"Détail d'un asset","tags":["assets"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/assets/{id}/purchase":{"post":{"summary":"Achète un asset (débit CR, reversement créateur)","tags":["assets"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/assets/{id}/download":{"get":{"summary":"URL de téléchargement (créateur, acheteur ou asset gratuit)","tags":["assets"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/lore/":{"get":{"summary":"Liste les entrées (tri score)","tags":["lore"],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Crée une entrée de lore","tags":["lore"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/lore/{id}":{"get":{"summary":"Détail (Markdown rendu et sanitizé)","tags":["lore"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/lore/{id}/vote":{"post":{"summary":"Vote +1 / -1","tags":["lore"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/":{"get":{"summary":"Liste les serveurs RP","tags":["servers"],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Déclare un serveur RP (le demandeur devient propriétaire)","tags":["servers"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/mine":{"get":{"summary":"Serveurs administrés par le demandeur (tous pour un GLOBAL_ADMIN)","tags":["servers"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/{id}":{"get":{"summary":"Détail d'un serveur RP","tags":["servers"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Met à jour un serveur RP (propriétaire uniquement)","tags":["servers"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/{id}/status":{"get":{"summary":"État courant (métriques réelles si heartbeat récent, sinon null)","tags":["servers"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/{id}/heartbeat":{"post":{"summary":"Télémétrie poussée par le serveur de jeu (x-api-key)","tags":["servers"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/{id}/api-key":{"post":{"summary":"(Re)génère la clé API du serveur — affichée une seule fois","tags":["servers"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/ranking":{"get":{"summary":"Classement des serveurs par votes, mois en cours","tags":["votes"],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/{id}/votes":{"get":{"summary":"Votes du mois et rang d'un serveur (+ état de vote du visiteur connecté)","tags":["votes"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Vote pour un serveur (1 par compte et par serveur toutes les 24 h)","tags":["votes"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/servers/{id}/votes/claim":{"post":{"summary":"Réclame les récompenses de vote d'un joueur (serveur de jeu, x-api-key)","tags":["votes"],"description":"Corps : { discordId } ou { rockstarLicense }. Renvoie le nombre de votes non encore récompensés, marqués récompensés dans la même opération : à distribuer en jeu.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/shop/products":{"get":{"summary":"Catalogue produits","tags":["shop"],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Crée un produit (propriétaire du serveur)","tags":["shop"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/shop/products/{id}":{"get":{"summary":"Détail d'un produit","tags":["shop"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Met à jour un produit (propriétaire du serveur)","tags":["shop"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Supprime un produit (propriétaire du serveur)","tags":["shop"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/shop/checkout":{"post":{"summary":"Achète un panier (débit CR instantané)","tags":["shop"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/shop/orders/{id}":{"get":{"summary":"Statut d'une commande","tags":["shop"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/analytics/me":{"get":{"summary":"Statistiques créateur du compte connecté (données réelles)","tags":["analytics"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/subscriptions/":{"post":{"summary":"Souscrire à un palier pour un serveur RP","tags":["subscriptions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["serverId","tier"],"properties":{"serverId":{"type":"string"},"tier":{"type":"string","enum":["bronze","silver","gold","platinum"]}}}}}},"security":[{"cookieAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","additionalProperties":true}}}}}}}}},"/api/subscriptions/me":{"get":{"summary":"Liste mes abonnements","tags":["subscriptions"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/subscriptions/tiers":{"get":{"summary":"Tarifs publics des paliers","tags":["subscriptions"],"responses":{"200":{"description":"Default Response"}}}},"/api/subscriptions/server/{serverId}":{"get":{"summary":"Abonnements d'un serveur","tags":["subscriptions"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"serverId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/subscriptions/whitelist/request":{"post":{"summary":"Demande de whitelist (utilisateur)","tags":["whitelist"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["serverId","discordId","rockstarLicense"],"properties":{"serverId":{"type":"string"},"discordId":{"type":"string"},"rockstarLicense":{"type":"string"},"reason":{"type":"string"}}}}}},"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/subscriptions/whitelist/{id}/decide":{"patch":{"summary":"Décide d'une demande de whitelist","tags":["whitelist"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["pending","approved","revoked"]},"reason":{"type":"string"}}}}}},"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/subscriptions/whitelist/server/{serverId}":{"get":{"summary":"Liste des whitelists d'un serveur","tags":["whitelist"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"serverId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/subscriptions/whitelist/verify":{"get":{"summary":"Vérifie qu'un joueur est whitelisté (auth machine)","tags":["whitelist"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"serverId","required":true},{"schema":{"type":"string"},"in":"query","name":"discordId","required":false},{"schema":{"type":"string"},"in":"query","name":"rockstarLicense","required":false}],"security":[{"serverApiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"whitelisted":{"type":"boolean"},"status":{"type":"string","nullable":true},"subscriptionActive":{"type":"boolean"}}}}}}}}},"/api/admin/stats":{"get":{"summary":"Statistiques globales du site + état économique","tags":["admin"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"days","required":false,"description":"Fenêtre en jours (1-365, défaut 30)"}],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/revenue-timeseries":{"get":{"summary":"Série journalière des revenus (CR + €)","tags":["admin"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"days","required":false,"description":"Fenêtre en jours (1-365, défaut 30)"}],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/users":{"get":{"summary":"Recherche d'utilisateurs (email/username, rôle, statut)","tags":["admin"],"description":"Les comptes anonymisés restent listés : rien n'est supprimé de la base, seule l'identité est neutralisée.","parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Filtre email/username (insensible à la casse)"},{"schema":{"type":"string"},"in":"query","name":"role","required":false,"description":"Filtre sur le rôle"},{"schema":{"type":"string"},"in":"query","name":"status","required":false,"description":"Filtre sur le statut de compte"},{"schema":{"type":"string"},"in":"query","name":"limit","required":false,"description":"Nombre max de résultats (1-100, défaut 50)"}],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/users/{id}":{"get":{"summary":"Fiche détaillée d'un compte (engagements + volumétrie)","tags":["admin"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/users/{id}/history":{"get":{"summary":"Historique d'audit d'un compte","tags":["admin"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/users/{id}/role":{"patch":{"summary":"Change le rôle d'un utilisateur (promotion CREATOR / SERVER_ADMIN…)","tags":["admin"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/users/{id}/suspend":{"post":{"summary":"Suspend un compte (mesure réversible)","tags":["admin"],"description":"Motif obligatoire. Révoque immédiatement les sessions en cours. `until` absent vaut suspension sans terme, levée à la main.","security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Lève la suspension d'un compte","tags":["admin"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/users/{id}/deletion":{"get":{"summary":"État de la demande de suppression et engagements bloquants","tags":["admin"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/users/{id}/anonymize":{"post":{"summary":"Anonymise un compte (équivalent RGPD d'une suppression)","tags":["admin"],"description":"Irréversible. Aucune donnée n'est détruite : les pièces comptables (grand livre CR, commandes, achats, versements) sont conservées — obligation légale — mais plus rien ne les rattache à une personne. La fiche reste consultable dans la console après l'opération. Exige un motif et la confirmation littérale « ANONYMISER ».","security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/content":{"get":{"summary":"File de modération (assets + lore)","tags":["admin"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"type","required":false,"description":"asset | lore"},{"schema":{"type":"string"},"in":"query","name":"status","required":false,"description":"visible | hidden | removed"},{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Filtre sur le titre"},{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"pageSize","required":false}],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/content/{type}/{id}":{"get":{"summary":"Consultation d'un contenu, y compris retiré, avec son historique","tags":["admin"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"type","required":true},{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Masque, retire ou rétablit un contenu","tags":["admin"],"description":"Aucune suppression physique : le contenu change de statut et sort des listes publiques, tout en restant consultable ici. Motif obligatoire dès qu'on sort de `visible`.","security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"type","required":true},{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/refunds/purchases":{"get":{"summary":"Achats appelant une décision de remboursement","tags":["admin"],"description":"`scope=actionable` (défaut) liste les encaissements sans contrepartie livrée : `refund_due`, `amount_mismatch`, `paid_uncredited`. `scope=all` y ajoute les achats normalement crédités.","parameters":[{"schema":{"type":"string"},"in":"query","name":"scope","required":false,"description":"actionable | all"},{"schema":{"type":"string"},"in":"query","name":"userId","required":false},{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"pageSize","required":false}],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/refunds/purchases/{id}":{"get":{"summary":"Historique des remboursements d'un achat","tags":["admin"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Rembourse un achat de crédits (vrais euros)","tags":["admin"],"description":"Restitue les euros sur le moyen de paiement d'origine et reprend les crédits correspondants, sans jamais pousser le solde en négatif. `amountCents` absent vaut remboursement du reliquat. Exige la confirmation littérale « REMBOURSER ».","security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/refunds/{refundId}/retry":{"post":{"summary":"Relance une tentative de remboursement en échec","tags":["admin"],"description":"Réutilise la clé d'idempotence de la tentative d'origine — c'est la seule façon de réessayer sans risquer un second virement réel.","security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"refundId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/features":{"get":{"summary":"État d'activation des fonctions (assets, lore, serveurs, shop, analytics)","tags":["admin"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Active ou désactive une fonction de la plateforme","tags":["admin"],"description":"Mise à jour partielle : n'envoyer que les fonctions à basculer, pour ne pas écraser une bascule concurrente. Une fonction désactivée garde ses liens dans la navigation et sert une page d'indisponibilité — elle n'est pas retirée du site. La bascule est consignée au journal d'audit.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"assets":{"type":"boolean"},"lore":{"type":"boolean"},"servers":{"type":"boolean"},"shop":{"type":"boolean"},"analytics":{"type":"boolean"}}}}}},"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/admin/audit":{"get":{"summary":"Journal d'audit des actions d'administration","tags":["admin"],"description":"Append-only : aucune route ne permet de le modifier ni de le purger.","parameters":[{"schema":{"type":"string"},"in":"query","name":"action","required":false},{"schema":{"type":"string"},"in":"query","name":"targetType","required":false,"description":"user | asset | lore | purchase"},{"schema":{"type":"string"},"in":"query","name":"targetId","required":false},{"schema":{"type":"string"},"in":"query","name":"actorId","required":false},{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"pageSize","required":false}],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/config":{"get":{"summary":"Config économique effective (taux, frais, seuils)","tags":["wallet"],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/me":{"get":{"summary":"Solde et historique des mouvements","tags":["wallet"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/buy":{"post":{"summary":"Acheter des crédits (€ → CR)","tags":["wallet"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["eurAmount"],"properties":{"eurAmount":{"type":"number"}}}}}},"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/withdraw":{"post":{"summary":"Demander un retrait créateur (CR → €)","tags":["wallet"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["credits"],"properties":{"credits":{"type":"number"}}}}}},"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/payouts":{"get":{"summary":"Historique des versements","tags":["wallet"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/connect/status":{"get":{"summary":"État du compte de versement (virements autorisés ou non)","tags":["wallet"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/connect/onboard":{"post":{"summary":"Démarre (ou reprend) l'onboarding du compte de versement","tags":["wallet"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/wallet/webhook/stripe":{"post":{"summary":"Webhook Stripe (signature vérifiée sur le corps brut)","tags":["wallet"],"responses":{"200":{"description":"Default Response"}}}},"/api/users/me/creator":{"post":{"summary":"Active le statut créateur du compte courant (USER → CREATOR)","tags":["users"],"description":"Idempotent. Ouvre la publication d'assets, la déclaration de serveur, la boutique et le retrait de CR. Rejouer POST /api/auth/refresh ensuite pour que le nouveau rôle soit porté par l'access token.","security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/users/me":{"patch":{"summary":"Met à jour le profil public (pseudo, avatar, Discord, licence Rockstar)","tags":["users"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/users/me/password":{"post":{"summary":"Change le mot de passe et révoque les autres sessions","tags":["users"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/users/me/notifications":{"patch":{"summary":"Met à jour les préférences de notification par email","tags":["users"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/users/me/sessions":{"get":{"summary":"Liste les sessions actives (un appareil connecté par session)","tags":["users"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/users/me/sessions/revoke-others":{"post":{"summary":"Déconnecte tous les autres appareils","tags":["users"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/users/me/deletion":{"get":{"summary":"État de la demande de suppression et engagements bloquants","tags":["users"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Demande la suppression du compte (délai de grâce de 30 jours)","tags":["users"],"description":"Refusée tant qu'un engagement reste ouvert : solde CR non nul, versement ou achat en cours, abonnés actifs sur un serveur possédé. La suppression est une anonymisation : les pièces comptables sont conservées sans identité.","security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Annule une demande de suppression encore dans son délai de grâce","tags":["users"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/transfers/":{"post":{"summary":"Propose le transfert d'une ressource possédée","tags":["transfers"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/transfers/incoming":{"get":{"summary":"Offres de transfert reçues et encore valides","tags":["transfers"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/transfers/outgoing":{"get":{"summary":"Offres de transfert émises et encore en attente","tags":["transfers"],"security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/transfers/{id}/accept":{"post":{"summary":"Accepte une offre (la propriété change de main)","tags":["transfers"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/transfers/{id}/decline":{"post":{"summary":"Refuse une offre reçue","tags":["transfers"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/transfers/{id}":{"delete":{"summary":"Annule une offre émise","tags":["transfers"],"security":[{"cookieAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/contact/":{"post":{"summary":"Envoie un message à l'équipe SixForge","tags":["contact"],"description":"Le mail part du domaine SixForge avec `reply-to` positionné sur l'expéditeur, et un accusé de réception lui est adressé. Répond 503 si l'acheminement échoue — jamais un succès de façade.","responses":{"200":{"description":"Default Response"}}}},"/api/settings/features":{"get":{"summary":"État d'activation des fonctions de la plateforme","tags":["system"],"responses":{"200":{"description":"Default Response"}}}}},"servers":[{"url":"/","description":"Serveur courant"}],"tags":[{"name":"auth","description":"Authentification"},{"name":"users","description":"Utilisateurs"},{"name":"assets","description":"Hub d'assets multimédias"},{"name":"lore","description":"Moteur de lore & storytelling"},{"name":"servers","description":"Dashboard serveurs RP"},{"name":"shop","description":"Boutique & monétisation"},{"name":"analytics","description":"Analytics streamers"},{"name":"subscriptions","description":"Abonnements & paliers"},{"name":"whitelist","description":"Vérification & gestion des whitelists"},{"name":"transfers","description":"Transfert de propriété (serveurs, assets)"},{"name":"contact","description":"Formulaire de contact"}]}