Skip to content

VimineServer

View as Markdown
import { VimineServer } from '@vimine/sdk/server';
const vimineServer = new VimineServer({ clientId: 'vmc_…', clientSecret: process.env.VIMINE_SECRET });

For the association’s own systems: a confidential client that authenticates with client_credentials, reads card statuses and drives its sandbox. Node ≥ 18. The secret must never reach a browser.

Option Type Default
clientId string — required
clientSecret string — required; vms_… or vms_test_…
scopes Scope[] all the registered ones a subset to ask for
apiUrl string https://api.vimine.network
fetch typeof fetch globalThis.fetch

A client access token (client_credentials, HTTP Basic), cached until 30 seconds before it expires (1 hour); a single request even under concurrent calls.

An authenticated call with Authorization: Bearer; JSON in and out; errors as VimineError. A 401 (rotated or revoked credentials) is retried once with a fresh token.

Status of one membership of the association, without personal data (memberships:read):

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

Creates a Vimine account for a person (identity:signup): they receive the mail to confirm the address and pick a password. Always answers { status: 'accepted' } — whether the address already had an account is not disclosed to you (its owner is told, by mail). opts.idempotencyKey (generated when absent).

await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi', phone: '+39 …' });

Submits a membership request for a person (enroll:write): a new address gets an account and a pending request; the owner of an existing account receives a confirmation link instead (nothing is written until they use it). accept_statuto (the in-force version) is required; so is privacy_notice when the association publishes a notice to its members (association(slug).privacy_notice): the person reads it on your site and you pass the version shown. See Server integrations.

The person is identified by codicefiscale or by dob + birthplace + birth_country — never neither (422, a required entry on each missing particular). A code that disagrees with the particulars is a codicefiscale_mismatch entry in err.errors, with mismatches, hints and confirmable: when confirmable is true and the person confirms, repeat with codicefiscale_confirmed: true. address (MemberAddress) when the association collects its members’ address (aps.member_address). See Members without a fiscal code.

// with a fiscal code
await vimineServer.enroll({ ...person, codicefiscale: 'RSSMRA80A01H501U', accept_statuto: { version: 3 }, privacy_notice: { version: 2 } }, { idempotencyKey: 'order-42' });
// without one: date, place and country of birth
await vimineServer.enroll({ ...person, dob: '1985-03-10', birthplace: 'Lyon', birth_country: 'FR', accept_statuto: { version: 3 }, privacy_notice: { version: 2 } });

Records a door check-in from the token read on the QR (checkins:write). A card answers { kind: 'card', verdict, status, membership_id, valid_until, valid_from, identity_check, checked_in_at } — identity_check: 'pending' is a note to show to whoever staffs the gate, it is not part of verdict and it restricts nothing (guide); an event registration’s QR answers { kind: 'registration', verdict, registration_id, event, first, membership_verdict, … } (see Events and registrations).

events.list(params?) · events.get(slug) — the association’s published events, members-only ones included (any client token).

registrations.listForEvent(slug, { status?, limit?, cursor? }) an event’s registrations: id, status, type, membership, check-in — no personal data (registrations:read, plans with API lists)
registrations.guest(slug, { email, first_name, last_name, registration_type, note? }, opts?) registers a guest without an account for a public event; always { status: 'accepted' }; Idempotency-Key generated (see guests)

The association’s memberships (memberships:read, plans with lists): { items: [{ id, status, verdict, membership_type, issued_at, valid_until, updated_at }], next_cursor }; params: status, updated_since, limit, cursor.

Test clients only: the synthetic members of the sandbox and the reset (new shared password, returned once). A production client gets 403.

The public, credential-less endpoints: see publicApi.

express.js
import express from 'express';
import { VimineServer, VimineError } from '@vimine/sdk/server';
const vimineServer = new VimineServer({ clientId: process.env.VIMINE_CLIENT_ID, clientSecret: process.env.VIMINE_SECRET });
const app = express();
app.get('/cards/:id/status', async (req, res) => {
try {
const { status, verdict, valid_until } = await vimineServer.memberships.status(req.params.id);
res.json({ status, verdict, valid_until });
} catch (err) {
if (err instanceof VimineError && err.code === 'not_found') return res.status(404).end();
throw err;
}
});