Aller au contenu

Intégrations serveur

Afficher en Markdown

Pour les systèmes de l’association elle-même — logiciel de gestion, tourniquet, plugin de CMS — un client confidentiel avec client_id + client_secret. Le secret n’est affiché qu’une fois et ne doit jamais atteindre un navigateur.

Node
import { VimineServer } from '@vimine/sdk/server';
const vimineServer = new VimineServer({
clientId: 'vmc_…',
clientSecret: process.env.VIMINE_SECRET,
scopes: ['memberships:read']
});
const token = await vimineServer.token(); // client_credentials — jeton d’une heure, renouvelé de lui-même

Sans le SDK : POST /v1/oauth/token avec grant_type=client_credentials et HTTP Basic client_id:client_secret (ou client_id/client_secret dans le corps) :

Fenêtre de terminal
curl -u "vmc_…:vms_…" -d "grant_type=client_credentials&scope=memberships:read" \
https://api.vimine.network/v1/oauth/token

Sur les endpoints de lecture (/v1/memberships/{id}/status, /v1/memberships), HTTP Basic est aussi accepté directement, sans passer par un jeton, pour le matériel et les plateformes low-code — jamais depuis un navigateur.

const s = await vimineServer.memberships.status('membership-uuid');
// { id, status: 'active', verdict: 'valid', valid_until: '2027-…', membership_type: { cod: 'ORD' } }

Aucune donnée personnelle : l’état et la validité seulement. L’id est celui que le membre voit sur sa propre carte (membership.id via Se connecter avec Vimine) ou que votre système a reçu en l’enregistrant.

Pour vérifier une carte présentée à l’entrée, utilisez plutôt le jeton du QR avec /v1/verify/{card_token} : il ne demande aucune authentification.

Avec identity:signup et enroll:write, votre back-office peut créer des comptes et envoyer des demandes d’adhésion sans que la personne passe par Vimine : elle reçoit par e-mail le lien pour confirmer son adresse et choisir un mot de passe.

// Le compte seulement (la personne n’est pas encore membre)
await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi' });
// Compte + demande d’adhésion en attente, approuvée par le secrétariat dans le back-office Vimine
const { statuto, membership_types } = await vimineServer.public.association('your-slug');
await vimineServer.enroll({
email: 'mario.rossi@example.org',
first_name: 'Mario',
last_name: 'Rossi',
codicefiscale: 'RSSMRA80A01H501U', // facultatif : sans lui, il faut dob + birthplace + birth_country
dob: '1980-01-01', birthplace: 'Roma', birth_country: 'IT',
gender: 'M', // démographique seulement : il n’est pas comparé avec le code
membership_type: membership_types[0].uid, // facultatif quand il y a exactement un type
accept_statuto: { version: statuto.version, sha256: statuto.sha256 },
privacy_notice: privacy_notice && { version: privacy_notice.version, sha256: privacy_notice.sha256 } // obligatoire quand l’association en publie une
});

La réponse est toujours 202 { status: 'accepted' }, quoi qu’il y ait derrière l’adresse : vous ne pouvez pas savoir si un e-mail a déjà un compte Vimine (seul son titulaire en est informé, par e-mail). Concrètement :

  • nouvelle adresse → compte créé et, avec enroll, une demande d’adhésion en attente ; e-mail de bienvenue avec la confirmation de l’adresse ;
  • adresse déjà enregistrée → avec enroll, rien n’est écrit : le titulaire reçoit un lien « confirmez votre demande à <association> » valable 24 heures, et la demande n’est créée que lorsqu’il l’utilise. S’il est déjà membre, il ne se passe rien ;
  • les erreurs 422 ne concernent que votre payload (validation_failed avec errors[].field, statuto_outdated, invalid_type) ; 403 api_disabled quand l’association n’accepte pas de demandes ; 403 not_available pendant la bêta privée, tant que les comptes ne sont créés que sur invitation.

