Aller au contenu

Membres sans code fiscal

Afficher en Markdown

Adhérer à une association n’exige pas de code fiscal italien (codice fiscale). Ce qu’il faut, c’est que la personne soit identifiée, et sur Vimine elle l’est de l’une de ces deux façons :

  • par un code fiscal, ou
  • par ses données de naissance : dob + birthplace + birth_country (ISO 3166-1 alpha-2).

Jamais ni l’un ni l’autre. La suite de ce guide décrit ce qui change, champ par champ, pour une intégration qui fait adhérer des personnes — étudiants en échange, bénévoles tout juste arrivés, membres qui vivent à l’étranger.

POST /v1/enroll et POST /v1/signup acceptent les mêmes champs :

Champ
codicefiscale facultatif. Quand il est présent, il est validé et comparé avec les noms, la date et le lieu de naissance
dob date de naissance, YYYY-MM-DD
birthplace la commune (comune) pour une personne née en Italie ; la ville, en texte libre, pour une personne née à l’étranger
birth_country pays de naissance, deux lettres (IT, FR, SN…)
gender démographique seulement : il n’est plus comparé avec le code
// Sans code fiscal : date, lieu et pays de naissance
await vimineServer.enroll({
email: 'marie.dupont@example.org',
first_name: 'Marie',
last_name: 'Dupont',
dob: '1985-03-10',
birthplace: 'Lyon',
birth_country: 'FR',
accept_statuto: { version: statuto.version, sha256: statuto.sha256 }
});

Sur /v1/enroll, sans code, chaque donnée de naissance manquante est un 422 validation_failed avec une entrée dans errors[] :

{ "code": "validation_failed", "errors": [{ "field": "birth_country", "code": "required" }] }

/v1/signup ne crée que le compte : les données de naissance y restent facultatives, et seront nécessaires quand la personne demandera une adhésion.

Le code fiscal d’une personne née en Italie contient la commune de naissance ; celui d’une personne née à l’étranger ne contient que l’État. Pour ces personnes, la comparaison porte donc sur birth_country et traite birthplace — la ville — comme du texte libre. Envoyer birth_country est ce qui permet à une personne née à l’étranger avec un code valable de passer : sans lui, « Lyon » serait cherché parmi les communes italiennes et le code paraîtrait incohérent. (Un formulaire qui envoyait jusqu’ici le nom italien de l’État comme lieu de naissance — birthplace: 'Francia' — continue de passer ; birth_country est la forme à préférer.)

Il en va de même pour la vérification publique, qui dit aussi désormais ce que le code contient :

const r = await publicApi().validateFiscalCode({
code: 'DPNMRA85C50Z110U', first_name: 'Marie', last_name: 'Dupont', date: '1985-03-10', place: 'Lyon', country: 'FR'
});
// { valid: true, error: null, mismatches: [], hints: [], birth_date: '1985-03-10', birth_country: 'FR' }

birth_date et birth_country sont lus dans le code lui-même : vous pouvez les utiliser pour préremplir le formulaire. Cet endpoint compare encore gender, quand vous l’envoyez ; l’adhésion et le profil, non.

Un code mal saisi (structure ou caractère de contrôle) est invalid_codicefiscale : il doit être corrigé, il ne peut jamais être confirmé. Un code bien formé qui est en désaccord avec les données saisies répond en revanche 422 avec une entrée plus riche :

{
"code": "validation_failed",
"errors": [{
"field": "codicefiscale",
"code": "codicefiscale_mismatch",
"mismatches": ["place"],
"hints": [],
"confirmable": true
}]
}
  • mismatches — ce qui ne concorde pas : lastName, firstName, date, place ;
  • hints — names_swapped quand le code correspond une fois le nom et le prénom intervertis : proposer l’inversion suffit généralement ;
  • confirmable — si la personne peut confirmer que c’est bien le code inscrit sur sa carte d’assurance maladie (tessera sanitaria). Cela arrive : communes qui n’existent plus, translittérations, noms enregistrés dans un autre ordre.

Quand confirmable vaut true, demandez à la personne et répétez la requête avec codicefiscale_confirmed: true. Quand les deux noms et la date sont tous en désaccord, plus rien ne relie ce code à cette personne : confirmable vaut false et la seule issue est de le corriger.

import { VimineError } from '@vimine/sdk/server';
try {
await vimineServer.enroll(input);
} catch (err) {
const entry = err instanceof VimineError && err.errors?.find((e) => e.code === 'codicefiscale_mismatch');
if (!entry) throw err;
if (entry.confirmable && (await askThePerson(entry.mismatches, entry.hints))) {
await vimineServer.enroll({ ...input, codicefiscale_confirmed: true });
}
}

N’envoyez pas codicefiscale_confirmed de votre propre initiative : c’est une déclaration de la personne, et elle est enregistrée comme telle.

Une personne qui a adhéré sans code peut l’ajouter quand elle en a un, depuis son propre profil :

const me = await vimine.me.update({ codicefiscale: 'DPNMRA85C50Z110U' });
me.codicefiscale_check; // 'matched'

PATCH /v1/me accepte birth_country et codicefiscale_confirmed, en écriture seule ; codicefiscale peut aussi être remis à null. GET /v1/me dit comment la personne est identifiée :

codicefiscale_check
matched un code fiscal qui concorde avec les données de naissance de la personne
mismatch_confirmed un code en désaccord, confirmé par la personne
absent pas de code : la date, le lieu et le pays de naissance l’identifient
null pas encore identifiée : elle ne peut pas demander d’adhésion

