VimineServer
import { VimineServer } from '@vimine/sdk/server';const vimineServer = new VimineServer({ clientId: 'vmc_…', clientSecret: process.env.VIMINE_SECRET });用于协会自己的系统:一个通过 client_credentials 认证的机密客户端,读取会员卡状态并操作其沙盒。需要 Node ≥ 18。secret 绝不能出现在浏览器中。
选项
章节“选项”| 选项 | 类型 | 默认值 | |
|---|---|---|---|
clientId |
string |
— | 必填 |
clientSecret |
string |
— | 必填;vms_… 或 vms_test_… |
scopes |
Scope[] |
所有已登记的权限 | 要申请的子集 |
apiUrl |
string |
https://api.vimine.network |
|
fetch |
typeof fetch |
globalThis.fetch |
方法
章节“方法”token()
章节“token()”客户端访问令牌(client_credentials,HTTP Basic),缓存至到期(1 小时)前 30 秒;即使被并发调用,也只发出一次请求。
request(path, init?)
章节“request(path, init?)”一次带 Authorization: Bearer 的认证调用;输入输出均为 JSON;错误以 VimineError 抛出。收到 401(凭据已轮换或已撤销)时,用新令牌重试一次。
memberships.status(id)
章节“memberships.status(id)”协会某个会员资格的状态,不含个人数据(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' } }signup(input, opts?)
章节“signup(input, opts?)”为某人创建 Vimine 账户(identity:signup):当事人会收到邮件,用于确认邮箱地址并设置密码。始终返回 { status: 'accepted' }——不会告诉您该地址是否已有账户(邮箱的所有者会通过邮件得知)。opts.idempotencyKey(未提供时自动生成)。
await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi', phone: '+39 …' });enroll(input, opts?)
章节“enroll(input, opts?)”为某人提交入会申请(enroll:write):新地址会获得一个账户和一份待处理的申请;已有账户的所有者则会收到一个确认链接(在其使用链接之前不写入任何内容)。accept_statuto(现行版本)为必填;当协会发布了面向会员的隐私声明时(association(slug).privacy_notice),privacy_notice 也为必填:当事人在您的网站上阅读后,您传入所展示的版本。参见服务器集成。
识别当事人,要么通过 codicefiscale,要么通过 dob + birthplace + birth_country——两者不能都没有(422,每缺少一项出生信息就有一条 required)。税号与出生信息不一致时,err.errors 中会有一条 codicefiscale_mismatch 记录,带有 mismatches、hints 和 confirmable:当 confirmable 为 true 且当事人确认时,请带上 codicefiscale_confirmed: true 重复调用。如果协会登记会员的地址(aps.member_address),请传入 address(MemberAddress)。参见没有意大利税号的会员。
// 有税号await vimineServer.enroll({ ...person, codicefiscale: 'RSSMRA80A01H501U', accept_statuto: { version: 3 }, privacy_notice: { version: 2 } }, { idempotencyKey: 'order-42' });// 没有税号:出生日期、出生地和出生国await vimineServer.enroll({ ...person, dob: '1985-03-10', birthplace: 'Lyon', birth_country: 'FR', accept_statuto: { version: 3 }, privacy_notice: { version: 2 } });checkins.create(token)
章节“checkins.create(token)”用从二维码中读取的令牌记录一次入场登记(checkins:write)。会员卡返回 { kind: 'card', verdict, status, membership_id, valid_until, valid_from, identity_check, checked_in_at }——identity_check: 'pending' 是需要显示给入口值守人员的提示,它不属于 verdict,也不限制任何操作(指南);活动报名的二维码返回 { kind: 'registration', verdict, registration_id, event, first, membership_verdict, … }(参见活动与报名)。
events
章节“events”events.list(params?) · events.get(slug)——协会已发布的活动,包括仅限会员的活动(任何客户端令牌均可)。
registrations
章节“registrations”registrations.listForEvent(slug, { status?, limit?, cursor? }) |
某个活动的报名:id、状态、类型、会员资格、入场登记——不含个人数据(registrations:read,适用于支持 API 列表的套餐) |
registrations.guest(slug, { email, first_name, last_name, registration_type, note? }, opts?) |
为没有账户的嘉宾报名公开活动;始终返回 { status: 'accepted' };自动生成 Idempotency-Key(参见嘉宾) |
memberships.list(params?)
章节“memberships.list(params?)”协会的会员资格列表(memberships:read,适用于支持列表的套餐):{ items: [{ id, status, verdict, membership_type, issued_at, valid_until, updated_at }], next_cursor };params:status、updated_since、limit、cursor。
sandbox.members() · sandbox.reset()
章节“sandbox.members() · sandbox.reset()”仅限测试客户端:沙盒中的虚构会员,以及重置(新的共用密码,只返回一次)。生产客户端会得到 403。
public
章节“public”无需凭据的公开端点:参见 publicApi。
中间件示例
章节“中间件示例”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; }});