Skip to content

Events and registrations

View as Markdown

The events an association publishes from its console are on the API with the same principle as the cards: headless copy (title, summary, markdown description, images, place, dates, links) and live availability per registration type — never who is registered. The vocabulary is the Italian Third Sector’s: a registration (iscrizione) and, when there is an amount, a contribution (contributo).

visibility Who sees it Who registers
members_only (default) only with a member token or the association’s own client members with a valid card
public anyone, no sign-in: GET /v1/aps/{slug}/events members and — when the registration type does not require a card — guests

A public event shows your site’s visitors the copy and the registration types with the places left; members-only events appear only after sign-in.

public page, no sign-in
import { publicApi } from '@vimine/sdk';
const api = publicApi();
const { items } = await api.events.list('your-slug', { filter: 'upcoming' });
const event = await api.events.get('your-slug', 'jazz-night');
after Sign in with Vimine (members-only events included)
const { items } = await vimine.events.list(); // events:read
const event = await vimine.events.get('jazz-night');

Every event carries registration_types[]: amount (0 = free), currency, remaining (places left, null = unlimited), open and — when it is not open — reason (sold_out, registration_not_open, registration_closed). status is published, completed (the date has passed) or cancelled.

Without writing code: the <vimine-events> element renders the list with the register buttons.

A public event also reaches people who are not members: it is the moment a person decides to become one. The association’s enrolment page on Vimine opens with the event, and the person joins and books in one step:

https://app.vimine.network/enroll/your-slug?event=jazz-night
the same address, from your code
import { eventEnrollUrl } from '@vimine/sdk/elements';
const url = eventEnrollUrl('https://app.vimine.network', 'your-slug', 'jazz-night', 'en');

What becomes of the place depends on where the membership stands, and the page tells the person:

The membership The place
is active at once (free card, no approval) confirmed, when the event’s registration is free
waits for approval or for the fee for a members-only registration: held until the card is active, and then, when it is free, confirmed by itself. For a registration open to everybody: confirmed at once, as for a non-member
the event’s registration asks for a contribution held until the deadline the association set: confirmed when it records the contribution
the e-mail address is not confirmed yet nothing is held: the place is asked for when the person confirms the address from the link in the mail, and a mail tells them how it went

Someone who is already a member uses the same page: they sign in and book with one button, with nothing to fill in (&signin=1 opens the sign-in at once). It applies to published public events that are still ahead: with any other slug the page is the ordinary enrolment page.

The event’s public page on Vimine (/agenda/your-slug/jazz-night) and <vimine-events> already offer visitors this way in: Join the association and book.

Before showing the button ask the API whether the member may register — the answer says why not:

const { can_register, types } = await vimine.events.eligibility('jazz-night');
// types[i].reasons: membership_required, membership_not_active, membership_not_yet_valid, sold_out, max_per_user, registration_closed, …

Then register them (registrations:write):

const reg = await vimine.registrations.create('jazz-night', { registration_type: types[0].uid, note: 'Coming with my sister' });
if (reg.status === 'confirmed') drawQr(reg.token); // free type: confirmed, QR ready
if (reg.status === 'reserved') show(reg.payment_instructions); // contribution: reserved until it is paid
  • A free type confirms at once and returns token: the content of the QR the member shows at the door (draw it yourself, with the library you prefer).
  • A type with a contribution reserves the place (reserved_until) and returns the association’s payment instructions; the secretariat confirms when it records the contribution — the member gets an e-mail and from then on vimine.registrations.get(id) carries the token. Card payments arrive with Stripe.
  • If the member’s card is still awaiting activation, the registration stays reserved and confirms itself when the card becomes active.
  • 422 not_eligible carries the same reasons as the eligibility call in errors[].

The member’s registrations: vimine.registrations.list({ filter: 'upcoming' }); cancellation inside the event’s window (registration.cancellation_hours hours before the start): vimine.registrations.cancel(id) — later, 409 window_closed.

A visitor without a Vimine account can register for a public event, on a registration type that does not require a card, from your server (confidential client, registrations:write):

server
await srv.registrations.guest('jazz-night', { email, first_name, last_name, registration_type });
// → { status: 'accepted' }, always

No account is created. The guest receives an e-mail with a confirmation link (valid 24 hours) that lands on the event’s page on Vimine: with a free type the place is confirmed there and the QR shown at once; with a contribution the place stays reserved with the payment instructions. If you would rather host the confirmation page yourself, consume the link’s token with api.confirmRegistration(token).

Once the place is confirmed — at once with a free type, when the contribution is recorded otherwise — the guest receives a second e-mail with their own link: it opens the event’s page with the QR to show at the door, and it works until the event is over (a postponed event keeps it). A guest has no personal area: the link is their place, never the QR itself (a forwarded mail is not a place). If you host that page yourself, read the place with api.viewRegistration(token) (SDK since 0.3.2).

The answer is always 202 { status: 'accepted' }: the API never discloses whether an address is already registered. Eligibility problems (sold_out, membership_required for a members-only type) are 422.

The registration QR is a signed token like the card’s: the same scanner and the same call accept it.

server (turnstile, scanner, desk)
const r = await srv.checkins.create(scannedToken);
if (r.kind === 'registration') {
// r.verdict: valid | already_checked_in | not_confirmed | cancelled | event_cancelled | membership_invalid
// r.first: true on the first pass; r.membership_verdict when the type requires a card
}

Public verification answers a registration token too: GET /v1/verify/{token} → { status, kind: 'registration', event: { slug, starts_at } }, no personal data.

The registrations of an event — id, status, type, membership, check-in, no personal data — are srv.registrations.listForEvent(slug, { status, limit, cursor }) (registrations:read, plans with API lists). Names stay in the association’s console.