matched signifie cohérent, pas vérifié auprès de l’administration fiscale : un code fiscal reste une donnée déclarée.

Un compte peut exister sans être identifié — une personne qui s’est inscrite seulement pour se connecter, par exemple. Quand une telle personne demande une adhésion, l’API le dit et nomme ce qui manque :

  • POST /v1/me/membership → 422 identification_required, avec errors[] = les données de naissance manquantes ({ field: 'birthplace', code: 'required' }…). Envoyez la personne compléter son profil avec PATCH /v1/me (autorisation profile:write) et répétez la requête.
  • POST /v1/enroll/confirm — le lien « confirmez votre demande » que reçoit le titulaire d’un compte existant → 409 identification_required, même errors[]. Demandez les données de naissance sur la page et renvoyez le jeton avec identification :
await publicApi().confirmEnrollment(token, { dob: '1985-03-10', birthplace: 'Lyon', birth_country: 'FR' });
// POST /v1/enroll/confirm { token, identification: { dob, birthplace, birth_country, codicefiscale?, codicefiscale_confirmed? } }

Les données de naissance voyagent dans le corps de la requête, jamais dans le lien : rien de personnel n’est jamais dans le lien. identification ne fait que compléter les champs vides du profil, elle n’écrase pas ce qui s’y trouve ; si elle ne tient pas, la réponse est un 422 validation_failed comme ci-dessus.

L’admission ne change pas : les pending_reasons sont ce que dit le modèle d’admission de l’association, pour tout le monde (voir Admission et activation).

Un code fiscal qui concorde avec les données de naissance peut être vérifié par rapport à elles ; les données de naissance seules, ou un code que la personne a confirmé, non. Pour ces membres, l’association regarde une pièce d’identité une fois, la première fois que la personne est là. Qui intègre un scanner le voit dans POST /v1/checkins (autorisation checkins:write), dans les réponses pour une carte :

const r = await vimineServer.checkins.create('vmt_…');
// { kind: 'card', verdict: 'valid', …, identity_check: 'pending' }
if (r.identity_check === 'pending') show('Première entrée : demandez une pièce d’identité');
identity_check
pending le membre n’a pas de code fiscal vérifiable et personne de l’association n’a encore regardé une pièce d’identité : affichez-le à la personne qui tient l’entrée
verified quelqu’un de l’association a regardé une pièce d’identité
flagged quelqu’un en a regardé une et elle ne concordait pas : le secrétariat de l’association prend la suite
null rien à vérifier

C’est une indication, elle ne fait pas partie de verdict et elle ne restreint rien : une carte valid avec identity_check: 'pending' entre. Le résultat est enregistré depuis la console de l’association, pas depuis l’API. La vérification publique GET /v1/verify/{card_token} ne le porte jamais : qui contrôle une carte depuis l’extérieur ne voit que l’état et l’échéance.

Certaines associations conservent l’adresse de leurs membres dans leur registre, d’autres non. Le choix appartient à l’association et vaut pour tous les membres ou pour aucun ; le profil public le déclare :

GET https://api.vimine.network/v1/aps/{slug}
→ { "aps": { …, "member_address": "optional" } }
member_address
none ne la demandez pas : une address envoyée malgré tout n’est pas conservée
optional demandez-la, sans la rendre obligatoire
required sans address, l’adhésion répond 422 avec { field: 'address', code: 'required' }
await vimineServer.enroll({
…,
address: { kind: 'residence', line: 'Via Roma 1', postal_code: '20121', city: 'Milano', province: 'MI', country: 'IT' }
});

line et city sont obligatoires dans address ; kind vaut residence (par défaut) ou domicile, quand il diffère de la résidence ; country vaut IT s’il est omis ; province ne concerne que les adresses italiennes. /v1/signup n’a pas d’address : l’adresse appartient à l’adhésion, pas au compte.

Il n’existe pas de réglage « code fiscal obligatoire ». Une association ne peut pas exiger un code fiscal de chaque personne qui adhère : qui n’en a pas est identifié par ses données de naissance, partout. Si votre formulaire le rend obligatoire, c’est un choix de votre formulaire — et il laisse de côté des personnes que l’association pourrait accueillir.

Tout est additif : un formulaire qui envoie toujours un code fiscal continue de fonctionner sans changement. Ce qu’une intégration existante peut remarquer :

  • codicefiscale n’est plus obligatoire dans POST /v1/enroll ; sans code, il faut dob, birthplace et birth_country (422 required sur chacun de ceux qui manquent) ;
  • nouveaux champs facultatifs birth_country, codicefiscale_confirmed (enroll, signup, PATCH /v1/me) et address (enroll) ;
  • gender n’est plus comparé avec le code : un 422 portant sur le seul sexe n’arrive plus ;
  • un code en désaccord répond toujours codicefiscale_mismatch, désormais avec hints et confirmable à côté de mismatches ; un code malformé reste invalid_codicefiscale ;
  • GET/PATCH /v1/me ont désormais un schéma déclaré (Me), avec birth_country et codicefiscale_check ;
  • une nouvelle erreur identification_required : 422 sur POST /v1/me/membership, 409 sur POST /v1/enroll/confirm (qui accepte identification dans le corps) ;
  • POST /v1/validate/fiscal-code accepte country et répond aussi hints, birth_date, birth_country ; error vaut invalid, mismatch ou null ;
  • POST /v1/checkins ajoute identity_check aux réponses pour une carte ; GET /v1/verify/{card_token} reste inchangé ;
  • le profil public ajoute aps.member_address.