Ir al contenido

Integraciones de servidor

Ver como Markdown

Para los sistemas de la propia asociación — un programa de gestión, un torniquete, un plugin de CMS — un cliente confidencial con client_id + client_secret. El secreto se muestra una sola vez y nunca debe llegar a un navegador.

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 de 1 hora, que se renueva solo

Sin el SDK: POST /v1/oauth/token con grant_type=client_credentials y HTTP Basic client_id:client_secret (o client_id/client_secret en el cuerpo):

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

En los endpoints de lectura (/v1/memberships/{id}/status, /v1/memberships) también se acepta HTTP Basic directamente, sin pasar por un token, para hardware y plataformas low-code — nunca desde un navegador.

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

Sin datos personales: solo el estado y la validez. El id es el que el socio ve en su propio carné (membership.id mediante Iniciar sesión con Vimine) o el que tu sistema recibió cuando lo registró.

Para verificar un carné mostrado en la entrada, usa en cambio el token del QR con /v1/verify/{card_token}: no necesita ninguna autenticación.

Con identity:signup y enroll:write, tu back office puede crear cuentas y enviar solicitudes de inscripción sin que la persona pase por Vimine: recibe por correo el enlace para confirmar su dirección y elegir una contraseña.

// Solo la cuenta (la persona todavía no es socia)
await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi' });
// Cuenta + solicitud de inscripción pendiente, que la secretaría aprueba en el back office de Vimine
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', // opcional: sin él, hacen falta dob + birthplace + birth_country
dob: '1980-01-01', birthplace: 'Roma', birth_country: 'IT',
gender: 'M', // solo demográfico: no se coteja con el código
membership_type: membership_types[0].uid, // opcional cuando hay exactamente un tipo
accept_statuto: { version: statuto.version, sha256: statuto.sha256 },
privacy_notice: privacy_notice && { version: privacy_notice.version, sha256: privacy_notice.sha256 } // obligatorio cuando la asociación publica una
});

La respuesta es siempre 202 { status: 'accepted' }, haya lo que haya detrás de la dirección: no puedes saber si un correo ya tiene una cuenta de Vimine (solo se le avisa a su titular, por correo). En concreto:

  • dirección nueva → cuenta creada y, con enroll, una solicitud de inscripción pendiente; correo de bienvenida con la confirmación de la dirección;
  • dirección ya registrada → con enroll no se escribe nada: el titular recibe un enlace «confirma tu solicitud a <asociación>» válido 24 horas, y la solicitud solo se crea cuando lo usa. Si ya es socio, no pasa nada;
  • los errores 422 se refieren solo a tu payload (validation_failed con errors[].field, statuto_outdated, invalid_type); 403 api_disabled cuando la asociación no acepta solicitudes; 403 not_available durante la beta privada, mientras las cuentas solo se crean por invitación.

Una persona se identifica con un código fiscal o con su fecha, lugar y país de nacimiento (dob, birthplace, birth_country) — nunca sin ninguno de los dos: sin código, cada dato de nacimiento que falte es una entrada required en errors[]. Para una persona nacida en el extranjero envía siempre birth_country: su código solo contiene el país. Un código que no coincide con los datos de nacimiento responde 422 con una entrada codicefiscale_mismatch que lleva mismatches, hints y confirmable: cuando confirmable es true, la persona puede confirmarlo, y repites la llamada con codicefiscale_confirmed: true. Cuando la asociación recoge la dirección de sus socios (aps.member_address en el perfil público), añade address. Cuando recoge los datos de quien ejerce la responsabilidad parental (aps.collects_guardian_data) y la persona es menor según dob, guardian es obligatorio — first_name, last_name, relation y, opcionalmente, codicefiscale, email, phone —; si no, 422 con guardian: required. El recorrido completo está en Socios sin código fiscal.

accept_statuto debe nombrar el estatuto en vigor: muéstraselo a la persona en tu sitio (está en association(slug); el texto y el documento, en GET /v1/aps/{slug}/statuto) y pasa la versión que ha aceptado. Una asociación que no ha registrado ningún estatuto legible responde accepting_requests: false, y la solicitud 403 not_available. Lo mismo vale para la política de privacidad de la asociación para sus socios (privacy_notice en association(slug), el texto en GET /v1/aps/{slug}/privacy-notice): cuando la asociación publica una, la solicitud debe nombrar la versión que la persona ha leído; si no, 422 (privacy_notice ausente o privacy_notice_outdated); el acuse de recibo se registra a nombre de la persona, con tu cliente indicado. Opcionales, con la misma regla: accept_terms y acknowledge_privacy (las condiciones de la cuenta y la política de privacidad de la plataforma, GET /v1/legal/{kind}) cuando la persona las ha aceptado en tu sitio. Las llamadas son idempotentes: el SDK genera una Idempotency-Key por llamada, o pasa la tuya ({ idempotencyKey: 'order-42' }) para repetir sin riesgos después de un timeout. Los correos tienen un límite (3 por dirección y día) y nunca se envían desde el sandbox.

Con checkins:write, un dispositivo en la entrada registra el paso de un socio enviando el token leído del QR del carné (no un identificador): la respuesta es solo el veredicto, sin datos personales. Se acepta HTTP Basic directamente, para hardware y plataformas low-code.

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 }
Ventana de terminal
curl -u "vmc_…:vms_…" -H "Content-Type: application/json" -d '{"token":"vmt_…"}' https://api.vimine.network/v1/checkins

El cuerpo es { "token": "vmt_…" } — el token leído del QR, de un carné o de una inscripción a un evento; solo para los carnés, card se acepta como alias.

Un token mal formado o falsificado es un 422 invalid_card; un carné de otra asociación es «no encontrado».

identity_check: 'pending' es una nota para quien atiende la entrada: el socio no tiene un código fiscal comprobable y nadie de la asociación ha mirado todavía un documento. Muéstrala; no forma parte de verdict y no restringe nada (consulta la comprobación de identidad).

Listar las inscripciones (planes Pro y Network)

Sección titulada «Listar las inscripciones (planes Pro y Network)»

vimineServer.memberships.list({ status?, updated_since?, limit?, cursor? }) devuelve ids, estados y fechas — nunca datos personales — por páginas (next_cursor). Con updated_since sincronizas solo lo que ha cambiado. En los planes que no lo incluyen, la respuesta es 403 plan_limit.

Desde la consola (Regenerar secreto): el secreto nuevo se muestra una sola vez y el anterior sigue funcionando durante 24 horas, para que puedas actualizar tus sistemas sin interrupciones. Si sospechas que está comprometido, revoca el cliente: todas sus sesiones terminan de inmediato.

  • Un secreto erróneo, repetido, bloquea el cliente durante 15 minutos.
  • Cada token está vinculado a la asociación del cliente: un carné de otra asociación es simplemente «no encontrado».
  • El SDK repite una vez, con un token nuevo, un 401 recibido con credenciales recién regeneradas.
  • Las respuestas usan application/problem+json (consulta Permisos, errores y límites).