Zum Inhalt springen

Einbetten und Ausweisprüfung

Als Markdown anzeigen

Jeder Verein, der den öffentlichen Beitritt aktiviert hat, hat eine Seite https://app.vimine.network/enroll/<slug>, die sich in einem iframe auf der Website des Vereins platzieren lässt:

<iframe src="https://app.vimine.network/enroll/your-slug" style="width:100%;min-height:900px;border:0"></iframe>

Der Verein muss die Domain der Website in seinen Einstellungen unter seinen Einbettungsdomains eintragen. Die Anmelde- und Einwilligungsseite von Mit Vimine anmelden dagegen lässt sich nicht in einen iframe setzen: Sie ist immer eine ganze Seite auf vimine.network.

?locale=en öffnet das Formular auf Englisch (das Element <vimine-enroll> übergibt es selbst, aus der Sprache der Seite).

Das Formular kann die Farben Ihrer Website übernehmen. Eine Seite in einem iframe sieht das CSS der umgebenden Seite nicht, also reist der Stil in der Adresse mit:

Parameter Werte
scheme light, dark das Farbschema der Seite; ohne den Parameter das des Hintergrunds oder des Besuchers
accent eine Hex-Farbe (1e3a5f) Schaltflächen, Links, fokussierte Felder und der Name des Vereins
background eine Hex-Farbe oder transparent der Grund hinter den Karten; transparent lässt Ihre Seite durchscheinen
font inter, roboto, open-sans, montserrat, nunito, lora, merriweather, roboto-slab, system die Schrift der ganzen Seite, Felder eingeschlossen, unter denen, die Vimine selbst ausliefert (system: die des Geräts)
<iframe src="https://app.vimine.network/enroll/your-slug?scheme=light&accent=1e3a5f&background=transparent"
style="width:100%;min-height:900px;border:0"></iframe>

Andere Werte werden ignoriert. Mit <vimine-enroll> gibt es keine Adresse zu schreiben: Setzen Sie --vimine-scheme, --vimine-accent, --vimine-background und --vimine-typeface in Ihrem CSS (Elemente). Mit transparent wählen Sie das Farbschema, das auf Ihrer Seite lesbar ist: Die Karten des Formulars haben ihre eigene Füllung, der Text außerhalb liegt auf Ihrer.

Eine Identität gilt für jeden Verein: Wer schon ein Konto hat, muss das Formular nicht noch einmal ausfüllen. Direkt geöffnet, erkennt die Seite …/enroll/<slug> die Sitzung und zeigt einen einzigen Bildschirm — die Mitgliedsart, das Statuto und die Datenschutzhinweise dieses Vereins, und nur das, was dieser Verein zusätzlich verlangt (die Adresse, wenn er erklärt hat, dass er sie erfasst). Statuto und Datenschutzhinweise werden jedes Mal akzeptiert: Nichts geht von einem Verein auf einen anderen über.

In einem iframe lässt sich die Sitzung nicht lesen: Ein Browser hält eine eingebettete Seite getrennt von derselben direkt geöffneten Website. Deshalb bietet das eingebettete Formular Haben Sie schon ein Vimine-Konto? Weiter auf Vimine an, das die Seite in einem neuen Tab öffnet. Wenn Sie den iframe von Hand schreiben und sandbox verwenden, nehmen Sie allow-popups und allow-popups-to-escape-sandbox auf, sonst bleibt dieser Tab in der Sandbox gefangen; <vimine-enroll> tut das bereits.

GET /v1/aps/{slug} liefert das öffentliche Profil des Vereins — Erscheinungsbild, Mitgliedsarten mit ihren Beiträgen, geltendes Statuto —, falls Sie ein eigenes Erlebnis bauen wollen:

import { publicApi } from '@vimine/sdk';
const { aps, membership_types, statuto } = await publicApi().association('your-slug');

Ohne Zugangsdaten. Auf einer Seite, auf der sich das Mitglied mit Mit Vimine anmelden angemeldet hat, können Sie dann den Antrag entgegennehmen:

const { aps, membership_types, statuto, privacy_notice } = await publicApi().association('your-slug');
await vimine.membership.request({
membership_type,
accept_statuto: { version: statuto.version },
// die Datenschutzhinweise des Vereins, die Ihre Seite gezeigt hat
privacy_notice: privacy_notice && { version: privacy_notice.version, sha256: privacy_notice.sha256, locale: privacy_notice.locale },
// die Adresse, wenn der Verein sie erfasst (aps.member_address: 'optional' | 'required')
address: { line: 'Via Roma 1', postal_code: '20100', city: 'Milano', province: 'MI' }
});

