Embed e verifica tessere
Il modulo di tesseramento nel tuo sito
Sezione intitolata “Il modulo di tesseramento nel tuo sito”Ogni associazione che ha attivato il tesseramento pubblico ha una pagina
https://app.vimine.network/enroll/<slug> che può essere inserita in un iframe nel sito dell’associazione:
<iframe src="https://app.vimine.network/enroll/tuo-slug" style="width:100%;min-height:900px;border:0"></iframe>L’associazione deve elencare il dominio del sito tra i domini di incorporamento nelle proprie impostazioni. La pagina di accesso e consenso di Accedi con Vimine invece non può essere inserita in un iframe: è sempre una pagina a tutto schermo su vimine.network.
?locale=en apre il modulo in inglese (l’elemento <vimine-enroll> lo passa da solo, dalla lingua della pagina).
L’aspetto del modulo
Sezione intitolata “L’aspetto del modulo”Il modulo può prendere i colori del tuo sito. Una pagina in un iframe non vede il CSS di chi la ospita, quindi lo stile viaggia nell’indirizzo:
| Parametro | Valori | |
|---|---|---|
scheme |
light, dark |
lo schema della pagina; senza, quello dello sfondo o del visitatore |
accent |
un colore esadecimale (1e3a5f) |
pulsanti, link, campi attivi e il nome dell’associazione |
background |
un colore esadecimale, o transparent |
lo sfondo dietro le schede; transparent lascia vedere la tua pagina |
font |
inter, roboto, open-sans, montserrat, nunito, lora, merriweather, roboto-slab, system |
il carattere di tutta la pagina, campi compresi, tra quelli che Vimine serve da sé (system: quello del dispositivo) |
<iframe src="https://app.vimine.network/enroll/tuo-slug?scheme=light&accent=1e3a5f&background=transparent" style="width:100%;min-height:900px;border:0"></iframe>Altri valori sono ignorati. Con <vimine-enroll> non serve scrivere l’indirizzo: imposti --vimine-scheme,
--vimine-accent, --vimine-background e --vimine-typeface nel tuo CSS (elementi). Con transparent scegli lo schema
che si legge sulla tua pagina: le schede del modulo hanno il loro fondo, il testo fuori dalle schede sta sul tuo.
Chi ha già un account Vimine
Sezione intitolata “Chi ha già un account Vimine”Un’identità vale per tutte le associazioni: chi ha già un account non deve ricompilare il modulo. Aperta direttamente,
la pagina …/enroll/<slug> riconosce la sessione e mostra una sola schermata — il tipo di tessera, lo statuto e
l’informativa privacy di questa associazione, e soltanto ciò che questa associazione chiede in più (l’indirizzo, se
ha dichiarato di raccoglierlo). Statuto e informativa si accettano ogni volta: nulla passa da un’associazione all’altra.
Dentro un iframe la sessione non è leggibile: il browser tiene separata una pagina incorniciata dallo stesso sito aperto
direttamente. Per questo il modulo incorniciato offre Hai già un account Vimine? Continua su Vimine, che apre la
pagina in una nuova scheda. Se scrivi l’iframe a mano e usi sandbox, includi allow-popups e
allow-popups-to-escape-sandbox, altrimenti quella scheda resta chiusa nella sandbox; <vimine-enroll> lo fa già.
Il profilo pubblico
Sezione intitolata “Il profilo pubblico”GET /v1/aps/{slug} restituisce il profilo pubblico dell’associazione — grafica, tipi di tessera con le quote,
statuto in vigore — se vuoi costruire un’esperienza tua:
import { publicApi } from '@vimine/sdk';
const { aps, membership_types, statuto } = await publicApi().association('tuo-slug');Nessuna credenziale. Da una pagina in cui il socio ha fatto Accedi con Vimine puoi poi raccogliere la richiesta:
const { aps, membership_types, statuto, privacy_notice } = await publicApi().association('tuo-slug');
await vimine.membership.request({ membership_type, accept_statuto: { version: statuto.version }, // l'informativa privacy dell'associazione, che la tua pagina ha mostrato privacy_notice: privacy_notice && { version: privacy_notice.version, sha256: privacy_notice.sha256, locale: privacy_notice.locale }, // l'indirizzo, se l'associazione lo raccoglie (aps.member_address: 'optional' | 'required') address: { line: 'Via Roma 1', postal_code: '20100', city: 'Milano', province: 'MI' }});Quello che un’associazione chiede a chi aderisce non dipende dalla porta da cui arriva la richiesta:
- l’informativa privacy. Finché l’associazione ne ha una in vigore che la persona non ha ancora visto,
privacy_noticeè obbligatorio: senza,422 validation_failedsul campoprivacy_notice; con una versione non più in vigore,422 privacy_notice_outdated.vimine.legal.acceptances()dice cosa è ancora da confermare; il testo èGET /v1/aps/{slug}/privacy-notice. La presa visione resta come riga di prova legata a questa tessera. - l’indirizzo.
aps.member_addressdice se l’associazione lo raccoglie: conrequired, senzaaddressla richiesta risponde422 validation_failedsul campoaddress; connoneviene ignorato. - chi è la persona. Se il profilo non è ancora identificato — né un codice fiscale, né data, luogo e Stato di
nascita — la richiesta risponde
422 identification_required: completa il profilo convimine.me.update(...)e ripeti (vedi Soci senza codice fiscale).
Verifica tessere
Sezione intitolata “Verifica tessere”La tessera digitale è un token firmato (vmt_…) che il socio mostra come QR. È verificabile in due modi.
Nessuna credenziale, nessun dato personale nella risposta:
GET https://api.vimine.network/v1/verify/vmt_…→ { "status": "active", "valid_until": "2027-03-31T22:59:59.000Z" } oppure→ { "status": "inactive", "reason": "expired" } oppure→ { "status": "inactive", "reason": "not_yet_valid", "valid_from": "2026-09-19T19:00:00.000Z" }not_yet_valid: la tessera è autentica e l’adesione è attiva, ma l’ente ha stabilito un intervallo tra l’ammissione e
l’utilizzabilità della tessera. valid_from dice da quando vale; fino ad allora, alla porta, è una tessera che non
conta. Lo stesso istante è nel token (nbf), quindi uno scanner offline arriva alla stessa risposta da solo.
import { publicApi } from '@vimine/sdk';
const { status } = await publicApi().verifyCard(tokenLettoDalQr);Offline
Sezione intitolata “Offline”Il token è firmato con Ed25519; le chiavi pubbliche stanno su
https://api.vimine.network/.well-known/vimine-card-keys.json (anche GET /v1/card-keys, o
publicApi().cardKeys()). Uno scanner verifica tre cose, con la chiave in cache: la firma, la finestra di validità (nbf/exp, al massimo
90 giorni, poi il token ruota) e che lo stato nel payload sia attivo — s === "active". Poi si riallinea online
quando torna la rete. Un kid sconosciuto
significa che la chiave è ruotata: ricarica le chiavi.
Il token ruota a ogni cambio di stato, a ogni rinnovo e comunque ogni 90 giorni: uno screenshot vecchio non apre nulla per sempre.
Una tessera esiste solo per un’adesione attiva: finché la domanda è in attesa (di ammissione o della quota), e
quando l’adesione è sospesa o revocata, l’API non rilascia alcun token — card è null in GET /v1/me/membership,
e GET /v1/me/membership/card, l’immagine, l’e-mail e il link a Google Wallet rispondono 409 not_active. Il
controllo di s resta obbligatorio: rifiuta i token emessi prima di questa regola e qualunque token che non dichiari
uno stato attivo. Rispetta anche nbf: un ente può stabilire che la tessera diventi utilizzabile qualche ora dopo
l’ammissione, e quell’istante viaggia lì.
Codice fiscale
Sezione intitolata “Codice fiscale”Il codice fiscale è facoltativo: chi non ne ha uno si iscrive con data, luogo e Stato di nascita (vedi
Soci senza codice fiscale). Quando c’è, POST /v1/validate/fiscal-code (o
publicApi().validateFiscalCode(...)) controlla struttura e carattere di controllo e, se passi anche i dati
anagrafici, la loro coerenza con il codice — e dice che cosa il codice stesso contiene:
const r = await publicApi().validateFiscalCode({ code: 'RSSMRA80A01H501U', first_name: 'Mario', last_name: 'Rossi', date: '1980-01-01', place: 'Roma', country: 'IT' });// { valid: true, error: null, mismatches: [], hints: [], birth_date: '1980-01-01', birth_country: 'IT' }// oppure// { valid: false, error: 'mismatch', mismatches: ['date'], hints: [], birth_date: '1980-01-01', birth_country: 'IT' }error vale invalid (struttura o carattere di controllo), mismatch (un codice ben formato che non concorda con i
dati inviati) o null; hints contiene names_swapped quando il codice torna scambiando nome e cognome. Per chi è
nato all’estero invia country (ISO 3166-1 alpha-2): il suo codice contiene solo lo Stato, e place — la città — non
viene confrontato.