@mi-pase / sdk
的官方Node.js / TypeScript SDK mi-pase API -管理项目,注册,奖励,传递模板和验证器从您的后端。
- 零运行时依赖,构建在本机上
fetch. - 每个请求和响应的完整TypeScript类型。
- 流畅的、可链接的API:
client.project(id).enrollment(id).setCustomFields(...). - 发布ESM和CJS版本。
安装
npm install @mi-pase/sdk
就这样——包被发布到公共npm注册表,不需要身份验证。
而是从GitHub包安装
@mi-pase/sdk 在每个版本中也会发布到GitHub Packages。要使用该注册表,请将其添加到项目的注册表中 .npmrc:
@mi-pase:registry=https://npm.pkg.github.com/
然后使用GitHub个人访问令牌对npm进行身份验证 read:packages 作用域,通过 npm login --scope=@mi-pase --registry=https://npm.pkg.github.com 或者加上 .npmrc:
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
快速启动
import { MiPaseClient } from "@mi-pase/sdk";
const client = new MiPaseClient({
// A Clerk Organization API key, created from your mi-pase organization's
// API Keys settings panel. Sent as `Authorization: Bearer <apiKey>`.
apiKey: process.env.MI_PASE_API_KEY!,
});
const project = await client.projects.create({
domain: "acme",
name: "Summer Fest 2026",
});
const enrollment = await client.project(project._id).enrollments.create({
domain: "acme",
name: "Jane Doe",
email: "[email protected]",
});
// Chain from a project straight into one of its enrollments:
await client
.project(project._id)
.enrollment(enrollment._id)
.setCustomFields({ seat: "12A" }, { override: true });
客户的选择
new MiPaseClient({
apiKey: "...", // required — Clerk Organization API key
baseUrl: "...", // default: "https://app.mi-pase.ar"
timeoutMs: 30_000, // per-request timeout
maxRetries: 2, // retries for GET/PUT/DELETE on network/timeout/429/5xx errors
fetch: customFetch, // override the fetch implementation
});
POST请求永远不会自动重试(默认情况下,它们不是幂等的——例如,创建一个项目两次会创建两个项目)。通过 { idempotent: true } 作为每个调用选项,如果您知道特定的POST可以安全重试,则底层资源方法将其公开。
API版本控制
midpase API目前是 v1 只有;下面展示的每一种方法都与 v1 端点。客户端接受一个预留 apiVersion 选项("v1" 今天)等那时候 v2 端点船,这个SDK可以添加一个 v2 表面没有断裂的变化 v1 一个。
资源
项目
await client.projects.list({ domain, kind });
await client.projects.create({ domain, name, ... });
await client.project(id).get();
await client.project(id).update({ name: "New name" });
await client.project(id).delete(); // only finalized projects can be deleted
await client.project(id).duplicate();
入学
await client.enrollments.list({ project, person, domain });
await client.enrollments.create({ domain, project_id, name, email, phone, customFields });
await client.enrollments.bulkCreate({ domain, project_id, rows: [...] });
await client.enrollments.copyToProject({ sourceProjectId, targetProjectId, domain });
await client.enrollment(id).get();
await client.enrollment(id).update({ customFields }); // full replace, matches the raw API
await client.enrollment(id).delete(); // unenrolls the person (and revokes their pass)
await client.enrollment(id).revoke(); // revokes the issued pass; person stays enrolled
await client.enrollment(id).setCustomFields({ seat: "12A" }); // merges with existing fields (fetches first)
await client.enrollment(id).setCustomFields({ seat: "12A" }, { override: true }); // full replace, no extra fetch
在一个项目范围内, project_id 为您填写:
await client.project(projectId).enrollments.list();
await client.project(projectId).enrollments.create({ domain, name, email });
await client.project(projectId).enrollments.bulkCreate({ domain, rows: [...] });
await client.project(projectId).enrollment(enrollmentId).setCustomFields({...});
奖励
奖励只存在于一个项目中——没有顶层 /rewards 端点。
await client.project(projectId).rewards.list();
await client.project(projectId).rewards.create({ name, description, pointsRequired });
await client.project(projectId).rewards.update(rewardId, { pointsRequired: 200 });
await client.project(projectId).rewards.delete(rewardId);
模板
await client.templates.list({ domain });
await client.templates.create({ domain, name, type: "event" });
await client.template(id).get();
await client.template(id).update({ name: "New name" });
await client.template(id).delete();
await client.template(id).duplicate();
await client.template(id).getConfig(); // Apple + Google wallet design, or undefined if unsynced
await client.template(id).saveConfig({ apple, google });
验证器
await client.validators.list({ domain });
await client.validators.create({ domain, name, project, scanMode: "both" });
await client.validators.recordsForEnrollments([enrollmentId1, enrollmentId2]);
await client.validator(id).get();
await client.validator(id).update({ scanMode: "nfc" });
await client.validator(id).delete();
await client.validator(id).scan({ scannedValue, scanMode: "camera" });
await client.validator(id).records({ limit: 50, skip: 0, search: "" });
scan() 可以返回 { matches: [...] } 当扫描值解析为多个注册时,不使用验证记录,而是使用导出的 isScanAmbiguous() 键入保护并重新扫描 enrollmentId 设置:
import { isScanAmbiguous } from "@mi-pase/sdk";
const result = await client.validator(id).scan({ scannedValue, scanMode: "camera" });
if (isScanAmbiguous(result)) {
// prompt the operator to pick one of result.matches
} else {
// result is a ValidationRecord
}
通知
钱包推送通知到项目的活动通道。 send 默认针对整个项目;缩小范围 enrollmentIds (特定注册)和/或 issuedFrom/issuedTo 签发日期窗口。 message 在两个钱包之间共享,可选的每个平台覆盖- googleMessage 可以携带一个单 <a href> 锚谷歌钱包呈现为一个可点击的链接(苹果推送没有链接支持)。
await client.notifications.send({
domain,
project: projectId,
message: "Doors open at 7pm.",
// optional per-platform overrides:
appleMessage: "Doors open at 7pm.",
googleMessage: 'Doors open at 7pm. <a href="https://acme.example/map">View map</a>',
// optional filters:
enrollmentIds: [enrollmentId1, enrollmentId2],
issuedFrom: "2026-10-01",
issuedTo: "2026-10-31",
});
await client.notifications.list({ domain }); // sent-notification history for a domain
await client.notifications.listByPasses([passId1]); // history touching specific passes
await client.notifications.preview({ domain, project: projectId, enrollmentIds }); // { count, cooldownUntil }
API上限发送点 每24小时通知一个项目在该窗口内发送将抛出 MiPaseApiError 与地位 429。呼叫 preview 首先找到潜在的目标 count 和 cooldownUntil 时间戳(ISO字符串,或 null (现在允许发送)而不消耗冷却时间。
健康
await client.health(); // { status: "ok", timestamp: "..." }
错误处理
每个非2xx响应都会抛出 MiPaseApiError:
import { MiPaseApiError } from "@mi-pase/sdk";
try {
await client.project("does-not-exist").get();
} catch (error) {
if (error instanceof MiPaseApiError) {
console.error(error.status, error.message, error.body);
}
throw error;
}
网络故障抛出 MiPaseNetworkError;客户端超时抛出 MiPaseTimeoutError.
要求
Node.js 18或更高版本(用于全局) fetch),或者传递你自己的 fetch 实现通过 options.fetch.