Une personne est identifiée par un code fiscal ou par sa date, son lieu et son pays de naissance (dob, birthplace, birth_country) — jamais ni l’un ni l’autre : sans code, chaque donnée manquante est une entrée required dans errors[]. Pour une personne née à l’étranger, envoyez toujours birth_country : son code ne contient que l’État. Un code en désaccord avec les données de naissance répond 422 avec une entrée codicefiscale_mismatch qui porte mismatches, hints et confirmable : quand confirmable vaut true, la personne peut le confirmer, et vous répétez l’appel avec codicefiscale_confirmed: true. Quand l’association recueille l’adresse de ses membres (aps.member_address dans le profil public), ajoutez address. Quand elle recueille les données de la personne qui exerce l’autorité parentale (aps.collects_guardian_data) et que la personne est mineure d’après dob, guardian est obligatoire — first_name, last_name, relation, et facultativement codicefiscale, email, phone — sinon 422 avec guardian: required. Le parcours complet est dans Membres sans code fiscal.

accept_statuto doit nommer le statuto en vigueur : montrez-le à la personne sur votre site (il est dans association(slug) ; le texte et le document dans GET /v1/aps/{slug}/statuto) et passez la version qu’elle a acceptée. Une association qui n’a enregistré aucun statuto lisible répond accepting_requests: false, et la demande 403 not_available. Il en va de même pour la notice d’information sur la vie privée destinée aux membres de l’association (privacy_notice dans association(slug), le texte sur GET /v1/aps/{slug}/privacy-notice) : quand l’association en publie une, la demande doit nommer la version que la personne a lue, sinon 422 (privacy_notice manquante ou privacy_notice_outdated) ; la prise de connaissance est enregistrée au nom de la personne, en nommant votre client. Facultatifs, même règle : accept_terms et acknowledge_privacy (les conditions du compte et la notice d’information de la plateforme, GET /v1/legal/{kind}) quand la personne les a acceptées sur votre site. Les appels sont idempotents : le SDK génère une Idempotency-Key par appel, ou passez la vôtre ({ idempotencyKey: 'order-42' }) pour réessayer sans risque après un délai dépassé. Les e-mails sont plafonnés (3 par adresse et par jour) et ne sont jamais envoyés depuis la sandbox.

Avec checkins:write, un appareil à l’entrée enregistre le passage d’un membre en envoyant le jeton lu sur le QR de la carte (pas un identifiant) : la réponse est le verdict seul, sans données personnelles. HTTP Basic est accepté directement, pour le matériel et les plateformes low-code.

const r = await vimineServer.checkins.create('vmt_…'); // { verdict: 'valid' | 'expired' | 'not_yet_valid' | 'statuto_required' | 'inactive', status, membership_id, valid_until, identity_check, checked_in_at }
Fenêtre de terminal
curl -u "vmc_…:vms_…" -H "Content-Type: application/json" -d '{"token":"vmt_…"}' https://api.vimine.network/v1/checkins

Le corps est { "token": "vmt_…" } — le jeton lu sur le QR, d’une carte ou d’une inscription à un événement ; pour les cartes seulement, card est accepté comme alias.

Un jeton malformé ou falsifié donne 422 invalid_card ; la carte d’une autre association est « introuvable ».

identity_check: 'pending' est une indication pour la personne qui tient l’entrée : 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-la ; elle ne fait pas partie de verdict et ne restreint rien (voir le contrôle d’identité).

vimineServer.memberships.list({ status?, updated_since?, limit?, cursor? }) renvoie les identifiants, l’état et les dates — jamais de données personnelles — par pages (next_cursor). Avec updated_since, vous ne synchronisez que ce qui a changé. Sur les formules qui ne l’incluent pas, la réponse est 403 plan_limit.

Depuis la console (Régénérer le secret) : le nouveau secret n’est affiché qu’une fois, l’ancien continue de fonctionner pendant 24 heures, pour que vous puissiez mettre à jour vos systèmes sans interruption. Si vous soupçonnez une compromission, révoquez le client : toutes ses sessions prennent fin immédiatement.

  • Un secret erroné, répété, bloque le client pendant 15 minutes.
  • Chaque jeton est lié à l’association du client : une carte d’une autre association est simplement « introuvable ».
  • Un 401 avec des identifiants tout juste régénérés est réessayé une fois par le SDK avec un nouveau jeton.
  • Les réponses sont en application/problem+json (voir Autorisations, erreurs et limites).