Pro Account And Structure For Front¶
Ce document décrit comment le front doit consommer les APIs backend pour le
début du parcours pro.
Périmètre de cette première partie :
- choix du type de compte ;
- création d'un compte
pro; - inscription en waitlist pour un futur compte
pro; - état initial d'un compte
prosans structure ; - création d'une structure ;
- revendication d'une structure catalogue existante ;
- rattachement à une structure déjà gérée ;
- lecture du contexte pro courant ;
- lecture des capabilities et quotas de structure ;
- création et gestion d'un event
pro.
Les exemples ci-dessous utilisent les préfixes :
- public :
/v1/public - privé web :
/v1/web/api
Les mêmes routes privées existent aussi sous /v1/mobile/api et /v1/dev/api.
Principes importants pour le front¶
Avant d'implémenter les écrans, il faut garder en tête ces contraintes du backend actuel :
- le choix
individualvsprose fait viaaccountType, au signup direct ou à l'inscription waitlist ; - un compte
propeut exister sans structure ; - créer une structure et revendiquer une structure existante sont deux flows différents ;
- ces deux flows sont asynchrones :
- ils passent par une modération / approbation ;
- ils ne donnent pas immédiatement un ownership actif sur une structure
valid; GET /me/subscriptiondécrit la souscription de laPerson, pas les entitlements de structure ;- le backend expose désormais des endpoints self dédiés pour :
- lister "mes structures gérées" ;
- lire les capabilities et quotas effectifs d'une structure.
Conséquence front :
- le front peut implémenter correctement les étapes
1à5avec les APIs existantes ; - l'étape
6reste partiellement couverte car il n'existe toujours pas de flow self-service pour rejoindre une structure déjà gérée ; - les étapes
7et8disposent maintenant d'endpoints canoniques.
Étape 1 - Choisir le type de compte à la création¶
Objectif¶
Faire diverger le parcours individual et pro avant le signup.
Ce que le front doit faire¶
- afficher un choix explicite entre
individualetpro; - mémoriser ce choix jusqu'à l'appel de signup ;
- ne pas essayer de convertir un compte après coup : ce n'est pas supporté en V1.
API à appeler¶
Aucune.
Le choix est porté dans le payload de signup.
Sortie attendue¶
Le front sait s'il doit appeler POST /v1/public/accounts avec :
accountType=individual- ou
accountType=pro
Étape 2 - Créer un compte pro¶
Objectif¶
Créer un compte authentifiable de type pro.
Endpoint¶
POST /v1/public/accounts
Payload¶
{
"pseudo": "club-alpha",
"email": "contact@club-alpha.test",
"accountType": "pro",
"challengeToken": "token"
}
Réponse de succès¶
201 Created
{
"id": 123,
"pseudo": "club-alpha",
"accountType": "pro"
}
Réponses à gérer¶
400si payload invalide, pseudo invalide, email invalide ou conflit pseudo / email ;403aveccode = "invalid_challenge"si le challenge antibot est invalide, manquant ou expiré ;503aveccode = "challenge_unavailable"si la vérification antibot est indisponible ;500si le backend ne peut pas finaliser le signup pour une autre raison.
Comportement UI attendu¶
- en cas de succès, considérer le compte comme créé mais pas encore activé ;
- afficher la suite du flow d'activation générique du produit ;
- ne pas attendre qu'une structure soit créée automatiquement ;
- ne pas déduire de contexte structure à ce stade.
Point produit important¶
Le signup pro :
- crée bien une
Personde typepro; - attribue aussi le rôle
ROLE_PRO; - attribue une souscription par défaut au niveau
Person.
Cette souscription Person ne doit pas être utilisée pour déduire les droits
pro d'une structure future.
Étape 2 bis - Inscrire un futur compte pro en waitlist¶
Objectif¶
Permettre à un utilisateur qui vise un compte pro d'entrer dans la waitlist
globale sans perdre cette intention.
Endpoint¶
POST /v1/public/waitlist-entries
Payload¶
{
"email": "contact@club-alpha.test",
"accountType": "pro",
"cityId": 12,
"sportIds": [1, 2],
"challengeToken": "token"
}
Règle contractuelle¶
accountType est obligatoire et doit valoir individual ou pro.
Le backend ne remplace pas un champ absent par individual. Un payload waitlist
sans accountType explicite est invalide.
Effet au signup depuis invitation waitlist¶
Quand l'utilisateur finalise son inscription via une invitation waitlist, le
backend crée le compte avec le accountType porté par l'entrée waitlist.
Le front ne doit donc pas demander ni envoyer accountType dans le payload de
signup depuis invitation waitlist; il doit seulement envoyer le token, le pseudo
et le challenge.
Étape 3 - Comprendre l'état initial d'un compte pro sans structure¶
Objectif¶
Savoir quoi afficher juste après création / activation d'un compte pro.
Endpoints utiles¶
GET /v1/web/api/meGET /v1/web/api/me/subscription
Ce que renvoie GET /me¶
Le payload expose notamment :
userIdpersonIdaccountTypeprofileStatuspseudoroles
Pour un compte pro, le front doit s'attendre à :
accountType = "pro"rolescontenantROLE_USERetROLE_PRO
Ce que renvoie GET /me/subscription¶
Le payload décrit :
- le plan courant de la
Person; - les
rights; - les
organizerCapabilities; - les
capabilities; - les
quotas; - les
quotaUsage.
Ce que le front doit en conclure¶
Après signup pro, l'utilisateur peut être :
pro;- authentifié ;
- sans aucune structure gérée.
Le front doit donc prévoir un écran ou état vide de type :
- "Créer une structure"
- "Revendiquer une structure existante"
Important¶
GET /me/subscription ne décrit pas les capabilities / quotas d'une structure.
Le front ne doit pas utiliser cette réponse pour décider si l'utilisateur peut :
- créer un event pro ;
- créer une proposal pro ;
- inviter des adhérents ;
- configurer la solidarité d'un event pro ;
- utiliser les scopes d'audience avancés.
Ces décisions dépendent du plan effectif de la structure, pas du compte seul.
Étape 4 - Créer une nouvelle structure¶
Objectif¶
Permettre à un compte pro de créer une structure qui entrera ensuite dans un
cycle de modération / approbation.
Endpoint¶
POST /v1/web/api/structures
Préconditions¶
- utilisateur authentifié ;
- rôle
ROLE_PRO.
Payload¶
{
"active": true,
"type": "associative",
"name": "Club Alpha",
"description": "Club de test",
"address": "10 rue du Test",
"email": "contact@club-alpha.test",
"phoneNumber": "0102030405",
"cityId": 12,
"avatarId": 44,
"sportsIds": [3, 7]
}
Réponse de succès¶
201 Created
Le backend renvoie uniquement l'identifiant créé :
{
"id": 123
}
Sémantique métier importante¶
Le backend crée :
- la structure ;
- un plan par défaut au niveau structure ;
- une
StructureClaimRequestde typecreateen statutpending.
En revanche, il ne crée pas immédiatement un ownership actif.
La structure créée sort donc en pratique dans un état de type :
reviewStatus = "pending_moderation"
Comportement UI attendu¶
Après succès :
- stocker
structureId; - si l'écran courant a besoin de la fiche complète, relire
GET /structures/{idStructure}; - si l'écran courant est une liste paginée / filtrée / triée côté serveur, relancer la requête canonique de liste plutôt que d'injecter localement un item ;
- afficher clairement que la structure est en attente de validation ;
- ne pas présenter la structure comme déjà "validée et pleinement gérée".
Si la vue courante est le feed public GET /structures, la structure créée n'a
en pratique pas vocation à y apparaître tant qu'elle reste en
pending_moderation.
Point subtil mais utile au front¶
Même en attente de modération, le créateur peut relire et éditer sa structure via les APIs de structure tant que le backend reconnaît sa demande de création en cours.
Le front peut donc enchaîner sur :
GET /structures/{idStructure}PATCH /structures/{idStructure}
mais doit garder l'état "pending moderation" visible.
Étape 5 - Revendiquer une structure catalogue existante¶
Objectif¶
Permettre à un compte pro de demander la gestion d'une structure déjà présente
dans le catalogue.
Séquence front recommandée¶
- rechercher une structure existante ;
- ouvrir sa fiche ;
- si l'utilisateur veut la gérer, créer une demande de revendication.
Endpoints utiles¶
GET /v1/web/api/structuresGET /v1/web/api/structures/{idStructure}POST /v1/web/api/structures/{idStructure}/claim
Recherche de structure¶
GET /structures renvoie un StructureFeedResponse :
itemsnextCursor
Chaque item expose notamment :
idtypenamedescriptionprimarySporttotalSportsactiveAdherentsCountcityavatarhasFacilitiesviewerRelationsi l'utilisateur connecté a une relation avec la structure
Valeurs possibles pour viewerRelation :
ownermanageradherent
Filtres utiles :
qsports[]types[]citydistanceitemsPerPagecursor
Création de la revendication¶
POST /structures/{idStructure}/claim ne prend pas de body.
Réponse de succès¶
201 Created
Le backend renvoie un StructureClaimRequestDTO avec notamment :
idstructureIdstructureNamerequestedByPersonIdrequestTypestatuscreatedAt
Le front doit s'attendre à :
requestType = "claim_existing"status = "pending"
Réponses métier à gérer¶
404si la structure n'existe pas ou n'est pas revendicable ;400si une revendication est déjà en cours ;400si la structure est déjà gérée ;403si l'acteur n'est pas un comptepro.
Comportement UI attendu¶
Après succès :
- afficher un état "demande envoyée" ;
- bloquer le bouton de revendication immédiat ;
- ne pas considérer l'utilisateur comme déjà gestionnaire ;
- ne pas afficher les écrans de gestion structure comme disponibles.
Étape 6 - Rejoindre une structure déjà gérée¶
Objectif¶
Couvrir le cas où un compte pro est rattaché à une structure déjà gérée par un
autre owner / gestionnaire.
État actuel du backend¶
Le modèle backend supporte bien :
StructureMembership- un owner ;
- des permissions déléguées
Mais il n'existe pas aujourd'hui d'endpoint front self dédié pour :
- inviter un compte
prodans une structure ; - accepter cette invitation ;
- lister les memberships du compte connecté.
Conséquence front¶
Cette étape ne peut pas être implémentée proprement en self-service avec les APIs actuelles.
Le front doit donc la considérer comme :
- un état métier existant ;
- mais sans flow utilisateur canonique exposé aujourd'hui.
Ce qu'il faut documenter côté front¶
Si ce cas apparaît plus tard dans le produit, il faudra ajouter au minimum des endpoints pour :
- lister les structures gérées par l'utilisateur ;
- lister les permissions portées par chaque membership ;
- inviter / rattacher un compte
proà une structure ; - accepter ou refuser ce rattachement.
Étape 7 - Lire le contexte pro courant¶
Objectif¶
Savoir dans quelle structure l'utilisateur agit et quelles fiches structure il peut ouvrir pour travailler.
Endpoints à utiliser¶
GET /v1/web/api/meGET /v1/web/api/me/structuresGET /v1/web/api/structures/{idStructure}GET /v1/web/api/structures/{idStructure}/entitlements
Ce que ces endpoints permettent réellement¶
GET /me permet de savoir :
- qui est connecté ;
- que le compte est de type
pro; - quels rôles globaux il porte.
GET /me/structures permet de lister le contexte structure exploitable du
compte connecté.
Chaque item expose notamment :
structureIdnamereviewStatustypeactivecityavatarprimarySportactiveAdherentsCountaccess
Le bloc access expose notamment :
kindisOwnermembershipStatuspermissionsclaimRequestIdclaimRequestTypeclaimRequestStatusreviewNote
Les valeurs utiles de access.kind sont :
owner_membershipmanager_membershippending_create_claimrejected_create_claimpending_claim_existingrejected_claim_existing
GET /structures/{idStructure} permet de relire :
- une structure publique
valid; - ou une structure non publique si l'acteur y a déjà accès.
Quand le viewer connecté a déjà un contexte sur la structure, la réponse peut aussi exposer :
accessactions
Le bloc access reste aligné avec GET /me/structures.
Le bloc actions reste aligné avec GET /structures/{idStructure}/entitlements
mais sans les détails de plan / quotas / usages.
GET /structures/{idStructure}/entitlements permet de lire, pour une structure
donnée :
- le type d'accès courant ;
- le plan effectif ;
- les capabilities ;
- les quotas ;
- le quota usage ;
- les
actionsfront-friendly.
Séquence front recommandée¶
- appeler
GET /mepour identifier le compte connecté ; - appeler
GET /me/structurespour construire le sélecteur ou la landing pro ; - choisir une structure à partir de la liste ;
- relire si nécessaire la fiche complète avec
GET /structures/{idStructure}; - appeler
GET /structures/{idStructure}/entitlementspour piloter les écrans d'action.
Ce que le front doit en conclure¶
- le cold start pro est désormais reconstructible proprement ;
- le front ne doit plus dépendre uniquement d'un
structureIdconservé dans son state local ; - le bloc
accessdeGET /me/structuresest la source de vérité pour comprendre si l'utilisateur est owner, manager, créateur en attente de modération, ou simple revendication en attente ; GET /structures/{idStructure}reste utile pour la fiche structure et peut maintenant porter le contexte viewer courant (access,actions) ;GET /structures/{idStructure}/entitlementsreste la source de vérité pour piloter les actions métier.
Étape 8 - Lire les capabilities et quotas de la structure¶
Objectif¶
Décider côté UI si une action pro doit être :
- visible ;
- masquée ;
- désactivée ;
- ou laissée tentable puis gérée via erreur métier backend.
Endpoint à utiliser¶
GET /v1/web/api/structures/{idStructure}/entitlements
Ce que renvoie cet endpoint¶
Le payload expose notamment :
structureIdstructureNamereviewStatusaccessplancapabilitiesquotasquotaUsageactions
Le bloc plan expose :
codenameactiveisDefaultperiodStartperiodEnd
Le bloc actions expose notamment :
canManageProfilecanManageMediacanManageActivitiescanManageFacilitiescanCreateEventscanManageAdherentscanInviteAdherentsWithoutWaitlistcanCreateEventProposalscanUseAdvancedAudiencecanConfigureEventSolidaritycanAllowExternalHelpers
Règles d'interprétation importantes¶
capabilitiesetquotasdécrivent le plan effectif de la structure ;quotaUsagedécrit l'usage courant de la période active ;actionsest la projection backend canonique pour piloter l'UI ;GET /me/subscriptionreste limité aux entitlements de laPerson.
Règle utile :
canInviteAdherentsWithoutWaitlistimplique aussi la gestion adhérents ;- autrement dit, une structure ne doit pouvoir bypass la waitlist que si elle peut déjà gérer son roster d'adhérents.
Cas subtil important¶
Une structure créée par le compte mais encore en attente de modération peut
ressortir dans GET /structures/{idStructure}/entitlements avec :
- des droits d'édition de structure ;
- mais sans droit de création d'event, de proposal, ni de gestion adhérents.
Le front doit donc utiliser actions, et non déduire seul les possibilités à
partir du simple fait que l'utilisateur "voit" la structure.
Stratégie front recommandée¶
- utiliser
GET /me/structurespour choisir la structure courante ; - utiliser
GET /structures/{idStructure}/entitlementspour afficher ou masquer les actions ; - conserver les erreurs métier des endpoints d'action comme filet de sécurité ;
- ne pas réutiliser
GET /me/subscriptionpour piloter une UI structure.
Étape 9 - Créer un event pro¶
Objectif¶
Créer un event rattaché à une structure gérée par le compte pro.
Endpoints à utiliser¶
GET /v1/web/api/me/structuresGET /v1/web/api/structures/{idStructure}/entitlementsPOST /v1/web/api/events
Préconditions¶
- utilisateur authentifié ;
- profil
valid; - compte de type
pro; - structure courante choisie ;
actions.canCreateEvents = truesurGET /structures/{idStructure}/entitlements.
Payload¶
{
"title": "Tournoi Alpha",
"description": "Session de test",
"address": "10 rue du Test",
"organizerStructureId": 12,
"venueStructureId": 34,
"creatorParticipates": true,
"audienceScope": "everyone",
"level": 3,
"startAt": "2026-04-20T18:00:00Z",
"endAt": "2026-04-20T20:00:00Z",
"minSeats": 8,
"maxSeats": 16,
"waitlistCapacity": 4,
"sportId": 7,
"cityId": 44,
"avatarId": 91,
"solidarity": {
"enabled": false
}
}
Règles métier importantes¶
- pour un compte
pro,organizerStructureIdest obligatoire ; venueStructureIdest optionnel ;audienceScopevauteveryonepar défaut ;- un
audienceScopedifférent deeveryonen'est autorisé que si la structure dispose de la capability d'audience avancée ; creatorParticipatesvauttruepar défaut ;- si
creatorParticipates=false, le créateur n'est pas inscrit comme participant et devientEventStaffMemberactif avec le titreOrganisateur; solidarityest optionnel ; son paramétrage détaillé sera documenté dans un bloc séparé.
Réponse de succès¶
201 Created
Le backend renvoie un Event complet, avec notamment :
idtitledescriptionaddressstartAtendAtminSeatsmaxSeatsconfirmedCountwaitlistCapacitywaitlistCountrecruitmentModeaudienceScopeorganizerStructureIdvenueStructureIdavatarsportcitycreatorparticipants
Réponses métier à gérer¶
400:- payload invalide ;
- date passée ;
endAt <= startAt;- incohérence
minSeats/maxSeats; waitlistCapacitytrop élevée ;audienceScopeinvalide ;levelinvalide ;403:- compte non
pro; - profil non validé ;
- structure non exploitable ;
- permission structure absente ;
- capability plan absente ;
- quota mensuel dépassé ;
404:- structure, ville, sport, avatar ou
venueStructureIdintrouvable.
Comportement UI attendu¶
- avant l'appel de création, choisir explicitement la structure courante ;
- idéalement, bloquer le CTA si
actions.canCreateEvents=false; - sur succès, naviguer vers la fiche détail de l'event ;
- conserver les erreurs backend comme source de vérité finale.
Point important pour le front¶
Le backend calcule recruitmentMode automatiquement :
publicsiaudienceScope=everyonerestrictedsinon
Le front ne doit pas essayer de l'envoyer lui-même.
Étape 10 - Lire et gérer un event pro existant¶
Objectif¶
Permettre au front de :
- afficher une fiche détail d'event pro ;
- éditer les champs autorisés ;
- changer l'avatar ;
- supprimer l'event.
Endpoints à utiliser¶
GET /v1/web/api/events/{idEvent}PATCH /v1/web/api/events/{idEvent}PATCH /v1/web/api/events/{idEvent}/avatarDELETE /v1/web/api/events/{idEvent}
Lecture détail¶
GET /events/{idEvent} renvoie un EventDetailDTO avec notamment :
idtitledescriptionaddressorganizerStructureIdvenueStructureIdlevelstartAtendAtminSeatsmaxSeatsconfirmedCountwaitlistCapacitywaitlistCountrecruitmentModeaudienceScopeavatarsportcitycreatorisRegisteredisCreatorparticipantssolidarity
Règle importante :
- si l'acteur n'a pas accès à l'event, le backend renvoie
404, pas un détail partiel.
Qui peut gérer un event pro¶
Pour un event structure-backed, un acteur peut gérer l'event s'il a sur la structure :
- un membership actif owner ;
- ou un membership actif avec la permission
create_structure_events.
Le front doit s'appuyer en pratique sur :
GET /structures/{idStructure}/entitlements- puis les réponses métier des endpoints d'action.
Mise à jour de l'event¶
PATCH /events/{idEvent} accepte uniquement les champs suivants :
titledescriptionaddressaudienceScopelevelstartAtendAtminSeatsmaxSeatswaitlistCapacitysportIdcityId
Champs non patchables via cet endpoint¶
Le front ne doit pas essayer de modifier ici :
organizerStructureIdvenueStructureIdcreatorParticipatesavatarId
Réponse de succès du patch¶
200 OK
Le backend renvoie un UpdateEventResponse :
eventparticipantsDelta
participantsDelta permet au front de comprendre l'effet d'un changement de
maxSeats :
promotedToMainmovedToWaiting
Règles métier importantes du patch¶
audienceScopen'est patchable que pour un eventpro;- un
audienceScopeavancé exige toujours la capability structure dédiée ; - un changement de
maxSeatspeut promouvoir ou rétrograder des participants ; - les validations de dates, places et
waitlistCapacityrestent actives à l'édition.
Mise à jour de l'avatar¶
PATCH /events/{idEvent}/avatar
Payload :
{
"avatarId": 92
}
Réponse de succès :
200 OK
{
"eventId": 123,
"avatarId": 92
}
Suppression¶
DELETE /events/{idEvent}
Réponse de succès :
204 No Content
Règle métier importante de suppression¶
Le backend désinscrit les participants actifs avant de supprimer l'event.
Le front peut donc considérer l'event comme définitivement indisponible après
succès du 204.
Ce qui n'est pas couvert dans ce bloc¶
La doc de cette étape ne détaille pas encore :
- les
audienceScopeun par un ; - les invitations d'accès à un event ;
- le
staffd'event ; - le paramétrage détaillé de la solidarité.
Étape 11 - Comprendre les audienceScope d'un event pro¶
Objectif¶
Permettre au front de :
- choisir le bon
audienceScopeà la création ou à l'édition ; - comprendre les règles de visibilité dans le feed ;
- comprendre les règles d'accès au détail et à l'inscription.
Valeurs supportées¶
everyoneinvite_onlymembers_onlymembers_and_invitees
Règles de création / édition¶
- pour un event
pro,audienceScopevauteveryonepar défaut ; - un
audienceScopedifférent deeveryoneexige la capability d'audience avancée côté structure ; - le front doit donc idéalement n'afficher ces options que si
actions.canUseAdvancedAudience=truesurGET /structures/{idStructure}/entitlements.
Sémantique d'accès¶
Pour un event pro, le backend calcule l'accès complet à partir de :
- la capacité à gérer l'event ;
- l'état
registered; - le statut
EventStaffMemberactif ; - l'adhésion active à la structure ;
- une invitation d'event active d'effet
access.
Règles par scope¶
everyone- accès complet pour tout utilisateur autorisé à consulter le feed ;
- inscription autorisée sans invitation d'accès ;
invite_only- accès complet si invitation active d'effet
access; - sinon, feed en mode signal et détail indisponible ;
members_only- accès complet si adhésion active à la structure organisatrice ;
- sinon, feed en mode signal et détail indisponible ;
members_and_invitees- accès complet si adhésion active ou invitation active d'effet
access; - sinon, feed en mode signal et détail indisponible.
Exceptions importantes¶
Quel que soit le audienceScope, le backend conserve un accès complet pour :
- les gestionnaires autorisés de l'event ;
- les participants inscrits ;
- les
EventStaffMemberactifs.
Conséquence feed / détail¶
Dans GET /events/feed :
- carte event complète si l'acteur a l'accès complet ;
- carte signal sinon.
Dans GET /events/{idEvent} :
200si l'acteur a l'accès complet ;404sinon.
Le front ne doit donc pas supposer qu'un item vu dans le feed donne toujours accès au détail complet.
Étape 12 - Gérer les invitations d'event¶
Objectif¶
Permettre à un gestionnaire d'event pro de :
- cibler des
individual; - leur ouvrir l'accès à un event restreint ;
- ou simplement les notifier.
Endpoints à utiliser¶
GET /v1/web/api/events/{idEvent}/invitationsPOST /v1/web/api/events/{idEvent}/invitationsDELETE /v1/web/api/events/{idEvent}/invitations/{idPerson}?effect={effect}POST /v1/web/api/events/{idEvent}/invitations/decline
Préconditions côté gestionnaire¶
- l'event doit être un event
pro; - l'acteur doit pouvoir gérer l'event.
Les invitations d'event ne sont pas supportées pour les events perso.
Effets supportés¶
accessnotify
Payload d'upsert¶
{
"personId": 456,
"effect": "access"
}
Réponse de succès¶
GET, POST et DELETE renvoient une liste de EventInvitationDTO :
ideffectstatusperson
Cible supportée¶
Le backend n'accepte que des comptes individual.
Une invitation d'event vers un compte pro est refusée.
Règles métier par audienceScope¶
everyone- seulement des invitations
notify; invite_only- seulement des invitations
access; members_only- seulement des invitations
notify; - et uniquement vers des adhérents actifs de la structure ;
members_and_invitees- adhérent actif => seulement
notify; - non-adhérent => seulement
access.
Sémantique d'upsert¶
L'upsert ne crée pas un doublon logique par event + person + effect.
Si une ligne existe déjà :
- si elle est
registered, elle reste telle quelle ; - sinon, le backend la remet en
sent.
Révocation¶
La révocation se fait par :
DELETE /events/{idEvent}/invitations/{idPerson}?effect=access- ou
...effect=notify
Point important :
- une invitation
registeredne peut plus être révoquée.
Decline côté invité¶
L'invité peut décliner ses invitations actives via :
POST /events/{idEvent}/invitations/decline
Cet endpoint agit sur les invitations de la personne connectée pour cet event.
Statuts utiles pour le front¶
Le backend peut renvoyer :
sentseendeclinedrevokedregistered
En V1, le front doit surtout piloter les parcours autour de :
sentdeclinedrevokedregistered
Le statut seen peut apparaître côté API, mais il n'y a pas dans ce bloc de
flow front dédié pour le piloter explicitement.
Point produit important¶
Une invitation access n'a pas de flow d'acceptation explicite séparé.
Son effet est immédiat sur les règles de visibilité / inscription tant qu'elle est active.
Étape 13 - Gérer le EventStaffMember¶
Objectif¶
Permettre à un gestionnaire d'event pro d'ajouter une équipe opérationnelle
autour de l'event.
Terminologie importante¶
Le nom métier / persistance à jour est :
EventStaffMember
Les endpoints exposés au front restent cependant :
/events/{idEvent}/staff
et les DTO de réponse restent :
EventStaffDTO
Endpoints à utiliser¶
GET /v1/web/api/events/{idEvent}/staffPOST /v1/web/api/events/{idEvent}/staffPATCH /v1/web/api/events/{idEvent}/staff/{idPerson}DELETE /v1/web/api/events/{idEvent}/staff/{idPerson}
Qui peut lire le staff¶
Le staff d'un event pro est lisible par un acteur qui a déjà le droit de voir
l'event.
Donc :
- gestionnaire ;
- participant ;
EventStaffMemberactif ;- ou utilisateur ayant l'accès normal via le
audienceScope.
Qui peut gérer le staff¶
Seul un acteur qui peut gérer l'event pro.
Cibles supportées¶
Le backend accepte :
individualpro
à condition que le profil soit valid.
Payload de création / upsert¶
{
"personId": 456,
"title": "Accueil"
}
Payload de patch¶
{
"title": "Logistique",
"status": 1
}
status supporte :
1= actif2= inactif
Réponse de succès¶
Les endpoints GET, POST, PATCH et DELETE renvoient une liste de
EventStaffDTO actifs :
idtitlestatusperson
Sémantique métier importante¶
- un
EventStaffMembern'est pas un participant par défaut ; - un
EventStaffMembern'obtient pas de droit de gestion ; - un
EventStaffMemberobtient un accès opérationnel de lecture ; - un
EventStaffMemberactif peut voir le détail complet de l'event ; - un
EventStaffMemberactif peut voir la liste des participants ; - un
EventStaffMemberactif accède à la conversation générale de l'event.
Cas particulier à connaître¶
Si un créateur pro crée un event avec creatorParticipates=false, le backend
le crée automatiquement en EventStaffMember actif avec le titre
Organisateur.
Le front ne doit pas essayer de recréer cette relation immédiatement après la création.
Étape 14 - Gérer les event proposals pro¶
Objectif¶
Permettre à une structure de proposer plusieurs créneaux à un groupe de personnes, puis de convertir automatiquement la proposal en event quand un créneau atteint le seuil requis.
Endpoints à utiliser¶
GET /v1/web/api/event-proposals/feedGET /v1/web/api/event-proposals/historyGET /v1/web/api/event-proposals/{idEventProposal}POST /v1/web/api/event-proposalsPATCH /v1/web/api/event-proposals/{idEventProposal}PUT /v1/web/api/event-proposals/{idEventProposal}/slots/{idSlot}/response
Préconditions de création côté pro¶
- utilisateur authentifié ;
- profil
valid; - compte
pro; - structure courante choisie ;
actions.canCreateEventProposals = truesurGET /structures/{idStructure}/entitlements.
Payload de création¶
{
"title": "Créneau entraînement Alpha",
"description": "On cherche le meilleur créneau",
"address": "10 rue du Test",
"organizerStructureId": 12,
"creatorParticipatesOnConversion": true,
"sportId": 7,
"cityId": 44,
"level": 3,
"minSeats": 6,
"maxSeats": 12,
"avatarId": 91,
"slots": [
{
"startAt": "2026-04-20T18:00:00Z",
"endAt": "2026-04-20T20:00:00Z"
},
{
"startAt": "2026-04-21T18:00:00Z",
"endAt": "2026-04-21T20:00:00Z"
}
],
"inviteePersonIds": [101, 102, 103]
}
Règles métier importantes de création¶
- pour un compte
pro,organizerStructureIdest obligatoire ; avatarIdest obligatoire ;slotsdoit contenir entre1et3créneaux ;- tous les slots doivent être futurs, avec
endAt > startAt; - les invités doivent être :
- des comptes
individual; - avec un profil
valid; - différents du créateur ;
creatorParticipatesOnConversionvauttruepar défaut ;- si
creatorParticipatesOnConversion=false, le créateur deviendraEventStaffMembersur l'event converti au lieu d'être inscrit comme participant.
Réponse de succès à la création¶
201 Created
Le backend renvoie un EventProposal brut avec notamment :
idcreatedByIdorganizerStructureIdcreatorParticipatesOnConversionexpiresAttitledescriptionaddresssportIdcityIdminSeatsmaxSeatsavatarIdstatusslotsinvitees
Statuts de proposal¶
Le champ status est numérique.
Mapping à utiliser côté front :
1=open2=converted3=cancelled4=expired
Lecture feed / history¶
GET /event-proposals/feed et GET /event-proposals/history renvoient un
EventProposalFeedResponse :
itemsnextCursor
Chaque item expose notamment :
proposalIdcreatedAtexpiresAtstatustitledescriptionaddresssportcityavatarminSeatsmaxSeatscreatorIdcreatorPseudoslotsinviteesCountdeclinedCountrespondedCountresponsesYesresponsesNoisCreatorisInviteehasDeclined
Lecture détail¶
GET /event-proposals/{idEventProposal} renvoie un
EventProposalDetailResponse :
proposalcreatorinviteesslotsviewer
Le bloc proposal expose notamment :
proposalIdstatuscreatedAtexpiresAtorganizerStructureIdcreatorParticipatesOnConversiontitledescriptionaddresssportlevelcityminSeatsmaxSeatswaitlistCapacityeventIdchosenSlotIdfirstRespondedAtavatar
Le bloc viewer expose notamment :
isCreatorisInviteehasDeclinedcanManageProposalmySlotResponsesmyEventStatuscanDeclineProposalcanRespondToSlotscanCounterProposecanChooseEventParticipationisTwoPeopleProposal
Point important sur le détail¶
Quand une proposal est convertie :
proposal.statuspasse à2proposal.eventIdest renseignéproposal.chosenSlotIdest renseigné
Le front peut donc naviguer directement vers l'event créé.
Réponse d’un invité sur un slot¶
PUT /event-proposals/{idEventProposal}/slots/{idSlot}/response
Payload :
{
"response": 1
}
Mapping à utiliser :
1=YES2=NO
Réponse de succès :
200 OK
{
"proposalId": 77,
"slotId": 3,
"response": 1,
"respondedAt": "2026-04-15T10:00:00Z"
}
Règles métier importantes de réponse¶
- seul un invité lié à la proposal peut répondre ;
- un invité qui a déjà décliné la proposal ne peut plus répondre ;
- une proposal doit être
open; - un slot fermé ne peut plus recevoir de réponse ;
- si l'acteur n'est pas lié à la proposal, le backend renvoie
404pour ne pas révéler son existence.
Conflits à gérer côté front¶
Le backend peut renvoyer 409 Conflict si :
- la proposal est expirée ;
- la proposal n'est plus
open; - le slot est fermé.
Auto-conversion en event¶
Quand un slot atteint minSeats, la proposal peut être convertie
automatiquement dans la même transaction.
Pour une proposal pro convertie :
- l'event créé est un event structure-backed ;
- l'
audienceScopeinitial de l'event converti estinvite_only; - les invités de la proposal sont propagés en invitations d'event ;
- si
creatorParticipatesOnConversion=false, le créateur devientEventStaffMembersur l'event converti.
Notifications liées aux proposals¶
La création d'une proposal envoie une notification système aux invités initiaux :
- type centre :
EventProposalSentNotificationType(16) ; payload.kind = "eventProposalSent";- push
data.type = "eventProposalSent"; - destination front : détail de la proposal via
proposalId.
Le patch avec inviteePersonIdsToAdd envoie la même notification uniquement aux
nouveaux invités ajoutés.
La conversion automatique en event envoie une notification système :
- au créateur de la proposal ;
- aux invités inscrits en liste principale sur l'event ;
- aux invités inscrits en liste d'attente sur l'event ;
- aux invités qui n'avaient pas répondu sur le créneau choisi mais peuvent encore rejoindre l'event.
Contrat :
- type centre :
EventProposalConvertedNotificationType(15) ; payload.kind = "eventProposalConverted";- push
data.type = "eventProposalConverted"; - destination front : event créé via
eventId.
Statuts de conversion :
creator: créateur de la proposal ;registered: invité inscrit en liste principale ;waitlisted: invité inscrit en liste d'attente ;joinable: invité sans réponse pouvant encore rejoindre l'event.
Référence exhaustive : - Notification catalog
Patch de proposal¶
PATCH /event-proposals/{idEventProposal} permet de modifier :
titledescriptionaddresslevelsportIdcityIdminSeatsmaxSeatsavatarIdslotsinviteePersonIdsToAdd
Règles importantes du patch¶
- le patch n'est possible que tant que la proposal est
open; - dès qu'il existe une première réponse, les modifications sont fortement verrouillées par le backend ;
inviteePersonIdsToAddest add-only ;- il n'y a pas dans ce bloc de suppression d'invité ;
- il n'y a pas de flow documenté ici pour créer une contre-proposition, même si certains flags de lecture existent déjà côté API.
Étape 15 - Inviter des adhérents sans waitlist¶
Objectif¶
Permettre à une structure d'inviter une adresse email à devenir adhérent sans passer par la waitlist globale.
Endpoints structure / admin¶
GET /v1/web/api/structures/{idStructure}/adherent-invitationsPOST /v1/web/api/structures/{idStructure}/adherent-invitationsGET /v1/web/api/admin/structure-adherent-invitations
Endpoints invitation côté invité¶
POST /v1/public/structure-adherent-invitations/resolvePOST /v1/public/structure-adherent-invitations/signupPOST /v1/public/structure-adherent-invitations/declinePOST /v1/web/api/structure-adherent-invitations/accept
Préconditions côté structure¶
- utilisateur authentifié ;
- compte
pro; - structure courante choisie ;
actions.canManageAdherents = true;actions.canInviteAdherentsWithoutWaitlist = truesurGET /structures/{idStructure}/entitlements.
Envoi batch¶
Payload :
{
"emails": [
"alice@example.com",
"bob@example.com"
]
}
Réponse :
resultsquotaLimitquotaUsedquotaRemainingperiodStartperiodEnd
Chaque item de results expose :
emailnormalizedEmailstatusinvitationId
Statuts métier du batch à gérer¶
sentinvalid_emailalready_active_invitationalready_adherentalready_declinedunsupported_existing_account_typequota_exceeded
Règles métier importantes de l’envoi¶
- l'unicité active est par
email + structure; - la structure doit pouvoir gérer ses adhérents ;
- la capability
users.invite_without_waitlistne suffit pas seule :adherents.managereste aussi requis ; - tant qu'une invitation active existe déjà pour cette structure et cet email,
l'endpoint renvoie
already_active_invitation; - le batch consomme le quota au moment de l'envoi ;
- le suivi quota est renvoyé immédiatement dans la réponse ;
- il n'existe pas de revoke structure-side en V1.
Tracking structure-side¶
GET /structures/{idStructure}/adherent-invitations renvoie un
StructureAdherentInvitationListResponse avec des items exposant notamment :
idstructureIdstructureNameinvitedByPersonIdemailstatustargetPersonIdacceptedPersonIdwaitlistEntryIdexpiresAtsentAtacceptedAtdeclinedAt
Tracking admin-side¶
GET /v1/web/api/admin/structure-adherent-invitations permet d'afficher un suivi
backoffice global du même objet métier.
Ouverture publique du token¶
POST /v1/public/structure-adherent-invitations/resolve avec { "token":
"..." } renvoie un StructureAdherentInvitationResolveResponse avec :
statusnextActioncanDeclinestructureNameemailexpiresAt
Valeurs attendues pour nextAction :
signuploginunsupported_accountnone
Décision front à partir du token¶
nextAction="signup"- afficher le flow de création de compte ;
nextAction="login"- demander une connexion au bon compte
individual, puis appeleraccept; nextAction="unsupported_account"- afficher un blocage produit clair ;
nextAction="none"- utiliser
statuspour informer l'utilisateur.
Le CTA de refus ne doit être affiché que si canDecline=true.
Signup depuis invitation¶
POST /v1/public/structure-adherent-invitations/signup
Payload :
{
"token": "...",
"pseudo": "alice-alpha",
"challengeToken": "token"
}
Réponse :
201 Createdsi le compteindividualest créé ;200 OKsi l'invitation était déjà acceptée.
Le backend renvoie un StructureAdherentInvitationActionResponse :
codemessagepersonIdpseudo
Codes utiles à gérer :
createdalready_accepted
Acceptation sur compte existant¶
POST /v1/web/api/structure-adherent-invitations/accept
Préconditions :
- utilisateur authentifié ;
- compte
individualcorrespondant.
Payload :
{
"token": "..."
}
Réponse :
200 OKStructureAdherentInvitationActionResponse
Codes utiles à gérer :
acceptedalready_accepted
Decline¶
POST /v1/public/structure-adherent-invitations/decline
Payload :
{
"token": "..."
}
Réponse :
200 OKStructureAdherentInvitationActionResponse
Codes utiles à gérer :
declinedalready_declined
Effet produit final¶
À l'acceptation réussie :
- soit un compte
individualest créé ; - soit un compte
individualexistant accepte ; - dans les deux cas, l'adhésion à la structure est créée ou réactivée automatiquement.
Point important lié à la waitlist¶
Si l'email invité était dans la waitlist :
- l'entrée sort proprement de la waitlist ;
- les anciens flows/tokens waitlist ne doivent plus être considérés comme utilisables.
Le front ne doit donc pas essayer de faire cohabiter un ancien parcours waitlist avec une invitation structure active sur le même email.
Résumé opérationnel pour le front¶
Avec les APIs actuelles, le front peut implémenter proprement :
- le choix du type de compte ;
- le signup
pro; - l'inscription waitlist d'un futur compte
pro; - l'état initial d'un compte
prosans structure ; - la création d'une structure ;
- la revendication d'une structure catalogue existante ;
- la lecture canonique de "mes structures gérées" ;
- la lecture canonique des entitlements de structure ;
- la création et la gestion d'un event
pro; - les
audienceScoped'un eventpro; - les invitations d'event
pro; - le
EventStaffMemberd'un eventpro; - les
event proposalspro; - les invitations adhérent structure sans waitlist.
Avec les APIs actuelles, le front ne peut pas encore implémenter proprement, sans convention locale ou nouvelle API :
- le rattachement self-service à une structure déjà gérée.