Skip to content

Public API

View as Markdown
import { publicApi } from '@vimine/sdk';
const api = publicApi(); // or vimine.public / vimineServer.public

The endpoints that need neither credentials nor a sign-in. Usable from any page, from a scanner, from a server. publicApi({ apiUrl?, fetch? }) takes the same network options as the other classes.

Method Endpoint
verifyCard(cardToken) GET /v1/verify/{card_token} “is this card active right now?” — status and validity end only
association(slug, { locale }?) GET /v1/aps/{slug} public profile: branding, membership types with fees, in-force statuto, how it admits members, whether it collects their address (member_address)
validateFiscalCode(input) POST /v1/validate/fiscal-code structure and check character; with personal data, their consistency too — and what the code holds (birth_date, birth_country). For a person born abroad send country
cardKeys() GET /v1/card-keys the public keys (JWKS, Ed25519) that verify tokens offline
confirmEnrollment(token, identification?, address?) POST /v1/enroll/confirm consumes the token of the “confirm your request” link sent when a system enrols an existing account; after a 409 identification_required it is repeated with identification, after a 409 address_required with address
events.list(slug, params?) · events.get(slug, event, { locale }?) GET /v1/aps/{slug}/events[/{event}] an association’s public events, with the places left per type (guide)
confirmRegistration(token) POST /v1/registrations/confirm consumes the token of a guest’s “confirm your registration” link: the registration, with the QR token when confirmed
viewRegistration(token) POST /v1/registrations/view reads the place behind a guest’s own link (the mail that confirms the place): its status and, while it is confirmed, the QR token; it works until the event is over (since 0.3.2)
const { status, valid_until } = await api.verifyCard('vmt_…');
// { status: 'active', valid_until: '2027-03-31T22:59:59.000Z' } | { status: 'inactive', reason: 'expired' }
const { aps, membership_types, statuto } = await api.association('your-slug');
const check = await api.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' }
// | { valid: false, error: 'mismatch', mismatches: ['date'], hints: [], birth_date: '1980-01-01', birth_country: 'IT' }
const { keys } = await api.cardKeys(); // [{ kty: 'OKP', crv: 'Ed25519', x, kid, use: 'sig', alg: 'EdDSA' }]
const { status, already, association } = await api.confirmEnrollment(token); // from the link received by e-mail
// { status: 'pending', already: false, association: { name, slug } } — 400 invalid_token when expired, 409 statuto_outdated
// 409 identification_required: the account is not identified; err.errors names what is missing. Ask for it and repeat:
await api.confirmEnrollment(token, { dob: '1985-03-10', birthplace: 'Lyon', birth_country: 'FR' });
// 409 address_required: the association asks every member for an address. Ask for it and repeat (with the identification, if already given):
await api.confirmEnrollment(token, undefined, { line: 'Via Roma 1', postal_code: '20100', city: 'Milano', province: 'MI' });

The fiscal code is optional: error is invalid, mismatch or null, and hints holds names_swapped when the code matches once surname and given name are exchanged. The particulars of identification and the address travel in the request body, never in the link. See Members without a fiscal code.

Keys change rarely: cache them and reload once a day, or when you meet an unknown kid. The rest of offline verification is in Embed and card verification.

These endpoints have a per-IP limit (60 requests per minute on verification and fiscal code): for higher volumes use a confidential client with verify:read.