# Eventos e inscripciones

> Publica los eventos de la asociación en tu sitio, deja que los socios se inscriban (y los invitados, en los eventos públicos), haz el check-in en la entrada con el mismo escáner que los carnés.

URL: https://developers.vimine.network/es/guides/events/

Los eventos que una asociación publica desde su consola están en la API con el mismo principio que los carnés:
**contenido headless** (título, resumen, descripción en markdown, imágenes, lugar, fechas, enlaces) y
**disponibilidad en directo** por tipo de inscripción — nunca *quién* está inscrito. El vocabulario es el del Tercer
Sector italiano: una **inscripción** (*iscrizione*) y, cuando hay un importe, una **contribución** (*contributo*).

:::note[Antes de empezar]
Tu cliente necesita los permisos `events:read`, `registrations:read` y `registrations:write` (consulta
[Permisos, errores y límites](https://developers.vimine.network/es/guides/scopes-and-errors/)). Para hacer pruebas sin tocar datos reales usa el
[sandbox](https://developers.vimine.network/es/guides/sandbox/): la asociación gemela puede publicar eventos como la real.
:::

## Dos visibilidades

| `visibility` | Quién lo ve | Quién se inscribe |
|---|---|---|
| `members_only` (por defecto) | solo con un token de socio o con el cliente de la propia asociación | socios con un carné válido |
| `public` | cualquiera, sin iniciar sesión: `GET /v1/aps/{slug}/events` | socios y — cuando el tipo de inscripción no requiere carné — **invitados** |

Un evento público muestra a los visitantes de tu sitio el contenido y los tipos de inscripción con las plazas que
quedan; los eventos solo para socios aparecen únicamente después de iniciar sesión.

## Mostrar los eventos

```js title="página pública, sin iniciar sesión"
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');
```

```js title="después de Iniciar sesión con Vimine (incluidos los eventos solo para socios)"
const { items } = await vimine.events.list();           // events:read
const event = await vimine.events.get('jazz-night');
```

Cada evento lleva `registration_types[]`: `amount` (0 = gratuito), `currency`, `remaining` (plazas que quedan,
`null` = ilimitadas), `open` y — cuando no está abierto — `reason` (`sold_out`, `registration_not_open`,
`registration_closed`). `status` es `published`, `completed` (la fecha ya ha pasado) o `cancelled`.

Sin escribir código: el elemento [`<vimine-events>`](https://developers.vimine.network/es/sdk/elements/) muestra la lista con los botones de
inscripción.

## Quien aún no es socio

Un evento público llega también a quienes no son socios: es el momento en que una persona decide hacerse socia. La
página de inscripción de la asociación en Vimine se abre **con el evento**, y la persona se hace socia y reserva en
un solo paso:

```
https://app.vimine.network/enroll/your-slug?event=jazz-night
```

```js title="la misma dirección, desde tu código"
import { eventEnrollUrl } from '@vimine/sdk/elements';
const url = eventEnrollUrl('https://app.vimine.network', 'your-slug', 'jazz-night', 'en');
```

Lo que pasa con la plaza depende de en qué punto está la inscripción como socio, y la página se lo dice a la persona:

| La inscripción como socio | La plaza |
|---|---|
| está activa de inmediato (carné gratuito, sin aprobación) | **confirmada**, cuando la inscripción al evento es gratuita |
| espera la aprobación o la cuota | para una inscripción solo para socios: **retenida** hasta que el carné esté activo y, entonces, si es gratuita, confirmada sola. Para una inscripción abierta a todos: confirmada de inmediato, como para quien no es socio |
| la inscripción al evento pide una contribución | **retenida** hasta el plazo que fijó la asociación: confirmada cuando esta registra la contribución |
| la dirección de correo aún no está confirmada | no se retiene nada: la plaza se solicita cuando la persona confirma su dirección desde el enlace del correo, y un correo le dice cómo ha ido |

Quien ya es socio usa la misma página: inicia sesión y reserva con un botón, sin rellenar nada (`&signin=1` abre el
inicio de sesión directamente). Vale para los eventos `public` publicados que todavía no han tenido lugar: con
cualquier otro slug, la página es la página de inscripción normal.

La página pública del evento en Vimine (`/agenda/your-slug/jazz-night`) y `<vimine-events>` ya ofrecen a los
visitantes esta vía de entrada: *Hacerse socio y reservar plaza*.

## Inscribir a un socio

Antes de mostrar el botón, pregunta a la API si el socio puede inscribirse — la respuesta dice por qué no:

```js
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, …
```

Después, inscríbelo (`registrations:write`):

```js
const reg = await vimine.registrations.create('jazz-night', { registration_type: types[0].uid, note: 'Vengo con mi hermana' });
if (reg.status === 'confirmed') drawQr(reg.token);           // tipo gratuito: confirmada, QR listo
if (reg.status === 'reserved') show(reg.payment_instructions); // contribución: reservada hasta que se pague
```

- Un tipo **gratuito** confirma de inmediato y devuelve `token`: el contenido del QR que el socio muestra en la
  entrada (dibújalo tú, con la biblioteca que prefieras).
- Un tipo **con contribución** reserva la plaza (`reserved_until`) y devuelve las instrucciones de pago de la
  asociación; la secretaría confirma cuando registra la contribución — el socio recibe un correo y, a partir de ese
  momento, `vimine.registrations.get(id)` lleva el `token`. Los pagos con tarjeta llegan con Stripe.
- Si el carné del socio todavía está pendiente de activación, la inscripción queda `reserved` y se confirma sola
  cuando el carné se activa.
- `422 not_eligible` lleva en `errors[]` los mismos motivos que la llamada de elegibilidad.

Las inscripciones del socio: `vimine.registrations.list({ filter: 'upcoming' })`; la anulación dentro de la ventana
del evento (`registration.cancellation_hours` horas antes del inicio): `vimine.registrations.cancel(id)` — después,
`409 window_closed`.

## Invitados (eventos públicos)

Un visitante sin cuenta de Vimine puede inscribirse en un evento **público**, en un tipo de inscripción que no
requiera carné, desde tu servidor (cliente confidencial, `registrations:write`):

```js title="servidor"
await srv.registrations.guest('jazz-night', { email, first_name, last_name, registration_type });
// → { status: 'accepted' }, siempre
```

No se crea ninguna cuenta. El invitado recibe un correo con un enlace de confirmación (válido 24 horas) que lleva a
la página del evento en Vimine: con un tipo gratuito, la plaza se confirma ahí y el QR se muestra enseguida; con una
contribución, la plaza queda reservada con las instrucciones de pago. Si prefieres alojar tú la página de
confirmación, consume el token del enlace con `api.confirmRegistration(token)`.

Una vez confirmada la plaza — de inmediato con un tipo gratuito, cuando se registra la contribución en los demás
casos — el invitado recibe un segundo correo con su propio enlace: abre la página del evento con el QR que hay que
mostrar en la entrada, y funciona hasta que el evento termina (un evento aplazado lo conserva). Un invitado no tiene
área personal: el enlace es su plaza, nunca el propio QR (un correo reenviado no es una plaza). Si alojas tú esa
página, lee la plaza con `api.viewRegistration(token)` (SDK desde la 0.3.2).

La respuesta es siempre `202 { status: 'accepted' }`: la API nunca revela si una dirección ya está inscrita. Los
problemas de elegibilidad (`sold_out`, `membership_required` para un tipo solo para socios) son `422`.

:::caution[Fiscalidad]
Según el Código del Tercer Sector italiano, las contribuciones de **quienes no son socios** son ingresos
comerciales: la consola lo indica cuando un evento se hace público, y cada contribución se clasifica automáticamente
según la condición de socio que tenía la inscripción en el momento del pago.
:::

## En la entrada

El QR de la inscripción es un token firmado como el del carné: el mismo escáner y la misma llamada lo aceptan.

```js title="servidor (torniquete, escáner, taquilla)"
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 en la primera pasada; r.membership_verdict cuando el tipo requiere carné
}
```

La verificación pública también responde a un token de inscripción: `GET /v1/verify/{token}` →
`{ status, kind: 'registration', event: { slug, starts_at } }`, sin datos personales.

## Desde tu back office

Las inscripciones de un evento — id, estado, tipo, condición de socio, check-in, **sin datos personales** — están en
`srv.registrations.listForEvent(slug, { status, limit, cursor })` (`registrations:read`, planes con listas por API).
Los nombres se quedan en la consola de la asociación.

## Referencias

- [SDK de navegador](https://developers.vimine.network/es/sdk/browser/#events) · [SDK de servidor](https://developers.vimine.network/es/sdk/server/#events) ·
  [`<vimine-events>`](https://developers.vimine.network/es/sdk/elements/) · [Tipos](https://developers.vimine.network/es/sdk/types/)
- API HTTP: las operaciones con las etiquetas `events` y `registrations` en la [referencia](https://developers.vimine.network/es/api/console/).