Was ein Verein von einer antragstellenden Person verlangt, hängt nicht davon ab, über welchen Weg der Antrag kommt:

  • die Datenschutzhinweise. Solange der Verein welche in Kraft hat, die die Person noch nicht gesehen hat, ist privacy_notice Pflicht: ohne sie 422 validation_failed auf dem Feld privacy_notice; mit einer Version, die nicht mehr in Kraft ist, 422 privacy_notice_outdated. vimine.legal.acceptances() sagt, was noch zu bestätigen ist; der Text ist GET /v1/aps/{slug}/privacy-notice. Die Kenntnisnahme wird als Nachweis gespeichert, an diese Mitgliedschaft gebunden.
  • die Adresse. aps.member_address sagt, ob der Verein sie erfasst: Bei required ergibt ein Antrag ohne address die Antwort 422 validation_failed auf dem Feld address; bei none wird sie ignoriert.
  • wer die Person ist. Ist das Profil noch nicht identifiziert — weder Steuernummer noch Geburtsdatum, Geburtsort und Geburtsland —, antwortet der Antrag mit 422 identification_required: Vervollständigen Sie das Profil mit vimine.me.update(...) und wiederholen Sie (siehe Mitglieder ohne Steuernummer).

Der digitale Ausweis ist ein signiertes Token (vmt_…), das das Mitglied als QR-Code vorzeigt. Es lässt sich auf zwei Arten prüfen.

Ohne Zugangsdaten, ohne personenbezogene Daten in der Antwort:

GET https://api.vimine.network/v1/verify/vmt_…
→ { "status": "active", "valid_until": "2027-03-31T22:59:59.000Z" }
oder
→ { "status": "inactive", "reason": "expired" }
oder
→ { "status": "inactive", "reason": "not_yet_valid", "valid_from": "2026-09-19T19:00:00.000Z" }

not_yet_valid: Der Ausweis ist echt und die Mitgliedschaft aktiv, aber die Organisation hat eine Frist zwischen Aufnahme und Nutzbarkeit des Ausweises festgelegt. valid_from sagt, ab wann er gilt; bis dahin ist er am Einlass ein Ausweis, der nicht gilt. Derselbe Zeitpunkt steht im Token (nbf), sodass ein Offline-Scanner allein zur selben Antwort kommt.

import { publicApi } from '@vimine/sdk';
const { status } = await publicApi().verifyCard(tokenReadFromQr);

Das Token ist mit Ed25519 signiert; die öffentlichen Schlüssel liegen unter https://api.vimine.network/.well-known/vimine-card-keys.json (auch GET /v1/card-keys oder publicApi().cardKeys()). Ein Scanner prüft mit dem zwischengespeicherten Schlüssel drei Dinge: die Signatur, das Gültigkeitsfenster (nbf/exp, höchstens 90 Tage, dann rotiert das Token) und dass der Status in den Nutzdaten aktiv ist — s === "active". Dann synchronisiert er sich online, sobald das Netz wieder da ist. Eine unbekannte kid bedeutet, dass der Schlüssel rotiert wurde: Laden Sie die Schlüssel neu.

Das Token rotiert bei jeder Statusänderung, bei jeder Verlängerung und spätestens alle 90 Tage: Ein alter Screenshot öffnet nichts für immer.

Einen Ausweis gibt es nur für eine aktive Mitgliedschaft: Solange der Antrag aussteht (Aufnahme oder Beitrag) und wenn die Mitgliedschaft ausgesetzt oder widerrufen ist, stellt die API kein Token aus — card ist null in GET /v1/me/membership, und GET /v1/me/membership/card, das Bild, die E-Mail und der Google-Wallet-Link antworten 409 not_active. Die Prüfung von s bleibt Pflicht: Sie weist Tokens ab, die vor dieser Regel ausgestellt wurden, und jedes Token, das keinen aktiven Status angibt. Beachten Sie auch nbf: Eine Organisation kann entscheiden, dass ein Ausweis erst einige Stunden nach der Aufnahme nutzbar wird, und dieser Zeitpunkt reist dort mit.

Die Steuernummer ist optional: Wer keine hat, tritt mit Geburtsdatum, Geburtsort und Geburtsland bei (siehe Mitglieder ohne Steuernummer). Wenn es eine gibt, prüft POST /v1/validate/fiscal-code (oder publicApi().validateFiscalCode(...)) Aufbau und Prüfzeichen eines italienischen Codice fiscale und, wenn Sie auch die persönlichen Daten übergeben, deren Übereinstimmung mit der Steuernummer — und sagt, was die Steuernummer selbst enthält:

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' }
// oder
// { valid: false, error: 'mismatch', mismatches: ['date'], hints: [], birth_date: '1980-01-01', birth_country: 'IT' }

error ist invalid (Aufbau oder Prüfzeichen), mismatch (eine korrekt aufgebaute Steuernummer, die nicht zu den gesendeten Daten passt) oder null; hints enthält names_swapped, wenn die Steuernummer passt, sobald Nachname und Vorname vertauscht werden. Für eine im Ausland geborene Person senden Sie country (ISO 3166-1 alpha-2): Ihre Steuernummer enthält nur den Staat, und place — die Stadt — wird nicht verglichen.