{"components":{"schemas":{"Artifact":{"properties":{"byte_size":{"format":"int64","type":"integer"},"content_type":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"doc_type":{"description":"Pièce d'entreprise déclarée (clé du pays : rccm, nif…).","type":["string","null"]},"id":{"format":"uuid","type":"string"},"kind":{"enum":["document_front","document_back","selfie","selfie_frame","proof_of_address"]},"quality":{"type":"object"},"revision":{"description":"Rang de la prise pour cette pièce. Une reprise ajoute une révision sans rien écraser ; la plus récente est celle qui est lue.","maximum":9,"minimum":0,"type":"integer"},"sequence":{"format":"int32","type":["integer","null"]}},"required":["id","kind","content_type","byte_size","created_at"],"type":"object"},"ArtifactList":{"properties":{"artifacts":{"items":{"$ref":"#/components/schemas/Artifact"},"type":"array"}},"type":"object"},"Balance":{"properties":{"alert_at":{"$ref":"#/components/schemas/Money","description":"Seuil d'alerte, ou absent si aucune alerte n'est demandée."},"available":{"$ref":"#/components/schemas/Money"},"reserved":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"}},"required":["available","reserved","total"],"type":"object"},"BalanceAlert":{"properties":{"minor":{"description":"Seuil en unités mineures de la devise du compte (centimes pour EUR/USD, unités pour XOF/XAF). `0` désactive l'alerte.","examples":[5000],"minimum":0,"type":"integer"}},"required":["minor"],"type":"object"},"ChallengeEnvelope":{"properties":{"challenge":{"properties":{"attempts_left":{"type":"integer"},"channel":{"enum":["email","sms","whatsapp","call"]},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"target_hint":{"description":"Cible masquée : assez pour reconnaître la bonne adresse, pas assez pour l'apprendre.","examples":["co•••@fastrate.net"],"type":"string"}},"type":"object"}},"required":["challenge"],"type":"object"},"ChallengeRequest":{"properties":{"channel":{"description":"Seul `email` est acheminé aujourd'hui.","enum":["email","sms","whatsapp","call"]}},"required":["channel"],"type":"object"},"CompanyPerson":{"properties":{"created_at":{"format":"date-time","type":"string"},"date_of_birth":{"format":"date","type":["string","null"]},"full_name":{"type":"string"},"id":{"format":"uuid","type":"string"},"kyc_session_id":{"format":"uuid","type":["string","null"]},"kyc_state":{"type":["string","null"]},"nationality":{"type":["string","null"]},"ownership_pct":{"type":["number","null"]},"role":{"enum":["director","ubo","signatory"]},"session_id":{"format":"uuid","type":"string"}},"type":"object"},"CompanyProfile":{"properties":{"address_1":{"type":"string"},"address_2":{"type":["string","null"]},"city":{"type":"string"},"country":{"maxLength":2,"minLength":2,"type":"string"},"email":{"description":"Adresse professionnelle de l'entreprise. C'est là que part le code de confirmation.","type":"string"},"legal_name":{"description":"Raison sociale **telle qu'elle figure au registre**.","examples":["Gracelab Open Tech Sarl"],"type":"string"},"phone":{"description":"E.164, indicatif compris.","examples":["+22898933317"],"type":"string"},"postal_code":{"type":["string","null"]},"region":{"type":["string","null"]},"website":{"type":["string","null"]}},"required":["legal_name","address_1","city","country","phone","email"],"type":"object"},"CompanyProfileEnvelope":{"properties":{"profile":{"$ref":"#/components/schemas/CompanyProfile"}},"required":["profile"],"type":"object"},"Country":{"properties":{"code":{"maxLength":2,"minLength":2,"type":"string"},"documents":{"items":{"$ref":"#/components/schemas/CountryDocument"},"type":"array"},"enabled":{"type":"boolean"},"handoff_ttl_minutes":{"maximum":60,"minimum":2,"type":["integer","null"]},"kyb_documents":{"items":{"properties":{"deferrable":{"description":"Obligatoire mais fournissable après l'envoi.","type":"boolean"},"label":{"type":"string"},"levels":{"description":"Vide : tous les paliers.","items":{"enum":["simplified","standard","enhanced"]},"type":"array"},"note":{"type":"string"},"required":{"type":"boolean"},"type":{"description":"Clé de la pièce, déclarée au dépôt (x-artifact-doc-type).","pattern":"^[a-z0-9_]{1,40}$","type":"string"}},"type":"object"},"type":"array"},"kyc_levels":{"items":{"enum":["simplified","standard","enhanced"]},"type":"array"},"languages":{"items":{"type":"string"},"type":"array"},"max_attempts":{"maximum":20,"minimum":1,"type":["integer","null"]},"name":{"type":"string"},"position":{"type":"integer"},"region":{"type":"string"},"require_address_proof":{"type":"boolean"},"rules":{"type":"object"},"session_ttl_minutes":{"maximum":60,"minimum":5,"type":["integer","null"]},"thresholds":{"properties":{"auto_approve_min":{"maximum":1,"minimum":0,"type":"number"},"doc_auto_accept_at":{"maximum":1,"minimum":0,"type":"number"},"doc_auto_reject_below":{"maximum":1,"minimum":0,"type":"number"},"face_auto_accept_at":{"maximum":1,"minimum":0,"type":"number"},"face_auto_reject_below":{"maximum":1,"minimum":0,"type":"number"},"face_match_min":{"maximum":1,"minimum":0,"type":"number"},"liveness_min_score":{"maximum":1,"minimum":0,"type":"number"},"reject_below":{"maximum":1,"minimum":0,"type":"number"}},"type":"object"},"ubo_policy":{"properties":{"by_level":{"additionalProperties":{"enum":["none","threshold","full_chain"]},"type":"object"},"ownership_threshold":{"exclusiveMinimum":0,"maximum":100,"type":"number"},"senior_managing_official_fallback":{"type":"boolean"},"threshold_inclusive":{"type":"boolean"}},"type":"object"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"CountryDocument":{"properties":{"accepted_for":{"items":{"enum":["simplified","standard","enhanced"]},"type":"array"},"category":{"enum":["identity","address","business"]},"country":{"maxLength":2,"minLength":2,"type":"string"},"doc_id":{"type":"string"},"enabled":{"type":"boolean"},"family":{"enum":["id_card","passport","driving_licence","residence_permit","other"]},"fields":{"items":{"$ref":"#/components/schemas/FieldRule"},"type":"array"},"hint":{"type":"string"},"label":{"type":"string"},"machine_readable":{"enum":["td1","td2","td3","pdf417","none","unknown"]},"position":{"type":"integer"},"rules":{"type":"object"},"sides":{"items":{"enum":["front","back"]},"type":"array"},"specimen":{"oneOf":[{"$ref":"#/components/schemas/SpecimenInfo"},{"type":"null"}]},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"CountryList":{"properties":{"countries":{"items":{"$ref":"#/components/schemas/Country"},"type":"array"}},"type":"object"},"CreateEndpoint":{"properties":{"event_kinds":{"description":"Vide = tous les types d'événements.","items":{"type":"string"},"type":"array"},"url":{"examples":["https://client.example/hooks"],"format":"uri","type":"string"}},"required":["url"],"type":"object"},"CreateReservation":{"properties":{"amount_minor":{"description":"Montant à geler, en unités mineures de la devise du compte.","format":"int64","minimum":1,"type":"integer"},"reference":{"type":"string"}},"required":["amount_minor"],"type":"object"},"CreateSession":{"properties":{"country":{"maxLength":2,"minLength":2,"type":"string"},"level":{"default":"standard","description":"`simplified` : pièce et visage apparié, sans épreuve de rotation ; `standard` : rotation de tête exigée ; `enhanced` : justificatif de domicile en plus, exigé à l'envoi.","enum":["simplified","standard","enhanced"]},"metadata":{"type":"object"},"product":{"examples":["kyc.basic","kyc.nfc","kyb.ubo"],"type":"string"},"reference":{"description":"Identifiant côté client, unique par compte.","type":"string"},"subject_type":{"description":"`person` → KYC, `company` → KYB (registre et bénéficiaires effectifs).","enum":["person","company"]},"ttl_seconds":{"maximum":3600,"minimum":60,"type":"integer"}},"required":["subject_type","product"],"type":"object"},"Delivery":{"properties":{"attempts":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"delivered_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"kind":{"type":"string"},"last_error":{"type":["string","null"]},"last_status":{"type":["integer","null"]},"next_attempt_at":{"format":"date-time","type":"string"},"session_id":{"format":"uuid","type":"string"},"state":{"enum":["pending","delivering","delivered","failed"]}},"required":["id","kind","state","attempts"],"type":"object"},"DeliveryList":{"properties":{"deliveries":{"items":{"$ref":"#/components/schemas/Delivery"},"type":"array"}},"type":"object"},"DuplicateList":{"properties":{"duplicates":{"items":{"properties":{"created_at":{"format":"date-time","type":"string"},"session_id":{"format":"uuid","type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"EndpointList":{"properties":{"endpoints":{"items":{"type":"object"},"type":"array"}},"type":"object"},"EndpointWithSecret":{"properties":{"event_kinds":{"items":{"type":"string"},"type":"array"},"id":{"format":"uuid","type":"string"},"secret":{"description":"Clé de vérification des signatures. Affichée une seule fois. Signature reçue : `webhook-signature: v1,<base64 HMAC-SHA256 de \"{webhook-id}.{webhook-timestamp}.{corps}\">`.","type":"string"},"status":{"enum":["active","disabled"]},"url":{"type":"string"}},"type":"object"},"Event":{"properties":{"created_at":{"format":"date-time","type":"string"},"kind":{"enum":["session.created","session.state_changed","session.decided","balance.debited","balance.released"]},"payload":{"type":"object"},"seq":{"description":"Numéro d'ordre dans la session. Curseur de reprise du flux.","type":"integer"}},"required":["seq","kind","payload","created_at"],"type":"object"},"EventList":{"properties":{"events":{"items":{"$ref":"#/components/schemas/Event"},"type":"array"}},"type":"object"},"ExtractedField":{"properties":{"confidence":{"description":"Dérivée de la provenance : puce 0,99, zone codée intègre 0,98, zone codée fausse 0,30, lecture optique 0,70, saisie 0.","type":"number"},"corrected":{"type":"boolean"},"key":{"type":"string"},"label":{"type":"string"},"mrz_match":{"type":"boolean"},"original_value":{"type":"string"},"rule_error":{"type":"string"},"source":{"enum":["chip","mrz","ocr","manual",null]},"value":{"type":["string","null"]}},"type":"object"},"ExtractionEnvelope":{"properties":{"extraction":{"properties":{"anomalies":{"items":{"type":"string"},"type":"array"},"authenticity_score":{"type":["number","null"]},"document":{"type":["string","null"]},"fields":{"items":{"$ref":"#/components/schemas/ExtractedField"},"type":"array"},"findings":{"items":{"properties":{"key":{"type":"string"},"kind":{"enum":["field_missing","field_format_invalid","field_low_confidence","mrz_cross_check_failed","field_corrected_by_user","correction_conflicts_with_mrz"]}},"type":"object"},"type":"array"},"mrz":{"properties":{"checksum_valid":{"type":"boolean"},"format":{"enum":["td1","td2","td3"]},"raw":{"items":{"type":"string"},"type":"array"}},"type":["object","null"]},"overall_confidence":{"type":["number","null"]},"read_at":{"format":"date-time","type":"string"}},"type":["object","null"]}},"type":"object"},"FieldRule":{"properties":{"cross_check_mrz":{"type":"boolean"},"key":{"pattern":"^[a-z0-9_]{1,40}$","type":"string"},"label":{"type":"string"},"min_confidence":{"default":0.85,"maximum":1,"minimum":0,"type":"number"},"pattern":{"description":"Expression régulière, non ancrée.","maxLength":200,"type":"string"},"pattern_hint":{"type":"string"},"required":{"type":"boolean"},"type":{"enum":["text","date","number","sex","country"]}},"required":["key","label","type"],"type":"object"},"Handoff":{"properties":{"claimed_at":{"format":"date-time","type":["string","null"]},"completed_at":{"format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"session_id":{"format":"uuid","type":"string"}},"type":"object"},"HandoffClaim":{"properties":{"token":{"type":"string"}},"required":["token"],"type":"object"},"HandoffClaimed":{"properties":{"handoff_id":{"format":"uuid","type":"string"},"session":{"$ref":"#/components/schemas/Session","description":"La session, avec un `client_token` propre au téléphone."},"token_expires_at":{"format":"date-time","type":"string"}},"required":["handoff_id","session"],"type":"object"},"HandoffEnvelope":{"properties":{"handoff":{"oneOf":[{"$ref":"#/components/schemas/Handoff"},{"type":"null"}]}},"type":"object"},"HandoffIssued":{"properties":{"expires_at":{"format":"date-time","type":"string"},"handoff_id":{"format":"uuid","type":"string"},"token":{"description":"Jeton de passerelle (`hd_…`), renvoyé une seule fois. À placer dans l'URL de continuation encodée dans le QR code.","type":"string"}},"required":["handoff_id","token","expires_at"],"type":"object"},"Money":{"properties":{"amount":{"description":"Rendu lisible. Ne pas parser : toutes les devises n'ont pas deux décimales.","type":"string"},"amount_minor":{"description":"Montant en unités mineures. Seule valeur à utiliser en calcul.","format":"int64","type":"integer"},"currency":{"maxLength":3,"minLength":3,"type":"string"}},"required":["amount_minor","amount","currency"],"type":"object"},"NewCompanyPerson":{"properties":{"date_of_birth":{"format":"date","type":["string","null"]},"full_name":{"minLength":3,"type":"string"},"nationality":{"maxLength":2,"minLength":2,"type":["string","null"]},"ownership_pct":{"maximum":100,"minimum":0,"type":["number","null"]},"role":{"enum":["director","ubo","signatory"]}},"required":["role","full_name"],"type":"object"},"PersonEnvelope":{"properties":{"person":{"$ref":"#/components/schemas/CompanyPerson"}},"type":"object"},"PersonKycLink":{"properties":{"expires_at":{"format":"date-time","type":"string"},"kyc_session_id":{"format":"uuid","type":"string"},"person":{"$ref":"#/components/schemas/CompanyPerson"},"token":{"description":"Jeton de passerelle, rendu une seule fois.","type":"string"}},"required":["person","kyc_session_id","token","expires_at"],"type":"object"},"PersonList":{"properties":{"persons":{"items":{"$ref":"#/components/schemas/CompanyPerson"},"type":"array"}},"type":"object"},"Problem":{"description":"Erreur au format RFC 9457.","properties":{"code":{"description":"Identifiant stable de la catégorie d'erreur, destiné au code client.","type":"string"},"detail":{"type":"string"},"status":{"type":"integer"},"title":{"type":"string"},"type":{"format":"uri","type":"string"}},"required":["type","title","status","code","detail"],"type":"object"},"Reservation":{"properties":{"amount":{"$ref":"#/components/schemas/Money"},"expires_at":{"format":"date-time","type":"string"},"reference":{"type":["string","null"]},"session_id":{"format":"uuid","type":"string"},"state":{"enum":["active","captured","released","expired"]}},"required":["session_id","state","amount"],"type":"object"},"ReviewCase":{"properties":{"blocking":{"description":"Interdit toute décision automatique.","type":"boolean"},"created_at":{"format":"date-time","type":"string"},"due_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"reference":{"type":["string","null"]},"resolution":{"description":"Motif écrit, renseigné à la clôture.","type":["string","null"]},"session_id":{"format":"uuid","type":"string"},"state":{"enum":["open","claimed","closed"]},"triggers":{"description":"Ce qui a détourné le dossier : `PrintedMismatch`, `IntegrityFailed`, `DuplicateArtifact`…"}},"required":["id","session_id","state","blocking","due_at","created_at"],"type":"object"},"ReviewQueue":{"properties":{"cases":{"items":{"$ref":"#/components/schemas/ReviewCase"},"type":"array"},"overdue":{"description":"Dossiers ayant dépassé l'échéance de 24 heures.","type":"integer"}},"required":["cases","overdue"],"type":"object"},"Session":{"properties":{"amount":{"$ref":"#/components/schemas/Money"},"client_token":{"description":"Présent uniquement à la création. Jamais réémis.","type":"string"},"country":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"decision":{"type":["object","null"]},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"level":{"enum":["simplified","standard","enhanced"]},"livemode":{"description":"`false` : session d'essai ouverte avec une clé `test` — ni facturée, ni examinée, invisible des clés de production.","type":"boolean"},"metadata":{"type":"object"},"open":{"description":"La session peut encore évoluer.","type":"boolean"},"outcome_reason":{"type":["string","null"]},"product":{"type":"string"},"reference":{"type":["string","null"]},"settled_at":{"format":"date-time","type":["string","null"]},"state":{"enum":["created","collecting","processing","approved","rejected","failed","cancelled","expired"]},"subject_type":{"enum":["person","company"]},"support_contact":{"description":"Contact d'assistance du compte, à montrer en cas de refus.","type":["string","null"]}},"required":["id","state","open","amount"],"type":"object"},"SessionList":{"properties":{"sessions":{"items":{"$ref":"#/components/schemas/Session"},"type":"array"}},"type":"object"},"SpecimenInfo":{"properties":{"byte_size":{"type":"integer"},"filename":{"type":"string"},"media_type":{"enum":["image/jpeg","image/png","image/webp","application/pdf"]},"note":{"type":"string"},"sha256":{"type":"string"},"uploaded_at":{"format":"date-time","type":"string"}},"type":"object"},"SubmitResult":{"properties":{"documents":{"type":"integer"},"legal_name":{"type":"string"},"review_within_hours":{"description":"Échéance de la file de revue, pas une promesse commerciale.","type":"integer"},"state":{"const":"processing"}},"type":"object"},"VerifyRequest":{"properties":{"code":{"examples":["123456"],"type":"string"}},"required":["code"],"type":"object"}},"securitySchemes":{"clientToken":{"description":"Jeton de session (`st_…`), renvoyé une seule fois à la création. Portée à cette seule session, périme avec elle.","scheme":"bearer","type":"http"},"draftToken":{"description":"Lien de reprise d'un parcours KYB (`kd_…`), rendu une seule fois. Donne accès à ce seul dossier : saisie, puis suivi et pièces différées.","scheme":"bearer","type":"http"},"tenantKey":{"description":"Clé d'API du compte (`sk_…`). Ne jamais l'exposer côté navigateur : utiliser le jeton de session.","scheme":"bearer","type":"http"}}},"info":{"description":"Vérification KYC, KYB et AML en temps réel, sur solde prépayé. Une vérification gèle son prix à l'ouverture et ne le débite que si une décision est rendue.","title":"API de vérification d'identité","version":"0.1.0"},"openapi":"3.1.0","paths":{"/v1/artifacts/{artifact_id}/duplicates":{"get":{"description":"Rapprochement par empreinte du contenu. Une même photo présentée dans plusieurs dossiers est un signal de fraude ; ce n'en est pas la preuve.","parameters":[{"in":"path","name":"artifact_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateList"}}},"description":"Succès"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Pièce inconnue pour ce compte"}},"summary":"Autres sessions ayant déposé la même image","tags":["Pièces"]}},"/v1/balance":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"}}},"description":"Succès"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Clé d'API absente ou inconnue"}},"summary":"Solde disponible, réservé et total","tags":["Solde"]}},"/v1/balance/alert":{"put":{"description":"Sous ce seuil, un événement `balance.low` part vers les destinations webhook actives. Il n'est envoyé qu'une fois : la marque se lève au premier rechargement, faute de quoi chaque débit sous le seuil enverrait une alerte et le client cesserait de les lire.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceAlert"}}},"required":true},"responses":{"204":{"description":"Seuil enregistré"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Seuil négatif"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Clé d'API absente ou inconnue"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Permission insuffisante"}},"summary":"Régler le seuil d'alerte de solde","tags":["Solde"]}},"/v1/cases":{"get":{"description":"Sessions envoyées, avec leur statut de dossier (pending, in_review, awaiting_documents, approved, rejected, expired), leur risque et leur revue. Les identités sont masquées pour qui n'a pas le droit de les lire.","parameters":[{"in":"query","name":"days","schema":{"default":200,"maximum":365,"type":"integer"}},{"in":"query","name":"limit","schema":{"default":2000,"maximum":5000,"type":"integer"}}],"responses":{"200":{"description":"{ items, pii }"}},"summary":"Dossiers de l'organisation","tags":["Sessions"]}},"/v1/cases/{session_id}":{"get":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"{ case, analysis, company, persons, documents, pii }"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Dossier d'une autre organisation, ou inconnu"}},"summary":"Un dossier : contrôles, champs lus, entreprise, personnes, pièces","tags":["Sessions"]}},"/v1/consent-notice":{"get":{"description":"Construite depuis vos réglages (responsable du traitement, délégué, hébergement, conservation, alternative en agence). Renvoyez `version` et `hash` avec le consentement : le texte exact est conservé comme preuve.","parameters":[{"in":"query","name":"level","required":false,"schema":{"enum":["simplified","standard","enhanced"],"type":"string"}}],"responses":{"200":{"description":"{ version, hash, notice }"}},"security":[{"tenantKey":[]}],"summary":"Notice d'information à afficher avant la collecte","tags":["Consentement"]}},"/v1/countries":{"get":{"description":"Sans authentification : c'est la liste que l'utilisateur final voit dans un sélecteur, avant d'avoir le moindre jeton. Ne renvoie que les pays et pièces ouverts. Pour chaque pièce : les faces à photographier, le format lisible par machine attendu, et les règles propres au document. Pour chaque pays : les pièces d'entreprise attendues et les seuils de décision. Une session ouverte pour un pays absent d'ici répond 422.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountryList"}}},"description":"Succès"}},"security":[],"summary":"Pays couverts et pièces acceptées","tags":["Catalogue"]}},"/v1/handoffs/claim":{"post":{"description":"Consomme le jeton lu dans le QR code et remet au téléphone son propre jeton de session, de portée identique à celui de l'ordinateur. Sans autre authentification : c'est le jeton qui authentifie. Un jeton inconnu, périmé ou déjà lu répond de la même façon (404).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffClaim"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffClaimed"}}},"description":"Succès"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Jeton inconnu, périmé ou déjà utilisé"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Trop de tentatives depuis cette adresse"}},"security":[],"summary":"Rejoindre une session depuis le téléphone","tags":["Passerelle"]}},"/v1/kyb/draft":{"get":{"responses":{"200":{"description":"{ draft, case } — case est présent une fois soumis : statut, pièces reçues et attendues, personnes, motif d'exemption."},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lien inconnu ou périmé"}},"security":[{"draftToken":[]}],"summary":"Saisie et état du dossier","tags":["Entreprises"]},"put":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"country":{"type":"string"},"level":{"enum":["simplified","standard","enhanced"]},"state":{"description":"64 Ko au plus.","type":"object"}},"required":["state"],"type":"object"}}},"required":true},"responses":{"200":{"description":"{ draft }"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Dossier déjà soumis"}},"security":[{"draftToken":[]}],"summary":"Enregistrer la saisie","tags":["Entreprises"]}},"/v1/kyb/draft/documents":{"post":{"description":"Corps : le fichier (image ou PDF) ; `x-artifact-doc-type` : la pièce demandée par le pays.","responses":{"201":{"description":"{ document, awaiting_documents }"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Dossier non soumis, ou pièce que le pays ne demande pas"}},"security":[{"draftToken":[]}],"summary":"Fournir une pièce après soumission","tags":["Entreprises"]}},"/v1/kyb/draft/persons/{person_id}/kyc":{"post":{"description":"Ouvre sa session d'identité au niveau du dossier et rend un jeton de passerelle (72 h).","parameters":[{"in":"path","name":"person_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"{ person, kyc_session_id, token, expires_at }"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Vérification déjà ouverte pour cette personne"}},"security":[{"draftToken":[]}],"summary":"Vérifier l'identité d'une personne du dossier","tags":["Entreprises"]}},"/v1/kyb/draft/session":{"post":{"description":"Ouvre (ou rouvre, sans second prix gelé) la session facturée de la soumission et rend un jeton limité à elle, pour déposer les pièces par `POST /v1/sessions/{id}/artifacts` avec `x-artifact-doc-type`.","responses":{"201":{"description":"{ session_id, client_token }"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Dossier déjà soumis"}},"security":[{"draftToken":[]}],"summary":"Ouvrir la session où déposer les pièces","tags":["Entreprises"]}},"/v1/kyb/draft/submit":{"post":{"description":"Le service rejoue toutes les règles : pièces exigées par le pays à ce niveau (les différables mettent le dossier en attente), format du numéro d'immatriculation, exigence de bénéficiaires effectifs selon la forme juridique, le niveau et le seuil du pays, repli sur le dirigeant. Enregistre l'entreprise, le dirigeant et les bénéficiaires, consigne le motif d'une exemption, et remet le dossier à un examinateur.","responses":{"200":{"description":"{ reference, session_id, awaiting_documents, ubo_exemption }"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Dossier incomplet — le motif dit quoi"}},"security":[{"draftToken":[]}],"summary":"Soumettre le dossier","tags":["Entreprises"]}},"/v1/kyb/drafts":{"post":{"description":"Appelé par le serveur du client, avec la clé du compte. Rend un lien de reprise (`kd_…`, 30 jours) à remettre au représentant de l'entreprise : il porte la saisie au fil des jours, puis le suivi et les pièces différées. N'engage aucun prix : la session facturée n'est ouverte qu'à la soumission.","requestBody":{"content":{"application/json":{"schema":{"properties":{"country":{"maxLength":2,"minLength":2,"type":"string"},"level":{"enum":["simplified","standard","enhanced"]},"metadata":{"description":"2 Ko au plus. `external_ref` relie les tentatives d'une même entreprise.","type":"object"}},"required":["level"],"type":"object"}}},"required":true},"responses":{"201":{"description":"{ token, draft }"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Pays ou niveau non ouvert"}},"summary":"Ouvrir un parcours KYB hébergé","tags":["Entreprises"]}},"/v1/links":{"get":{"responses":{"200":{"description":"{ links }"}},"summary":"Liens de vérification émis","tags":["Liens"]},"post":{"description":"Le dossier naîtra chez vous, au niveau et dans le pays imposés. Canal `email` : le lien part par courriel ; `sms` : aucun opérateur raccordé, `delivery: not_available` — transmettez le lien vous-même.","requestBody":{"content":{"application/json":{"schema":{"properties":{"channel":{"enum":["link","email","sms","api","widget"]},"country":{"type":"string"},"external_ref":{"maxLength":64,"type":"string"},"kyc_level":{"enum":["simplified","standard","enhanced"]},"recipient_email":{"type":"string"},"recipient_name":{"type":"string"},"recipient_phone":{"type":"string"},"ttl_hours":{"maximum":720,"minimum":1,"type":"integer"},"type":{"enum":["kyc","kyb"]}},"required":["type","kyc_level","channel","ttl_hours"],"type":"object"}}},"required":true},"responses":{"201":{"description":"{ link } — avec son jeton et `delivery`."},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Organisation suspendue"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Réglage du lien invalide"}},"summary":"Émettre un lien de vérification","tags":["Liens"]}},"/v1/links/resolve/{token}":{"get":{"parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}},{"description":"Page hôte d'une iframe de widget : la réponse dit si elle est autorisée.","in":"query","name":"origin","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok, link, client, embed: { frame_ancestors, origin_allowed } } ou { ok: false, reason }"}},"security":[],"summary":"Résoudre un lien (public)","tags":["Liens"]}},"/v1/links/{link_id}/resend":{"post":{"parameters":[{"in":"path","name":"link_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"{ link }"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lien déjà terminé ou révoqué"}},"summary":"Renvoyer un lien (remplacé s'il est périmé)","tags":["Liens"]}},"/v1/links/{link_id}/revoke":{"post":{"parameters":[{"in":"path","name":"link_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"{ link }"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lien déjà terminé ou révoqué"}},"summary":"Révoquer un lien","tags":["Liens"]}},"/v1/links/{token}/notice":{"get":{"parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ version, hash, notice }"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lien inconnu"}},"security":[],"summary":"Notice d'information de l'organisation qui a émis le lien (public)","tags":["Liens"]}},"/v1/links/{token}/open":{"post":{"description":"KYC : une session et son jeton client. KYB : un brouillon et son lien de reprise.","parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"{ type, session | draft_token, client }"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lien indisponible"}},"security":[],"summary":"Ouvrir le parcours d'un lien (public)","tags":["Liens"]}},"/v1/reservations":{"post":{"description":"Sert aux traitements dont le prix n'est pas celui d'un produit du catalogue. Le cycle est le même que celui d'une session : gel, puis débit (`capture`) ou restitution (`release`).","parameters":[{"description":"Clé unique par requête (8 à 255 caractères). Un rejeu avec la même clé renvoie la réponse mémorisée sans réexécuter ; avec un corps différent, c'est un conflit.","in":"header","name":"Idempotency-Key","required":true,"schema":{"maxLength":255,"minLength":8,"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReservation"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reservation"}}},"description":"Succès"},"402":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Solde insuffisant"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Réservation déjà ouverte pour cette référence"}},"summary":"Geler un montant sans ouvrir de vérification","tags":["Réservations"]}},"/v1/reservations/{session_id}":{"get":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reservation"}}},"description":"Succès"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Réservation inconnue"}},"summary":"État d'une réservation","tags":["Réservations"]}},"/v1/reservations/{session_id}/capture":{"post":{"description":"Idempotent : rejouer une capture déjà faite renvoie 200. Le client qui a perdu la réponse n'a donc rien de particulier à gérer. Capturer une réservation déjà libérée reste un conflit réel.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reservation"}}},"description":"Succès"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Réservation déjà libérée"}},"summary":"Débiter la réservation","tags":["Réservations"]}},"/v1/reservations/{session_id}/release":{"post":{"description":"Idempotent, au même titre que la capture.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reservation"}}},"description":"Succès"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Réservation déjà capturée"}},"summary":"Restituer la réservation au solde disponible","tags":["Réservations"]}},"/v1/reviews":{"get":{"description":"Pourquoi une session n'avance pas. Un dossier `blocking` interdit toute décision automatique : la session attend un examinateur, quelles que soient les pièces déposées ensuite. La décision est rendue par nos analystes — cette route ne l'expose pas, elle explique l'attente.","parameters":[{"description":"Nombre de dossiers (1 à 200, 50 par défaut).","in":"query","name":"limit","required":false,"schema":{"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewQueue"}}},"description":"Succès"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Clé d'API absente ou inconnue"}},"summary":"Vérifications retenues pour examen humain","tags":["Sessions"]}},"/v1/screening/alerts":{"get":{"description":"Correspondances entre vos clients (personnes, sociétés, dirigeants, bénéficiaires effectifs) et les listes de sanctions (ONU, OFAC, UE, Royaume-Uni, France, listes nationales) ou de personnes politiquement exposées. Levées à l'entrée en relation et à chaque mise à jour des listes (surveillance continue). Chaque alerte vous est aussi notifiée par webhook : `screening.alert`, puis `screening.confirmed` (correspondance confirmée : gel et déclaration à votre cellule de renseignement financier) ou `screening.cleared` (homonymie).","parameters":[{"in":"query","name":"status","required":false,"schema":{"enum":["open","true_positive","false_positive","all"],"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"maximum":1000,"minimum":1,"type":"integer"}}],"responses":{"200":{"description":"{ alerts: [...] } — nom du client masqué sans le droit de lecture des données personnelles"}},"security":[{"tenantKey":[]}],"summary":"Alertes sanctions et PPE de vos dossiers","tags":["Filtrage LBC/FT"]}},"/v1/sessions":{"get":{"description":"Fenêtre récente, de la plus récente à la plus ancienne. Sert à retrouver une session dont l'identifiant n'a pas été conservé, ou à reprendre après un incident. L'export d'historique complet n'est pas cette route.","parameters":[{"description":"Nombre de sessions (1 à 200, 50 par défaut).","in":"query","name":"limit","required":false,"schema":{"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionList"}}},"description":"Succès"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Clé d'API absente ou inconnue"}},"summary":"Dernières vérifications du compte","tags":["Sessions"]},"post":{"description":"Gèle le prix du produit. Échoue en 402 si le solde ne le couvre pas, avant tout traitement coûteux.","parameters":[{"description":"Clé unique par requête (8 à 255 caractères). Un rejeu avec la même clé renvoie la réponse mémorisée sans réexécuter ; avec un corps différent, c'est un conflit.","in":"header","name":"Idempotency-Key","required":true,"schema":{"maxLength":255,"minLength":8,"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSession"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Succès"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Corps invalide ou clé d'idempotence absente"},"402":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Solde insuffisant : recharger le compte"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Référence déjà utilisée, ou clé d'idempotence rejouée avec un autre corps"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Produit non tarifé"}},"summary":"Ouvrir une vérification","tags":["Sessions"]}},"/v1/sessions/{session_id}":{"get":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Succès"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session inconnue pour cette authentification"}},"security":[{"tenantKey":[]},{"clientToken":[]}],"summary":"État courant d'une session","tags":["Sessions"]}},"/v1/sessions/{session_id}/artifacts":{"get":{"description":"Ne renvoie jamais les octets. Une image d'identité n'a pas à retraverser le réseau, et l'exposer ouvrirait une voie de récupération des données biométriques.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactList"}}},"description":"Succès"}},"security":[{"tenantKey":[]},{"clientToken":[]}],"summary":"Métadonnées des pièces déposées","tags":["Pièces"]},"post":{"description":"Le corps est le **binaire brut** de l'image, pas du multipart ni du base64 : deux mégaoctets encodés en base64 en font presque trois, pour rien. Les métadonnées voyagent en en-têtes.\n\nLe type déclaré ne fait pas foi : le format est reconnu à ses octets d'en-tête, et un `Content-Type` qui ne correspond pas est refusé. Un dépôt est immuable — redéposer le même type dans la même session est un conflit.\n\nLimites : 8 Mio par image, 24 pièces par session, `image/jpeg`, `image/png` ou `image/webp`.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Nature de la pièce.","in":"header","name":"x-artifact-kind","required":true,"schema":{"enum":["document_front","document_back","selfie","selfie_frame","proof_of_address"]}},{"description":"Rang dans une séquence faciale. Obligatoire en pratique pour `selfie_frame` : sans lui, deux poses sont deux dépôts du même type, donc un conflit.","in":"header","name":"x-artifact-sequence","required":false,"schema":{"format":"int32","type":"integer"}},{"description":"Mesures relevées sur l'appareil, en JSON compact. Conservées telles quelles : elles disent dans quelles conditions l'image a été prise, ce qu'aucune analyse ultérieure ne retrouve.","in":"header","name":"x-artifact-quality","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"image/jpeg":{"schema":{"format":"binary","type":"string"}},"image/png":{"schema":{"format":"binary","type":"string"}},"image/webp":{"schema":{"format":"binary","type":"string"}}},"description":"Octets de l'image.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Artifact"}}},"description":"Succès"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"En-tête de nature absent ou inconnu"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Pièce déjà déposée pour ce type, ou session close"},"413":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Image au-delà de 8 Mio, ou 24 pièces déjà déposées"},"415":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Format non accepté, ou octets ne correspondant pas au type déclaré"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Déposer une image","tags":["Pièces"]}},"/v1/sessions/{session_id}/cancel":{"post":{"description":"Rend les fonds gelés. Impossible une fois l'analyse engagée (`processing`) : le travail est déjà consommé.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Succès"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session déjà terminée, ou analyse déjà engagée"}},"security":[{"tenantKey":[]},{"clientToken":[]}],"summary":"Abandonner une vérification","tags":["Sessions"]}},"/v1/sessions/{session_id}/challenge":{"post":{"description":"Le code part vers l'adresse **déclarée dans le profil**, jamais vers une adresse fournie ici : laisser choisir la destination au moment de l'envoi reviendrait à laisser le sujet se confirmer sur une boîte jetable. Valable une heure, trois essais. Émettre un nouveau code invalide le précédent. Seul `email` est acheminé aujourd'hui.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChallengeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChallengeEnvelope"}}},"description":"Succès"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Profil d'entreprise absent, ou canal inconnu"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Jeton absent ou périmé"},"501":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Canal pas encore acheminé"}},"summary":"Envoyer un code de confirmation","tags":["Entreprises"]}},"/v1/sessions/{session_id}/challenge/verify":{"post":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyRequest"}}},"required":true},"responses":{"204":{"description":"Canal confirmé"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Aucun code en attente"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Code incorrect ou expiré"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Trop d'essais : demander un nouveau code"}},"summary":"Confirmer le code reçu","tags":["Entreprises"]}},"/v1/sessions/{session_id}/company":{"put":{"description":"Remplaçable tant que la session est ouverte : un formulaire de dix champs se corrige, et refuser la correction pousserait à rouvrir une session — donc à payer deux fois. Le téléphone s'écrit en E.164, indicatif compris.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyProfile"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyProfileEnvelope"}}},"description":"Succès"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Champ manquant, pays ou téléphone invalide"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Jeton absent ou périmé"}},"summary":"Déclarer l'entreprise vérifiée","tags":["Entreprises"]}},"/v1/sessions/{session_id}/consent":{"post":{"description":"À appeler avant toute collecte. Idempotent pour une même finalité et une même version du texte. Émet `consent.granted`. Conservé en ajout seul : un retrait se date, il ne s'efface pas.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"locale":{"default":"fr","maxLength":16,"type":"string"},"notice_version":{"maxLength":64,"type":"string"},"purpose":{"default":"identity_verification","maxLength":64,"type":"string"}},"required":["notice_version"],"type":"object"}}},"required":true},"responses":{"201":{"description":"Consentement consigné (ou déjà présent)"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session déjà terminée"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Consigner le consentement de la personne","tags":["Sessions"]}},"/v1/sessions/{session_id}/document":{"put":{"description":"Validé contre le catalogue : pays ouvert, palier de la session ouvert sur ce pays, pièce d'identité active et recevable à ce palier. Changer de pièce efface la lecture en temps réel précédente. Émet `document.chosen`.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"country":{"maxLength":2,"minLength":2,"type":"string"},"document":{"type":"string"}},"required":["country","document"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Succès"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session déjà envoyée"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Pays, palier ou pièce non recevable"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Choisir le pays et la pièce d'identité","tags":["Sessions"]}},"/v1/sessions/{session_id}/events":{"get":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Ne renvoyer que les événements de numéro supérieur.","in":"query","name":"after","required":false,"schema":{"format":"int32","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventList"}}},"description":"Succès"}},"security":[{"tenantKey":[]},{"clientToken":[]}],"summary":"Journal des événements","tags":["Sessions"]}},"/v1/sessions/{session_id}/extraction":{"get":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionEnvelope"}}},"description":"Succès"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Jeton absent ou périmé"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Dernière lecture, corrections comprises","tags":["Sessions"]},"patch":{"description":"La personne corrige ce qui a été mal lu. La valeur probante n'est jamais remplacée : l'examinateur voit les deux, et corriger une valeur protégée par un chiffre de contrôle bloque le dossier (`CorrectionConflictsWithMrz`). Refusé une fois la session envoyée. Émet `extraction.corrected` (clés seulement).","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"corrections":{"items":{"properties":{"key":{"type":"string"},"value":{"maxLength":200,"minLength":1,"type":"string"}},"required":["key","value"],"type":"object"},"minItems":1,"type":"array"}},"required":["corrections"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionEnvelope"}}},"description":"Succès"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Pièce pas encore lue"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Champ inconnu du gabarit, valeur vide, session envoyée"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Corriger des valeurs lues","tags":["Sessions"]},"post":{"description":"Lit la pièce déposée (zone codée, face imprimée) et juge chaque champ par le gabarit du pays : obligatoire, format, confiance, recoupement avec la zone codée. À appeler après le dépôt du document, pour l'écran de relecture. Ne décide rien : l'analyse finale relit la pièce à l'envoi. Émet `extraction.completed` (clés en défaut, sans valeurs).","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionEnvelope"}}},"description":"Succès"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Document non déposé"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Jeton absent ou périmé"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session déjà envoyée"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Moteur de lecture indisponible"},"504":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lecture trop longue"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Lire la pièce en temps réel","tags":["Sessions"]}},"/v1/sessions/{session_id}/handoff":{"get":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffEnvelope"}}},"description":"Succès"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"État de la passerelle la plus récente","tags":["Passerelle"]},"post":{"description":"Émet un jeton de passerelle à encoder dans un QR code, sous la forme d'une URL de continuation. Le jeton vit dix minutes, ne sert qu'une fois, et n'est **pas** le jeton de session : il peut traverser un écran que d'autres regardent. Réémettre périme la passerelle précédente et révoque le téléphone qui l'avait réclamée.\n\nL'écran qui l'a demandé n'a ensuite qu'à écouter le flux SSE : `handoff.claimed` quand le téléphone se connecte, `artifact.uploaded` à chaque image, `handoff.completed` quand il a terminé.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffIssued"}}},"description":"Succès"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Jeton absent ou périmé"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session déjà terminée"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Déporter la capture vers un téléphone","tags":["Passerelle"]}},"/v1/sessions/{session_id}/handoff/complete":{"post":{"description":"Appelée par le téléphone après la dernière image. Son jeton de session est révoqué dans la même transaction : il ne peut plus rien déposer, et l'ordinateur reprend la main.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffEnvelope"}}},"description":"Succès"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Aucun téléphone n'a rejoint la session"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Déclarer la capture mobile terminée","tags":["Passerelle"]}},"/v1/sessions/{session_id}/liveness/challenges":{"post":{"description":"Trois mouvements tirés par le serveur, dont toujours une rotation de tête, dans un ordre imprévisible : une séquence connue d'avance se rejoue avec une vidéo. Émet `liveness.challenges_issued`.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"{ challenges: [{ key, label }] }"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session déjà envoyée"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Tirer la séquence de vivacité","tags":["Sessions"]}},"/v1/sessions/{session_id}/persons":{"get":{"parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonList"}}},"description":"Succès"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Personnes déclarées sur le dossier d'entreprise","tags":["Personnes"]},"post":{"description":"Un bénéficiaire effectif se déclare avec sa part détenue. Au plus douze personnes par dossier ; au moins une avant l'envoi.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewCompanyPerson"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonEnvelope"}}},"description":"Succès"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Nom trop court, nationalité mal formée, part manquante"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Déclarer un dirigeant, un bénéficiaire effectif ou un signataire","tags":["Personnes"]}},"/v1/sessions/{session_id}/persons/{person_id}":{"delete":{"description":"Refusé une fois sa vérification d'identité ouverte.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"person_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Retirée"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Introuvable ou déjà vérifiée"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Retirer une personne déclarée","tags":["Personnes"]}},"/v1/sessions/{session_id}/persons/{person_id}/kyc":{"post":{"description":"Crée une session `person` sur le compte — son prix est gelé — rattachée au dossier d'entreprise dans ses métadonnées, et rend un jeton de passerelle (`hd_…`, trois jours, usage unique) à placer dans le lien transmis à la personne : `/verifier?jeton=…`. C'est elle qui consent et capture, dans son propre parcours.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"person_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonKycLink"}}},"description":"Succès"},"402":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Solde insuffisant pour geler le prix de la vérification"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Vérification déjà ouverte pour cette personne"}},"security":[{"clientToken":[]},{"tenantKey":[]}],"summary":"Ouvrir la vérification d'identité d'une personne","tags":["Personnes"]}},"/v1/sessions/{session_id}/simulate":{"post":{"description":"Réservé aux sessions ouvertes avec une clé `test`. Fixe l'issue (`approved`, `rejected` ou `review`) en suivant le vrai chemin : mêmes transitions, mêmes événements, mêmes webhooks (envoyés aux seuls points de terminaison `test`, avec `livemode: false`). Rien n'est facturé, personne n'est certifié.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"outcome":{"enum":["approved","rejected","review"],"type":"string"},"reason":{"maxLength":500,"type":"string"}},"required":["outcome"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Succès"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session inconnue, ou d'un autre environnement que la clé"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session réelle, ou déjà terminée"}},"security":[{"tenantKey":[]}],"summary":"Simuler l'issue d'une session d'essai","tags":["Bac à sable"]}},"/v1/sessions/{session_id}/stream":{"get":{"description":"Diffuse chaque étape au moment où elle se produit et se ferme seul sur une session terminée. En cas de coupure, renvoyer l'en-tête `Last-Event-ID` pour reprendre exactement où le flux s'était arrêté.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"text/event-stream":{"schema":{"type":"string"}}},"description":"Flux d'événements"}},"security":[{"tenantKey":[]},{"clientToken":[]}],"summary":"Flux temps réel (Server-Sent Events)","tags":["Sessions"]}},"/v1/sessions/{session_id}/submit":{"post":{"description":"Clôt la collecte ; la session ne s'abandonne plus. Pour une **personne**, l'analyse démarre : lecture de la zone codée et de la face imprimée, appariement du visage au portrait du document, épreuve de rotation de tête, aiguillage par les règles puis par les seuils du pays. La décision (`session.decided`) ou la mise en revue arrivent par le flux et le webhook ; `analysis.completed` les précède avec les scores. Pour une **entreprise**, le dossier part à un examinateur : profil déclaré, contact confirmé et au moins une pièce sont exigés.","parameters":[{"in":"path","name":"session_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitResult"}}},"description":"Succès"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Profil, confirmation ou pièce manquante"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Jeton absent ou périmé"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Session déjà terminée"}},"summary":"Clore la collecte et remettre le dossier","tags":["Entreprises"]}},"/v1/subjects":{"get":{"description":"Risque, statut PPE, prochaine revue, fin de relation, conservation. `due=true` : revues arrivées à échéance (aussi notifiées par webhook `subject.review_due`).","parameters":[{"in":"query","name":"due","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"{ subjects: [...] }"}},"security":[{"tenantKey":[]}],"summary":"Clients vérifiés et revues périodiques","tags":["Clients vérifiés"]}},"/v1/subjects/{external_ref}":{"get":{"parameters":[{"description":"Votre référence du client (subject_ref)","in":"path","name":"external_ref","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ subject, data }"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Client inconnu ou effacé"}},"security":[{"tenantKey":[]}],"summary":"Droit d'accès : tout ce qui est détenu sur la personne","tags":["Clients vérifiés"]}},"/v1/subjects/{external_ref}/erasure":{"post":{"description":"Pendant la conservation légale, l'effacement est différé et l'accès restreint (`status: restricted`, avec la date d'échéance et la base légale) ; après, effacement immédiat (`status: erased`).","parameters":[{"description":"Votre référence du client (subject_ref)","in":"path","name":"external_ref","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"note":{"type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"description":"{ status, detail, retention_until, legal_basis }"}},"security":[{"tenantKey":[]}],"summary":"Transmettre une demande d'effacement de la personne","tags":["Clients vérifiés"]}},"/v1/subjects/{external_ref}/relationship-end":{"post":{"description":"La conservation légale (10 ans) court à partir de cette date ; la surveillance continue s'arrête. Données effacées à l'échéance (webhook `subject.purged`).","parameters":[{"description":"Votre référence du client (subject_ref)","in":"path","name":"external_ref","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"ended_at":{"format":"date-time","type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"description":"{ subject }"}},"security":[{"tenantKey":[]}],"summary":"Déclarer la fin de la relation d'affaires","tags":["Clients vérifiés"]}},"/v1/webhook_deliveries":{"get":{"parameters":[{"in":"query","name":"state","required":false,"schema":{"enum":["pending","delivering","delivered","failed"]}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryList"}}},"description":"Succès"}},"summary":"Journal des livraisons","tags":["Webhooks"]}},"/v1/webhook_deliveries/{delivery_id}/retry":{"post":{"description":"Réservé aux livraisons épuisées après leurs huit tentatives. Le compteur repart à zéro et la livraison est reprise au tour suivant du distributeur.","parameters":[{"in":"path","name":"delivery_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}},"description":"Succès"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Livraison inconnue pour ce compte"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Livraison déjà remise, ou encore en cours de traitement"}},"summary":"Remettre une livraison abandonnée en file","tags":["Webhooks"]}},"/v1/webhook_endpoints":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointList"}}},"description":"Succès"}},"summary":"Lister les destinations","tags":["Webhooks"]},"post":{"description":"Le secret de signature n'est renvoyé qu'ici, une seule fois. L'URL doit être en HTTPS.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEndpoint"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointWithSecret"}}},"description":"Succès"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"URL non HTTPS ou invalide"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"URL déjà enregistrée"}},"summary":"Enregistrer une destination","tags":["Webhooks"]}},"/v1/webhook_endpoints/{endpoint_id}":{"delete":{"description":"Désactivation, pas suppression : « cette destination a reçu des livraisons jusqu'au 12 mars » est une information d'audit, une ligne absente n'en est pas une. Les livraisons déjà en file ne sont plus tentées.","parameters":[{"in":"path","name":"endpoint_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Destination désactivée"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Destination inconnue pour ce compte"}},"summary":"Désactiver une destination","tags":["Webhooks"]}},"/v1/webhook_endpoints/{endpoint_id}/rotate":{"post":{"parameters":[{"in":"path","name":"endpoint_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"{ id, secret } — le secret n'est rendu qu'une fois."}},"summary":"Nouveau secret de signature","tags":["Webhooks"]}},"/v1/webhook_endpoints/{endpoint_id}/test":{"post":{"parameters":[{"in":"path","name":"endpoint_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"{ status_code, duration_ms }"}},"summary":"Envoi d'essai signé","tags":["Webhooks"]}},"/v1/widget/sessions":{"post":{"description":"Appelé par le serveur de l'intégrateur avec sa clé d'API (droit links:write). Rend un jeton valable 30 minutes, à usage unique, que seules les origines déclarées dans l'espace client peuvent afficher dans une iframe. Refusé tant qu'aucune origine n'est déclarée.","requestBody":{"content":{"application/json":{"schema":{"properties":{"country":{"maxLength":2,"minLength":2,"type":"string"},"external_ref":{"maxLength":64,"type":"string"},"kyc_level":{"enum":["simplified","standard","enhanced"],"type":"string"},"recipient_name":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"201":{"description":"{ session_token, link_id, expires_at }"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Organisation suspendue ou droit manquant"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Aucune origine déclarée, pays ou niveau non ouvert"}},"summary":"Jeton de widget (depuis votre serveur)","tags":["Liens"]}}},"security":[{"tenantKey":[]}],"servers":[{"description":"Instance courante","url":"/"}],"tags":[{"description":"Cycle de vie d'une vérification","name":"Sessions"},{"description":"Consultation du solde prépayé","name":"Solde"},{"description":"Notifications sortantes signées","name":"Webhooks"},{"description":"Dépôt des images depuis l'appareil","name":"Pièces"},{"description":"Capture déportée de l'ordinateur vers le téléphone","name":"Passerelle"},{"description":"Pays couverts et pièces acceptées","name":"Catalogue"},{"description":"Dirigeants et bénéficiaires effectifs d'une entreprise","name":"Personnes"},{"description":"Gel et débit du solde, hors vérification","name":"Réservations"}]}