跳转到内容

VimineServer

查看 Markdown
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

客户端访问令牌(client_credentials,HTTP Basic),缓存至到期(1 小时)前 30 秒;即使被并发调用,也只发出一次请求。

一次带 Authorization: Bearer 的认证调用;输入输出均为 JSON;错误以 VimineError 抛出。收到 401(凭据已轮换或已撤销)时,用新令牌重试一次。

协会某个会员资格的状态,不含个人数据(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' } }

为某人创建 Vimine 账户(identity:signup):当事人会收到邮件,用于确认邮箱地址并设置密码。始终返回 { status: 'accepted' }——不会告诉您该地址是否已有账户(邮箱的所有者会通过邮件得知)。opts.idempotencyKey(未提供时自动生成)。

await vimineServer.signup({ email: 'mario.rossi@example.org', first_name: 'Mario', last_name: 'Rossi', phone: '+39 …' });

为某人提交入会申请(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: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.list(params?) · events.get(slug)——协会已发布的活动,包括仅限会员的活动(任何客户端令牌均可)。

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。

无需凭据的公开端点:参见 publicApi。

express.js
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;
}
});