referentiel-des-tiers
Interface synchrone (OpenAPI) — version 0.1.0. Producteur : relation-tiers. Consommateurs déclarés : back-office, instruments, operations.
L’ancre est tenantisée : elle référence l’identité détenue par un autre domaine ou porte une identité professionnelle locale strictement limitée au besoin relationnel — les deux modes sont exclusifs. Un rôle n’est jamais un type d’acteur. Un canal vérifié n’est ni un pouvoir juridique ni une autorisation applicative. Les identifiants canoniques sont opaques ; aucun identifiant ni statut de CRM ne traverse ce contrat. Les valeurs de coordonnées sont masquées partout, hors l’endpoint distinct et fortement autorisé de révélation.
La spécification
Section intitulée « La spécification »openapi: 3.1.0info: title: relation-tiers — le référentiel des tiers version: 0.1.0 summary: >- Les ancres d'acteurs et leurs identifiants qualifiés, le rapprochement d'identité et les redirections, les relations, rôles et périmètres, les mandats et la capacité déclarée, les contacts, points de contact et autorisations de canal. description: >- L'ancre est tenantisée : elle référence l'identité détenue par un autre domaine ou porte une identité professionnelle locale strictement limitée au besoin relationnel — les deux modes sont exclusifs. Un rôle n'est jamais un type d'acteur. Un canal vérifié n'est ni un pouvoir juridique ni une autorisation applicative. Les identifiants canoniques sont opaques ; aucun identifiant ni statut de CRM ne traverse ce contrat. Les valeurs de coordonnées sont masquées partout, hors l'endpoint distinct et fortement autorisé de révélation. x-producteurs: - relation-tiers x-consommateurs: - composant: back-office statut: pressenti — fiches épargnant et entreprise, interlocuteurs, état des coordonnées, pouvoirs - composant: instruments statut: pressenti — l'identité des tiers structurels vient du domaine Relation tiers - composant: operations x-ruptures: [] # première version publiée — aucune rupturepaths: /relation-tiers/v1/actors: post: operationId: creerUneAncre summary: >- Créer une ancre locale ou référencée — les deux modes d'identité sont exclusifs, une référence de domaine inconnue part en quarantaine sans pouvoir opposable. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreationDAncre' responses: '201': description: L'ancre est créée — identifiant canonique, version, statut. content: application/json: schema: $ref: '#/components/schemas/Ancre' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/actors/{actorId}: get: operationId: consulterUneAncre summary: >- Consulter l'ancre à une date — source, statut, libellé autorisé ; la réponse porte un ETag (version d'agrégat). security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/actorId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/dateDEffet' responses: '200': description: L'ancre applicable à la date demandée. content: application/json: schema: $ref: '#/components/schemas/Ancre' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } /relation-tiers/v1/actors:search: get: operationId: rechercherDesAncres summary: >- Rechercher par critères qualifiés — identifiant officiel (type, émetteur, valeur), nature, statut, libellé — sous contrôle d'habilitation et de finalité ; candidats filtrés, curseur opaque. security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/curseur' - $ref: '#/components/parameters/limite' - name: identifierType in: query schema: { type: string } - name: identifierValue in: query schema: { type: string } - name: actorNature in: query schema: { $ref: '#/components/schemas/NatureDActeur' } - name: status in: query schema: { type: string } - name: label in: query schema: { type: string } responses: '200': description: La page de candidats filtrés. content: application/json: schema: $ref: '#/components/schemas/PageDAncres' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } /relation-tiers/v1/actors/{actorId}/external-identifiers: post: operationId: ajouterUnIdentifiantExterne summary: >- Ajouter un identifiant qualifié — type, valeur, émetteur, juridiction, objet identifié, portée, période, statut de vérification ; un identifiant sans émetteur est rejeté. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/actorId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/IdentifiantExterne' responses: '201': description: L'identifiant est enregistré. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/actors/{actorId}:suspend: post: operationId: suspendreUneAncre summary: Suspendre l'ancre — raison codée, date d'effet ; nouvelle version. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/actorId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: L'ancre est suspendue — nouvelle version. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/actors/{actorId}:close: post: operationId: fermerUneAncre summary: Fermer l'ancre — raison codée, date d'effet ; nouvelle version. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/actorId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: L'ancre est fermée — nouvelle version. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/actors/{actorId}/history: get: operationId: consulterLHistoriqueDUneAncre summary: >- Restituer les versions et redirections — « identité utilisée à l'époque » et « identité canonique actuelle », chronologie complète. security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/actorId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' responses: '200': description: La chronologie des versions et redirections. content: application/json: schema: $ref: '#/components/schemas/HistoriqueDAncre' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } /relation-tiers/v1/identity-match-cases: post: operationId: proposerUnDossierDeRapprochement summary: >- Proposer un dossier et ses candidats — signaux favorables et contradictoires, versions comparées ; l'IA propose, elle ne fusionne jamais. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PropositionDeRapprochement' responses: '201': description: Le dossier de rapprochement est ouvert. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/identity-match-cases/{caseId}: get: operationId: consulterUnDossierDeRapprochement summary: Consulter les critères, signaux et impacts du dossier. security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/caseId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' responses: '200': description: Le dossier de rapprochement. content: application/json: schema: $ref: '#/components/schemas/DossierDeRapprochement' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } /relation-tiers/v1/identity-match-cases/{caseId}:decide: post: operationId: deciderUnRapprochement summary: >- La décision humaine — MEME_ACTEUR, ACTEURS_DISTINCTS, INDETERMINE ou A_REEXAMINER ; exige decision, reasonCode, deciderContext et les références de preuves ; refuse un sujet de type AI_AGENT. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/caseId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DecisionDeRapprochement' responses: '200': description: >- La décision est enregistrée — MEME_ACTEUR crée la redirection datée, ACTEURS_DISTINCTS inhibe les propositions répétées de la paire. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/actor-redirects/{redirectId}:reverse: post: operationId: inverserUneRedirection summary: >- Séparation logique motivée — la fusion logique est réversible ; les références historiques ne bougent pas. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/redirectId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: La redirection est close par une séparation datée et motivée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships: post: operationId: declarerUneRelation summary: >- Déclarer une relation — nature et sens explicites, parties, période [from, to), fondement avant opposabilité. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DeclarationDeRelation' responses: '201': description: La relation est déclarée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships/{relationshipId}:submit: post: operationId: soumettreUneRelation summary: Soumettre la relation à validation. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/relationshipId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' responses: '200': description: La relation est soumise. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships/{relationshipId}:activate: post: operationId: activerUneRelation summary: Activer la relation — le fondement est exigé avant l'opposabilité. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/relationshipId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' responses: '200': description: La relation est active. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships/{relationshipId}:suspend: post: operationId: suspendreUneRelation summary: Suspendre la relation — raison codée, date d'effet. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/relationshipId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: La relation est suspendue. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships/{relationshipId}:close: post: operationId: cloturerUneRelation summary: >- Clôturer la relation — l'ancienne relation est close, jamais écrasée ; les rôles actifs hors période sont refusés. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/relationshipId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: La relation est clôturée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships/{relationshipId}/roles: post: operationId: attribuerUnRole summary: >- Attribuer un rôle dans la relation — code canonique, période, contexte ; jamais hors de la période de la relation. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/relationshipId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AttributionDeRole' responses: '201': description: Le rôle est attribué. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships/{relationshipId}/roles/{roleId}:withdraw: post: operationId: retirerUnRole summary: Retirer le rôle à date — fin et raison, l'historique demeure. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/relationshipId' - $ref: '#/components/parameters/roleId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: Le rôle est retiré à la date d'effet. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships/{relationshipId}/scopes: post: operationId: versionnerUnPerimetre summary: >- Créer une version de périmètre — membres {mode, domain, objectType, objectId, purpose} ; les expressions dynamiques utilisent le langage canonique versionné, jamais une requête SQL ni un filtre CRM. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/relationshipId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/VersionDePerimetre' responses: '201': description: La version de périmètre est créée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/relationships:applicable: get: operationId: consulterLesRelationsApplicables summary: >- Les relations applicables à une date et un contexte — acteur, nature, périmètre ; sert notamment l'état de la relation d'une entreprise (entrée en relation, active, sortie). security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/dateDEffet' - $ref: '#/components/parameters/curseur' - $ref: '#/components/parameters/limite' - name: actorId in: query schema: { type: string } - name: relationshipType in: query schema: { type: string } responses: '200': description: Les relations applicables. content: application/json: schema: $ref: '#/components/schemas/PageDeRelations' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } /relation-tiers/v1/mandates: post: operationId: enregistrerUnMandat summary: >- Enregistrer un mandat ou une délégation — mandant et mandataire identifiés, actes et limites structurés, date d'effet obligatoire. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EnregistrementDeMandat' responses: '201': description: Le mandat est enregistré. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/mandates/{mandateId}:verify: post: operationId: enregistrerLaVerificationDUnMandat summary: Enregistrer la validation humaine — la preuve est exigée avant activation. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/mandateId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/VerificationDeMandat' responses: '200': description: La vérification est enregistrée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/mandates/{mandateId}:activate: post: operationId: activerUnMandat summary: >- Activer à date — preuve et période exigées ; deux mandats actifs incompatibles sur la même portée sont refusés (PERIOD_OVERLAP). security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/mandateId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' responses: '200': description: Le mandat est applicable. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/mandates/{mandateId}:revoke: post: operationId: revoquerUnMandat summary: >- Enregistrer une révocation — append-only, date d'effet distincte de la date de connaissance : une révocation reçue après une instruction ne réécrit ni l'instruction ni la décision initiale. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/mandateId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: La révocation est enregistrée à sa date d'effet. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/mandates/{mandateId}:suspend: post: operationId: suspendreUnMandat summary: Suspendre le mandat — raison codée, date d'effet. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/mandateId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: Le mandat est suspendu. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/mandates:applicable: get: operationId: consulterLesMandatsApplicables summary: >- Les mandats applicables à une date — par mandant, mandataire ou périmètre ; les actes autorisés sont des codes canoniques. security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/dateDEffet' - $ref: '#/components/parameters/curseur' - $ref: '#/components/parameters/limite' - name: grantorActorId in: query schema: { type: string } - name: granteeActorId in: query schema: { type: string } responses: '200': description: Les mandats applicables. content: application/json: schema: $ref: '#/components/schemas/PageDeMandats' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } /relation-tiers/v1/declared-capacity-checks: post: operationId: verifierLaCapaciteDeclaree summary: >- Vérifier la capacité déclarée d'un acteur à agir pour un autre — action codée, portée, contexte de canal, date d'effet ; ETABLIE, NON_ETABLIE, AMBIGUE ou INDETERMINABLE. Le domaine exécutant doit encore autoriser la commande. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/VerificationDeCapacite' responses: '200': description: Le contrôle est rendu et conservé avec ses sources. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCapacite' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '422': { $ref: '#/components/responses/inapplicable' } '503': { $ref: '#/components/responses/dependanceIndisponible' } /relation-tiers/v1/declared-capacity-checks/{checkId}: get: operationId: consulterUnControleDeCapacite summary: Consulter le contrôle et ses sources — reconstituable pour l'audit. security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/checkId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' responses: '200': description: Le contrôle conservé. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCapacite' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } /relation-tiers/v1/contact-assignments: post: operationId: rattacherUnContact summary: >- Rattacher une personne à une organisation — fonction, période ; aucun pouvoir implicite. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RattachementDeContact' responses: '201': description: Le rattachement est créé. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/contact-assignments/{assignmentId}:close: post: operationId: cloturerUnRattachement summary: >- Clôturer le rattachement — l'ancien rattachement est clos, les demandes anciennes restent inchangées. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/assignmentId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: Le rattachement est clôturé. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/contact-substitutions: post: operationId: declarerUneSuppleance summary: Déclarer une suppléance ou un remplacement — période bornée. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Suppleance' responses: '201': description: La suppléance est déclarée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/contact-points: post: operationId: ajouterUnPointDeContact summary: >- Ajouter un point de contact — type, valeur protégée, usage ; la valeur est chiffrée, seul un masque non réversible est restituable en liste. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PointDeContact' responses: '201': description: Le point de contact est ajouté — la réponse ne porte pas la valeur. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/contact-points/{contactPointId}:verify: post: operationId: enregistrerUneVerificationDeContact summary: Enregistrer une vérification — finalité, niveau, date. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/contactPointId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/VerificationDeContact' responses: '200': description: La vérification est enregistrée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/contact-points/{contactPointId}:suspend: post: operationId: suspendreUnPointDeContact summary: >- Suspendre ou déclarer compromis — le NPAI d'une adresse postale, l'endpoint compromis d'un partenaire ; le canal devient inutilisable, l'historique demeure. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/contactPointId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' - $ref: '#/components/parameters/versionAttendue' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CommandeDeCycleDeVie' responses: '200': description: Le point de contact est suspendu ou déclaré compromis. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/contact-points/{contactPointId}:reveal: post: operationId: revelerUneValeurDeContact summary: >- L'endpoint distinct et fortement autorisé — la valeur déchiffrée pour une action précise et une finalité déclarée ; acte audité. security: - authentification: [relation-tiers:coordonnees] parameters: - $ref: '#/components/parameters/contactPointId' - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' requestBody: required: true content: application/json: schema: type: object required: [purpose, action] properties: purpose: type: string description: La finalité autorisée qui justifie la révélation. action: type: string description: L'action précise pour laquelle la valeur est demandée. responses: '200': description: La valeur déchiffrée, pour cette action et cette finalité seules. content: application/json: schema: type: object required: [contactPointId, value] properties: contactPointId: { type: string } value: { type: string } '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/channel-authorizations: post: operationId: autoriserUnUsageDeCanal summary: >- Autoriser un usage et une finalité sur un point de contact — période ; une même finalité ne porte pas deux autorisations qui se chevauchent. security: - authentification: [relation-tiers:tiers] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/idempotence' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AutorisationDeCanal' responses: '201': description: L'autorisation est créée. content: application/json: schema: $ref: '#/components/schemas/ResultatDeCommande' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '409': { $ref: '#/components/responses/conflit' } '422': { $ref: '#/components/responses/inapplicable' } /relation-tiers/v1/contacts:resolve: get: operationId: resoudreLeContactAdapte summary: >- Chercher le contact adapté au contexte — acteur, finalité, canal ; la réponse masque la valeur. security: - authentification: [relation-tiers:consultation] parameters: - $ref: '#/components/parameters/tenant' - $ref: '#/components/parameters/correlation' - $ref: '#/components/parameters/dateDEffet' - name: actorId in: query required: true schema: { type: string } - name: purpose in: query required: true schema: { type: string } - name: channelType in: query schema: { type: string } responses: '200': description: >- Les contacts adaptés, valeur masquée — le masque non réversible et l'état de vérification, jamais la valeur. content: application/json: schema: $ref: '#/components/schemas/ContactsResolus' '401': { $ref: '#/components/responses/nonAuthentifie' } '403': { $ref: '#/components/responses/nonAutorise' } '404': { $ref: '#/components/responses/introuvable' }components: securitySchemes: authentification: type: http scheme: bearer description: >- Tout appel est authentifié (401) et autorisé par famille d'accès (403 hors famille) — chaque opération déclare sa famille en portée, sous la forme relation-tiers:famille. Ce contrat ouvre relation-tiers:consultation (lectures), relation-tiers:tiers (écritures du référentiel relationnel) et relation-tiers:coordonnees (révélation d'une valeur). La portée est le filtre grossier ; le grain fin (périmètre, finalité) s'évalue à l'exécution. Le tenant vient du jeton ; un X-Tenant-Id éventuel doit être identique. Le mécanisme est OIDC ; sa déclinaison relève de l'assemblage. parameters: tenant: name: X-Tenant-Id in: header required: false description: >- Facultatif — le tenant fait foi dans le jeton ; s'il est fourni, il doit être identique, et le corps ne peut jamais le choisir. schema: type: string correlation: name: X-Correlation-Id in: header required: false schema: type: string idempotence: name: Idempotency-Key in: header required: true description: >- La clé d'idempotence de la commande — liée à l'intention métier, pas à la tentative réseau ; même clé et même contenu rejouent le résultat initial, même clé et contenu différent font 409 IDEMPOTENCY_CONFLICT. schema: type: string versionAttendue: name: If-Match in: header required: true description: La version d'agrégat attendue — 409 CONCURRENT_MODIFICATION sinon. schema: type: string dateDEffet: name: effectiveAt in: query required: false description: >- La date d'effet de la lecture — la situation applicable à cette date ; absente, la lecture porte sur maintenant. schema: type: string format: date-time curseur: name: cursor in: query required: false schema: type: string limite: name: limit in: query required: false schema: type: integer maximum: 200 actorId: name: actorId in: path required: true schema: { type: string } caseId: name: caseId in: path required: true schema: { type: string } redirectId: name: redirectId in: path required: true schema: { type: string } relationshipId: name: relationshipId in: path required: true schema: { type: string } roleId: name: roleId in: path required: true schema: { type: string } mandateId: name: mandateId in: path required: true schema: { type: string } checkId: name: checkId in: path required: true schema: { type: string } assignmentId: name: assignmentId in: path required: true schema: { type: string } contactPointId: name: contactPointId in: path required: true schema: { type: string } responses: nonAuthentifie: description: Aucune identité présentée (401). nonAutorise: description: >- L'identité présentée n'a pas la famille d'accès requise (403). Les 403 croisés entre familles sont prouvés par les tests d'assemblage. Un écart de tenant ne produit jamais ce code sur une ressource — il produit 404 (ne rien révéler). introuvable: description: >- Ressource absente ou invisible — y compris une ressource d'un autre tenant : le régime de la muraille ne révèle pas l'existence (404, jamais 403). content: application/json: schema: $ref: '#/components/schemas/Probleme' conflit: description: >- Version obsolète (CONCURRENT_MODIFICATION), chevauchement interdit (PERIOD_OVERLAP) ou clé d'idempotence réutilisée avec un contenu différent (IDEMPOTENCY_CONFLICT). content: application/json: schema: $ref: '#/components/schemas/Probleme' inapplicable: description: >- Donnée comprise mais non admissible — règle identifiée (BUSINESS_RULE_VIOLATION), référence externe non résolue (REFERENCE_UNRESOLVED) ou preuve insuffisante (CAPACITY_INDETERMINATE). content: application/json: schema: $ref: '#/components/schemas/Probleme' dependanceIndisponible: description: Une dépendance critique est indisponible (DEPENDENCY_UNAVAILABLE). content: application/json: schema: $ref: '#/components/schemas/Probleme' schemas: Probleme: type: object description: >- L'enveloppe d'erreur du catalogue (Problem Details) — le texte n'expose ni l'existence d'un objet d'un autre tenant, ni une donnée sensible. required: [type, title, status, code, correlationId] properties: type: { type: string } title: { type: string } status: { type: integer } code: { type: string } detail: { type: string } instance: { type: string } correlationId: { type: string } retryable: { type: boolean } violations: type: array items: type: object properties: field: { type: string } reason: { type: string } ruleId: { type: string } NatureDActeur: type: string enum: [LEGAL_ENTITY, NATURAL_PERSON, COLLECTIVE, TECHNICAL_PARTY] ModeDAncrage: type: string enum: [REFERENCE_DOMAINE, IDENTITE_LOCALE] ReferenceDeDomaine: type: object required: [domain, objectType, objectId] properties: domain: { type: string } objectType: { type: string } objectId: { type: string } CreationDAncre: type: object required: [identityMode, actorNature] properties: identityMode: $ref: '#/components/schemas/ModeDAncrage' actorNature: $ref: '#/components/schemas/NatureDActeur' ownerReference: $ref: '#/components/schemas/ReferenceDeDomaine' localIdentity: type: object description: >- L'identité professionnelle locale, strictement limitée au besoin relationnel — exclusive d'une ownerReference. properties: legalName: { type: string } jurisdiction: { type: string } displayLabel: type: string description: Non opposable — sa modification ne change pas l'identité source. Ancre: type: object required: [actorId, identityMode, actorNature, status, aggregateVersion] properties: actorId: { type: string } identityMode: $ref: '#/components/schemas/ModeDAncrage' actorNature: $ref: '#/components/schemas/NatureDActeur' ownerReference: $ref: '#/components/schemas/ReferenceDeDomaine' displayLabel: { type: string } status: { type: string } aggregateVersion: { type: integer } redirectedTo: type: string description: L'ancre canonique si une redirection logique est active. PageDAncres: type: object required: [items] properties: items: type: array items: $ref: '#/components/schemas/Ancre' nextCursor: { type: string } HistoriqueDAncre: type: object required: [actorId, entries] properties: actorId: { type: string } entries: type: array items: type: object required: [kind, recordedAt] properties: kind: type: string description: VERSION_IDENTITE, REDIRECTION, SEPARATION, TRANSITION. validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } recordedAt: { type: string, format: date-time } detail: { type: object } IdentifiantExterne: type: object required: [identifierType, value, issuer] properties: identifierType: { type: string } value: { type: string } issuer: { type: string } jurisdiction: { type: string } identifiedObjectType: { type: string } scope: { type: string } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } verificationStatus: { type: string } verificationSource: { type: string } PropositionDeRapprochement: type: object required: [sourceActorId, candidates] properties: sourceActorId: { type: string } candidates: type: array items: type: object required: [actorId] properties: actorId: { type: string } score: { type: number } signals: type: array items: { type: string } producedBy: type: string description: La règle ou le modèle ayant produit la proposition. comparedVersions: { type: object } DossierDeRapprochement: type: object required: [caseId, status, sourceActorId, candidates] properties: caseId: { type: string } status: { type: string } sourceActorId: { type: string } candidates: type: array items: { type: object } decision: { type: string } decidedBy: { type: string } decidedAt: { type: string, format: date-time } aggregateVersion: { type: integer } DecisionDeRapprochement: type: object required: [decision, reasonCode, deciderContext] properties: decision: type: string enum: [MEME_ACTEUR, ACTEURS_DISTINCTS, INDETERMINE, A_REEXAMINER] reasonCode: { type: string } deciderContext: type: object description: Le décideur humain — un sujet de type AI_AGENT est refusé. evidenceReferences: type: array items: { type: string } effectiveAt: { type: string, format: date-time } DeclarationDeRelation: type: object required: [relationshipType, parties, validFrom] properties: relationshipType: { type: string } parties: type: array items: type: object required: [actorId, side] properties: actorId: { type: string } side: { type: string } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } basisReferences: type: array items: { type: string } PageDeRelations: type: object required: [items] properties: items: type: array items: type: object required: [relationshipId, relationshipType, status] properties: relationshipId: { type: string } relationshipType: { type: string } status: { type: string } parties: type: array items: { type: object } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } aggregateVersion: { type: integer } nextCursor: { type: string } AttributionDeRole: type: object required: [actorId, roleCode, validFrom] properties: actorId: { type: string } roleCode: { type: string } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } context: { type: object } VersionDePerimetre: type: object required: [members] properties: members: type: array items: type: object required: [mode, domain, objectType] properties: mode: { type: string } domain: { type: string } objectType: { type: string } objectId: { type: string } purpose: { type: string } expression: type: string description: >- Expression dynamique dans le langage canonique versionné — jamais une requête SQL ni un filtre CRM. expressionLanguageVersion: { type: string } EnregistrementDeMandat: type: object required: [grantorActorId, granteeActorId, mandateType, effectiveAt] properties: grantorActorId: { type: string } granteeActorId: { type: string } mandateType: { type: string } actions: type: array items: { type: string } limits: { type: object } scope: type: array items: $ref: '#/components/schemas/ReferenceDeDomaine' effectiveAt: { type: string, format: date-time } expiresAt: { type: string, format: date-time } evidenceReferences: type: array items: { type: string } VerificationDeMandat: type: object required: [verifierContext, verifiedAt] properties: verifierContext: { type: object } verifiedAt: { type: string, format: date-time } evidenceReferences: type: array items: { type: string } PageDeMandats: type: object required: [items] properties: items: type: array items: type: object required: [mandateId, status] properties: mandateId: { type: string } grantorActorId: { type: string } granteeActorId: { type: string } mandateType: { type: string } status: { type: string } actions: type: array items: { type: string } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } nextCursor: { type: string } VerificationDeCapacite: type: object required: [actingActorId, representedActorId, action, effectiveAt] properties: actingActorId: { type: string } representedActorId: { type: string } action: { type: string } scope: type: array items: $ref: '#/components/schemas/ReferenceDeDomaine' channelContextId: { type: string } effectiveAt: { type: string, format: date-time } ResultatDeCapacite: type: object required: [checkId, verdict] properties: checkId: { type: string } verdict: type: string enum: [ETABLIE, NON_ETABLIE, AMBIGUE, INDETERMINABLE] sources: type: array items: { type: object } checkedAt: { type: string, format: date-time } RattachementDeContact: type: object required: [personActorId, organisationActorId, validFrom] properties: personActorId: { type: string } organisationActorId: { type: string } function: { type: string } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } Suppleance: type: object required: [substitutedAssignmentId, substituteAssignmentId, validFrom, validTo] properties: substitutedAssignmentId: { type: string } substituteAssignmentId: { type: string } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } PointDeContact: type: object required: [holderActorId, channelType, value] properties: holderActorId: { type: string } channelType: { type: string } value: type: string description: >- La valeur en entrée seulement — chiffrée à la persistance, jamais restituée hors de l'endpoint de révélation. usage: { type: string } VerificationDeContact: type: object required: [purpose, level, verifiedAt] properties: purpose: { type: string } level: { type: string } verifiedAt: { type: string, format: date-time } AutorisationDeCanal: type: object required: [contactPointId, purpose, validFrom] properties: contactPointId: { type: string } purpose: { type: string } validFrom: { type: string, format: date-time } validTo: { type: string, format: date-time } ContactsResolus: type: object required: [items] properties: items: type: array items: type: object required: [contactPointId, channelType, maskedValue] properties: contactPointId: { type: string } channelType: { type: string } maskedValue: { type: string } verificationLevel: { type: string } authorizedPurposes: type: array items: { type: string } CommandeDeCycleDeVie: type: object required: [reasonCode] properties: reasonCode: { type: string } effectiveAt: { type: string, format: date-time } comment: { type: string } ResultatDeCommande: type: object required: [id, aggregateVersion, status] properties: id: { type: string } aggregateVersion: { type: integer } status: { type: string }