Salta ai contenuti

Integrazioni server

Apri come Markdown

Per i sistemi dell’associazione stessa — gestionale, tornello, plugin del CMS — un client riservato con client_id + client_secret. Il secret è mostrato una sola volta e non deve mai raggiungere un browser.

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 — token di 1 ora, rinnovato da solo

Senza SDK: POST /v1/oauth/token con grant_type=client_credentials e HTTP Basic client_id:client_secret (o client_id/client_secret nel corpo):

Finestra del terminale
curl -u "vmc_…:vms_…" -d "grant_type=client_credentials&scope=memberships:read" \
https://api.vimine.network/v1/oauth/token

Sugli endpoint di lettura (/v1/memberships/{id}/status, /v1/memberships) è accettato anche HTTP Basic direttamente, senza passare dal token, per hardware e piattaforme low-code — mai da un browser.

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

Nessun dato personale: solo stato e validità. L’id è quello che il socio vede nella propria tessera (membership.id via Accedi con Vimine) o che il tuo sistema ha ricevuto quando l’ha registrata.

Per verificare una tessera mostrata allo scanner usa invece il token del QR con /v1/verify/{card_token}: non serve nemmeno autenticarsi.

Con identity:signup e enroll:write il tuo gestionale può creare account e inviare richieste di tesseramento senza che la persona passi da Vimine: riceverà per e-mail il link per confermare l’indirizzo e scegliere la password.

// Solo l'account (la persona non è ancora socia)
await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi' });
// Account + richiesta di tessera in attesa, che la segreteria approva dal gestionale Vimine
const { statuto, membership_types } = await vimineServer.public.association('tuo-slug');
await vimineServer.enroll({
email: 'mario.rossi@example.org',
first_name: 'Mario',
last_name: 'Rossi',
codicefiscale: 'RSSMRA80A01H501U', // facoltativo: senza, servono dob + birthplace + birth_country
dob: '1980-01-01', birthplace: 'Roma', birth_country: 'IT',
gender: 'M', // solo statistico: non viene confrontato con il codice
membership_type: membership_types[0].uid, // facoltativo se il tipo è uno solo
accept_statuto: { version: statuto.version, sha256: statuto.sha256 },
privacy_notice: privacy_notice && { version: privacy_notice.version, sha256: privacy_notice.sha256 } // obbligatorio se l'associazione ne pubblica una
});

La risposta è sempre 202 { status: 'accepted' }, qualunque cosa ci sia dietro l’indirizzo: non puoi sapere se un’e-mail ha già un account Vimine (lo sa solo il suo titolare, per posta). In particolare:

  • indirizzo nuovo → account creato e, con enroll, richiesta di tessera in attesa; mail di benvenuto con la conferma dell’indirizzo;
  • indirizzo già registrato → con enroll non viene scritto nulla: il titolare riceve un link «conferma la richiesta a <associazione>» valido 24 ore, e la richiesta nasce solo quando lo usa. Se è già socio, non succede niente;
  • errori 422 riguardano solo il tuo payload (validation_failed con errors[].field, statuto_outdated, invalid_type); 403 api_disabled se l’associazione non accetta richieste; 403 not_available durante la beta privata, quando gli account nascono solo su invito.

Una persona si identifica con il codice fiscale oppure con data, luogo e Stato di nascita (dob, birthplace, birth_country) — mai nessuno dei due: senza codice, ogni dato mancante è una voce required in errors[]. Per chi è nato all’estero invia sempre birth_country: il suo codice contiene solo lo Stato. Un codice che non concorda con i dati risponde 422 con una voce codicefiscale_mismatch che porta mismatches, hints e confirmable: quando confirmable è true la persona può confermarlo, e tu ripeti la chiamata con codicefiscale_confirmed: true. Se l’associazione raccoglie l’indirizzo dei soci (aps.member_address nel profilo pubblico) aggiungi address. Se raccoglie i dati di chi esercita la responsabilità genitoriale (aps.collects_guardian_data) e la persona è minorenne per dob, guardian è obbligatorio — first_name, last_name, relation, e facoltativi codicefiscale, email, phone — altrimenti 422 con guardian: required. Tutto il percorso è in Soci senza codice fiscale.

accept_statuto deve indicare lo statuto in vigore: mostralo alla persona sul tuo sito (lo trovi in association(slug); il testo e il documento in GET /v1/aps/{slug}/statuto) e passa la versione che ha accettato. Un’associazione che non ha registrato uno statuto leggibile risponde accepting_requests: false e la richiesta 403 not_available. Lo stesso vale per l’informativa privacy ai soci (privacy_notice in association(slug), il testo in GET /v1/aps/{slug}/privacy-notice): quando l’associazione ne pubblica una la richiesta deve indicarne la versione letta, altrimenti 422 (privacy_notice mancante o privacy_notice_outdated); la presa visione viene registrata a nome della persona, con il tuo client indicato. Facoltativi ma con la stessa regola: accept_terms e acknowledge_privacy (le condizioni dell’account e l’informativa della piattaforma, GET /v1/legal/{kind}), se la persona le ha accettate sul tuo sito. Le chiamate sono idempotenti: l’SDK genera una Idempotency-Key per ogni chiamata, oppure passane una tua ({ idempotencyKey: 'ordine-42' }) per ripetere in sicurezza dopo un timeout. Le mail sono contingentate (3 al giorno per indirizzo) e mai inviate dalla sandbox.

Con checkins:write un dispositivo agli ingressi registra il passaggio di un socio inviando il token letto dal QR della tessera (non un identificativo): la risposta è solo il verdetto, senza dati personali. HTTP Basic è accettato direttamente, per hardware e piattaforme 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 }
Finestra del terminale
curl -u "vmc_…:vms_…" -H "Content-Type: application/json" -d '{"token":"vmt_…"}' https://api.vimine.network/v1/checkins

Il corpo è { "token": "vmt_…" } — il token letto dal QR, di una tessera o dell’iscrizione a un evento; per le sole tessere card è accettato come sinonimo.

Un token malformato o contraffatto è un 422 invalid_card; una tessera di un’altra associazione è «non trovata».

identity_check: 'pending' è una nota per chi è all’ingresso: il socio non ha un codice fiscale verificabile e nessuno dell’associazione ha ancora visto un documento. Mostrala; non fa parte di verdict e non limita nulla (vedi il controllo d’identità).

vimineServer.memberships.list({ status?, updated_since?, limit?, cursor? }) restituisce identificativi, stato e date — mai dati personali — a pagine (next_cursor). Con updated_since sincronizzi solo ciò che è cambiato. Sui piani che non lo includono la risposta è 403 plan_limit.

Dalla console (Rigenera secret): il nuovo secret è mostrato una volta, il precedente continua a funzionare per 24 ore, così puoi aggiornare i tuoi sistemi senza interruzioni. Se sospetti una compromissione, revoca il client: tutte le sue sessioni terminano subito.

  • Un secret sbagliato più volte blocca il client per 15 minuti.
  • Ogni token è legato all’associazione del client: una tessera di un’altra associazione è semplicemente «non trovata».
  • Una risposta 401 con credenziali appena ruotate viene ritentata una volta dall’SDK con un token nuovo.
  • Le risposte usano application/problem+json (vedi Permessi, errori e limiti).