# Server-Integrationen

> Vertrauliche Clients für die eigenen Systeme des Vereins, client_credentials, Ausweisstatus, Rotation des Secrets.

URL: https://developers.vimine.network/de/guides/server/

Für die Systeme **des Vereins selbst** — eine Verwaltungssoftware, ein Drehkreuz, ein CMS-Plugin — ein
**vertraulicher** Client mit `client_id` + `client_secret`. Das Secret wird einmal angezeigt und darf nie in einen
Browser gelangen.

## Authentifizieren

```js title="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 für 1 Stunde, erneuert sich selbst
```

Ohne das SDK: `POST /v1/oauth/token` mit `grant_type=client_credentials` und HTTP Basic
`client_id:client_secret` (oder `client_id`/`client_secret` im Body):

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

Bei den lesenden Endpunkten (`/v1/memberships/{id}/status`, `/v1/memberships`) wird HTTP Basic auch **direkt**
akzeptiert, ohne den Umweg über ein Token, für Hardware und Low-Code-Plattformen — nie aus einem Browser.

## Status eines Ausweises

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

Keine personenbezogenen Daten: nur Status und Gültigkeit. Die `id` ist die, die das Mitglied auf seinem eigenen Ausweis sieht
(`membership.id` über *Mit Vimine anmelden*), oder die, die Ihr System bei der Erfassung erhalten hat.

