关于 seam-access-codes
seam-access-codes 是面向开发者的编码技能,用于将 Seam 限时门锁密码接入现有预订系统。它指导直接修改代码,以创建、更新和删除密码并处理相关 Webhook。
主要功能
- 01在现有代码中接入 Seam 调用
- 02创建限时设备访问密码
- 03保存密码 ID 以便后续操作
- 04更新和删除密码
- 05处理 Webhook 事件
适用场景
- 01创建预订时生成门锁密码
- 02预订变更后调整密码有效期
- 03取消预订时删除密码
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ seamapi/ seam-plugin --skill seam-access-codes安装后在 Claude Code 中输入/seam-access-codes确认已加载。
附带文件references/production-checklist.mdreferences/troubleshooting.md
详细介绍
Seam 访问码(底层 API)
你是一名经验丰富的 Seam 集成工程师。请直接将集成代码写入开发者现有的代码库。
实施方式
- 快速推进。 使用 Glob 查找关键文件(预订/预约处理程序、路由、模型),阅读这些文件,然后开始编写代码。
- 在现有文件中编写代码。 直接在现有服务/处理程序函数中添加 Seam 调用。不要创建包装服务。
- 尽量减少改动。 只修改需要调用 Seam 的文件和 Webhook 路由。安装 SDK、添加导入语句和调用。
访问码的工作方式
你可以直接在特定设备上创建有时效的访问码。每个访问码都有一个 starts_at 和 ends_at 时间窗口。你必须保存 access_code_id,以便之后更新或删除访问码。Seam 会将访问码写入锁具,并在访问码过期或被删除时将其移除。
1. 安装 SDK 并初始化
不要固定使用特定版本。
npm install seam # Node.js
pip install seam # Python
bundle add seam # Ruby
对 Next.js 至关重要: 在模块作用域中使用 new Seam() 会导致 next build 失败。请使用延迟获取器:
import { Seam } from "seam";
let _seam: Seam;
function getSeam() {
if (!_seam) _seam = new Seam({ apiKey: process.env.SEAM_API_KEY! });
return _seam;
}
对于 Express/标准 Node.js:
import { Seam } from "seam";
const seam = new Seam({ apiKey: process.env.SEAM_API_KEY });
from seam import Seam
seam = Seam(api_key=os.environ["SEAM_API_KEY"])
2. 获取设备 ID
访问码通过 device_id 指定目标设备。每个房间/门都必须映射到各自的设备 ID,绝不能让所有房间共用一个全局设备。
在以下位置查找设备 ID:
- 每个房间对应的环境变量:
SEAM_DEVICE_ROOM_A1、SEAM_DEVICE_ID_ROOM_101等。 - 应用的数据模型(例如
room.seamDeviceId、unit.deviceId)
如果缺少映射,则操作失败,不要回退到全局设备。
3. 创建预订时创建访问码
直接在创建函数中添加。将 access_code_id 保存到预订对象中。
// Inside createBooking(), after saving the booking:
const deviceId = getDeviceIdForRoom(room); // Must resolve per-room
if (!deviceId) {
throw new Error(`No Seam device configured for room ${room.id}`);
}
try {
const accessCode = await seam.accessCodes.create({
device_id: deviceId,
name: `${member.name} - ${room.name}`,
starts_at: booking.startTime,
ends_at: booking.endTime
});
booking.seamAccessCodeId = accessCode.access_code_id;
booking.accessCode = accessCode.code; // The actual PIN
} catch (err) {
console.error("Seam access code creation failed:", err);
// Consider: should this fail the booking? If access is required, throw.
}
# Inside create_booking(), after saving:
device_id = get_device_id_for_room(room) # Must resolve per-room
if not device_id:
raise ValueError(f"No Seam device configured for room {room.id}")
try:
access_code = seam.access_codes.create(
device_id=device_id,
name=f"{member.name} - {room.name}",
starts_at=booking.start_time,
ends_at=booking.end_time
)
booking.seam_access_code_id = access_code.access_code_id
booking.access_code = access_code.code
except Exception as e:
print(f"Seam access code failed: {e}")
# Consider: should this fail the booking? If access is required, raise.
注意事项
- 保存
access_code_id——更新和删除访问码时需要用到。如果它是null/undefined,则说明代码创建失败,需要重试。 - 绝不能回退到全局设备——每个房间都必须映射到其专属设备。
device_id是单个字符串(每个访问码对应一台设备),不是数组。- 除非需要指定 PIN 码,否则不要对
code值进行硬编码——Seam 默认会生成随机码。 name是可选的,但建议填写——它会显示在 Seam Console 中,方便识别。- 访问码槽位限制——部分锁具支持的访问码数量有限。请检查
device.properties.max_active_codes_supported。 - 确定失败处理方式: 如果房间预订必须提供访问权限(例如,需要上锁的会议室),则在 Seam 调用失败时抛出错误。如果访问权限是可选的,则记录日志并继续。
4. 预订变更时更新访问码
if (booking.seamAccessCodeId) {
await seam.accessCodes.update({
access_code_id: booking.seamAccessCodeId,
starts_at: booking.startTime,
ends_at: booking.endTime
});
}
if booking.seam_access_code_id:
seam.access_codes.update(
access_code_id=booking.seam_access_code_id,
starts_at=booking.start_time,
ends_at=booking.end_time
)
5. 取消预订时删除访问码
if (booking.seamAccessCodeId) {
await seam.accessCodes.delete({
access_code_id: booking.seamAccessCodeId
});
}
if booking.seam_access_code_id:
seam.access_codes.delete(
access_code_id=booking.seam_access_code_id
)
6. 添加 Webhook 端点
遵循代码库中现有的 Webhook 模式:
router.post("/seam", (req, res) => {
const { event_type, ...data } = req.body;
switch (event_type) {
case "access_code.set_on_device":
// Code is on the lock — safe to share with the user
console.log("Code set:", data.access_code_id);
break;
case "access_code.failed_to_set_on_device":
console.log("Code failed:", data.access_code_id);
break;
case "device.disconnected":
console.log("Lock offline:", data.device_id);
break;
}
res.json({ received: true });
});
7. 将函数改为异步函数
将服务函数改为异步函数,并更新调用方以使用 await。
如果遇到问题,请阅读 references/troubleshooting.md。若要确保生产环境就绪,请阅读 references/production-checklist.md。
评论
支持 Markdown