Um einen **am Einlass gezeigten** Ausweis zu prüfen, verwenden Sie stattdessen das QR-Token mit
[`/v1/verify/{card_token}`](https://developers.vimine.network/de/guides/embed-and-verify/): Es braucht überhaupt keine Authentifizierung.

## Beitritte aus Ihrem System

Mit `identity:signup` und `enroll:write` kann Ihr Backoffice Konten anlegen und Beitrittsanträge stellen,
**ohne dass die Person über Vimine geht**: Sie erhält per E-Mail den Link, um die Adresse zu bestätigen und ein
Passwort zu wählen.

```js
// Nur das Konto (die Person ist noch nicht Mitglied)
await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi' });

// Konto + ausstehender Beitrittsantrag, den das Sekretariat in der Vimine-Verwaltung genehmigt
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',      // optional: ohne sie sind dob + birthplace + birth_country nötig
    dob: '1980-01-01', birthplace: 'Roma', birth_country: 'IT',
    gender: 'M',                              // nur statistisch: wird nicht mit der Steuernummer abgeglichen
    membership_type: membership_types[0].uid, // optional, wenn es genau eine Art gibt
    accept_statuto: { version: statuto.version, sha256: statuto.sha256 },
    privacy_notice: privacy_notice && { version: privacy_notice.version, sha256: privacy_notice.sha256 } // Pflicht, wenn der Verein Datenschutzhinweise veröffentlicht
});
```

Die Antwort ist **immer** `202 { status: 'accepted' }`, was auch immer hinter der Adresse steht: Sie können nicht erfahren, ob
eine E-Mail-Adresse schon ein Vimine-Konto hat (nur ihr Inhaber erfährt es, per E-Mail). Im Einzelnen:

- **neue Adresse** → Konto angelegt und, mit `enroll`, ein *ausstehender* Beitrittsantrag; Willkommens-E-Mail mit der
  Bestätigung der Adresse;
- **bereits registrierte Adresse** → mit `enroll` wird nichts geschrieben: Der Inhaber erhält einen Link „Bestätigen Sie Ihren Antrag
  an *<Verein>*“, 24 Stunden gültig, und der Antrag entsteht erst, wenn er ihn verwendet. Ist er bereits
  Mitglied, geschieht nichts;
- `422`-Fehler betreffen nur *Ihre* Nutzdaten (`validation_failed` mit `errors[].field`, `statuto_outdated`,
  `invalid_type`); `403 api_disabled`, wenn der Verein keine Anträge annimmt; `403 not_available` während der
  [privaten Beta](https://developers.vimine.network/de/guides/scopes-and-errors/#die-private-beta), solange Konten nur auf Einladung angelegt werden.

Eine Person wird über eine **Steuernummer oder** über Geburtsdatum, Geburtsort und Geburtsland (`dob`, `birthplace`,
`birth_country`) identifiziert — nie über keins von beidem: Ohne Steuernummer ist jede fehlende Geburtsangabe ein Eintrag `required` in `errors[]`. Für eine
im Ausland geborene Person senden Sie immer `birth_country`: Ihre Steuernummer enthält nur den Staat. Eine Steuernummer, die nicht zu den
Geburtsdaten passt, ergibt `422` mit einem Eintrag `codicefiscale_mismatch`, der `mismatches`, `hints` und `confirmable` enthält: Ist
`confirmable` gleich `true`, darf die Person sie bestätigen, und Sie wiederholen den Aufruf mit `codicefiscale_confirmed: true`. Wenn
der Verein die Adresse seiner Mitglieder erfasst (`aps.member_address` im öffentlichen Profil), fügen Sie `address` hinzu. Wenn er
die Daten der sorgeberechtigten Person erfasst (`aps.collects_guardian_data`) und die Person laut
`dob` minderjährig ist, ist `guardian` Pflicht — `first_name`, `last_name`, `relation`, optional `codicefiscale`, `email`, `phone` —
sonst `422` mit `guardian: required`. Der ganze Weg steht in
[Mitglieder ohne Steuernummer](https://developers.vimine.network/de/guides/members-without-cf/).

`accept_statuto` muss das **geltende** Statuto nennen: Zeigen Sie es der Person auf Ihrer Website (es steht in
[`association(slug)`](https://developers.vimine.network/de/sdk/public/); Text und Dokument unter `GET /v1/aps/{slug}/statuto`) und übergeben Sie die
Version, die sie akzeptiert hat. Ein Verein, der kein lesbares Statuto hinterlegt hat, antwortet mit `accepting_requests: false`, und
der Antrag mit `403 not_available`. Dasselbe gilt für die
**Datenschutzhinweise des Vereins für seine Mitglieder** (`privacy_notice` in `association(slug)`, der Text unter `GET /v1/aps/{slug}/privacy-notice`):
Wenn der Verein welche veröffentlicht, muss der Antrag die Version nennen, die die Person gelesen hat, sonst `422` (`privacy_notice`
fehlt oder `privacy_notice_outdated`); die Kenntnisnahme wird im Namen der Person erfasst, unter Nennung Ihres Clients.
Optional, nach derselben Regel: `accept_terms` und `acknowledge_privacy` (die Nutzungsbedingungen des Kontos und die Datenschutzerklärung der Plattform,
`GET /v1/legal/{kind}`), wenn die Person sie auf Ihrer Website akzeptiert hat. Die Aufrufe sind idempotent: Das SDK
erzeugt pro Aufruf einen `Idempotency-Key`, oder Sie übergeben Ihren eigenen (`{ idempotencyKey: 'order-42' }`), um nach einem
Timeout gefahrlos zu wiederholen. E-Mails sind kontingentiert (3 pro Adresse und Tag) und werden aus der Sandbox nie versendet.

## Check-ins am Einlass

Mit `checkins:write` erfasst ein Gerät am Eingang den Durchgang eines Mitglieds, indem es **das aus dem QR-Code des
Ausweises gelesene Token** sendet (keine Kennung): Die Antwort ist allein das Ergebnis, keine personenbezogenen Daten. HTTP Basic wird
direkt akzeptiert, für Hardware und Low-Code-Plattformen.

```js
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 }
```

```sh
curl -u "vmc_…:vms_…" -H "Content-Type: application/json" -d '{"token":"vmt_…"}' https://api.vimine.network/v1/checkins
```

Der Body ist `{ "token": "vmt_…" }` — das aus dem QR-Code gelesene Token, eines Ausweises oder einer Veranstaltungsanmeldung; nur bei Ausweisen wird `card` als Alias akzeptiert.

Ein fehlerhaftes oder gefälschtes Token ergibt `422 invalid_card`; der Ausweis eines anderen Vereins ist „nicht gefunden“.

`identity_check: 'pending'` ist ein Hinweis für die Person am Einlass: Das Mitglied hat keine prüfbare Steuernummer, und noch niemand
aus dem Verein hat ein Ausweisdokument angesehen. Zeigen Sie ihn an; er ist nicht Teil von `verdict` und schränkt nichts ein (siehe
[die Identitätsprüfung](https://developers.vimine.network/de/guides/members-without-cf/#am-einlass-die-identitätsprüfung)).

## Mitgliedschaften auflisten (Tarife Pro und Network)

`vimineServer.memberships.list({ status?, updated_since?, limit?, cursor? })` liefert IDs, Status und Daten — **nie
personenbezogene Daten** — seitenweise (`next_cursor`). Mit `updated_since` synchronisieren Sie nur, was sich geändert hat. In Tarifen,
die das nicht enthalten, lautet die Antwort `403 plan_limit`.

## Rotation des Secrets

In der Konsole (*Secret erneuern*): Das neue Secret wird einmal angezeigt, **das bisherige funktioniert noch
24 Stunden**, sodass Sie Ihre Systeme ohne Ausfall umstellen können. Wenn Sie eine Kompromittierung vermuten, widerrufen Sie den Client:
Alle seine Sitzungen enden sofort.

## Sicherheit

- Ein wiederholt falsches Secret sperrt den Client für 15 Minuten aus.
- Jedes Token ist an den Verein des Clients gebunden: Ein Ausweis eines anderen Vereins ist schlicht „nicht gefunden“.
- Ein `401` mit gerade rotierten Zugangsdaten wiederholt das SDK einmal mit einem frischen Token.
- Antworten verwenden `application/problem+json` (siehe [Berechtigungen, Fehler und Limits](https://developers.vimine.network/de/guides/scopes-and-errors/)).
