seam-reservation-automations

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Seam Reservation Automations

Seam 预订自动化

You are an expert Seam integration engineer. Write the integration code directly into the developer's existing codebase.
您是一位资深的Seam集成工程师。请直接将集成代码写入开发者的现有代码库中。

Approach

实施方案

  1. Move fast. Glob for key files (reservation/booking handlers, routes, models), read them, start writing code.
  2. Write code in existing files. Add Seam calls directly into existing service/handler functions. Don't create wrapper services.
  3. Minimize changes. Only touch files that need Seam calls + webhook route. Install SDK, add import, add calls.
  1. 快速推进:查找关键文件(预订/订单处理程序、路由、模型),读取文件内容后开始编写代码。
  2. 在现有文件中编写代码:直接在现有服务/处理函数中添加Seam调用。不要创建包装服务。
  3. 最小化改动:仅修改需要添加Seam调用的文件以及Webhook路由。安装SDK、添加导入语句、添加调用代码。

How Reservation Automations works

预订自动化的工作原理

The PMS pushes reservation data to Seam via
push_data
. Seam automatically creates time-bound access codes on the unit's smart lock. When the reservation is cancelled,
delete_data
revokes the codes.
The PMS does NOT need to manage individual access codes, devices, or credentials.
PMS通过
push_data
将预订数据推送给Seam。Seam会自动在对应单元的智能锁上创建限时访问码。当预订取消时,
delete_data
会撤销这些访问码。
PMS无需管理单个访问码、设备或凭证。

1. Install SDK + initialize

1. 安装SDK并初始化

Do NOT pin to a specific version.
bash
npm install seam        # Node.js
pip install seam        # Python
bundle add seam         # Ruby
CRITICAL for Next.js:
new Seam()
at module scope BREAKS
next build
. Use a lazy getter:
typescript
import { Seam } from "seam";
let _seam: Seam;
function getSeam() {
  if (!_seam) _seam = new Seam({ apiKey: process.env.SEAM_API_KEY! });
  return _seam;
}
For Express / standard Node.js, module-scope is fine:
typescript
import { Seam } from "seam";
const seam = new Seam({ apiKey: process.env.SEAM_API_KEY });
python
from seam import Seam
seam = Seam(api_key=os.environ["SEAM_API_KEY"])
请勿固定到特定版本
bash
npm install seam        # Node.js
pip install seam        # Python
bundle add seam         # Ruby
Next.js 关键注意事项:在模块作用域使用
new Seam()
会导致
next build
失败。请使用延迟获取器:
typescript
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,模块作用域初始化是可行的:
typescript
import { Seam } from "seam";
const seam = new Seam({ apiKey: process.env.SEAM_API_KEY });
python
from seam import Seam
seam = Seam(api_key=os.environ["SEAM_API_KEY"])

2. Add push_data to reservation creation

2. 在预订创建时添加push_data调用

Add directly inside the create function — not in a helper:
typescript
await seam.customers.pushData({
  customer_key: property.id,           // Your property/PM ID — not a Seam ID
  user_identities: [{
    user_identity_key: `guest_${guest.id}`,
    name: guest.name,
    email_address: guest.email          // Must be unique per guest
  }],
  reservations: [{
    reservation_key: `res_${reservation.id}`,
    user_identity_key: `guest_${guest.id}`,
    starts_at: reservation.checkIn,
    ends_at: reservation.checkOut,
    space_keys: [unit.id]               // Unit ID = space key
  }]
});
python
seam.customers.push_data(
    customer_key=property.id,
    user_identities=[{
        "user_identity_key": f"guest_{guest.id}",
        "name": guest.name,
        "email_address": guest.email
    }],
    reservations=[{
        "reservation_key": f"res_{reservation.id}",
        "user_identity_key": f"guest_{guest.id}",
        "starts_at": reservation.check_in,
        "ends_at": reservation.check_out,
        "space_keys": [unit.id]
    }]
)
直接在创建函数内部添加——不要使用辅助函数:
typescript
await seam.customers.pushData({
  customer_key: property.id,           // 您的物业/物业管理ID——不是Seam生成的ID
  user_identities: [{
    user_identity_key: `guest_${guest.id}`,
    name: guest.name,
    email_address: guest.email          // 每个客人必须唯一
  }],
  reservations: [{
    reservation_key: `res_${reservation.id}`,
    user_identity_key: `guest_${guest.id}`,
    starts_at: reservation.checkIn,
    ends_at: reservation.checkOut,
    space_keys: [unit.id]               // 单元ID = space key
  }]
});
python
seam.customers.push_data(
    customer_key=property.id,
    user_identities=[{
        "user_identity_key": f"guest_{guest.id}",
        "name": guest.name,
        "email_address": guest.email
    }],
    reservations=[{
        "reservation_key": f"res_{reservation.id}",
        "user_identity_key": f"guest_{guest.id}",
        "starts_at": reservation.check_in,
        "ends_at": reservation.check_out,
        "space_keys": [unit.id]
    }]
)

Gotchas

注意事项

  • customer_key
    — use an existing ID from your data model (property ID, PM ID). NOT a Seam-generated ID.
  • space_keys
    — must match the space_key used when the space was created in Seam (typically the unit/room ID).
  • email_address
    — must be unique per guest. Duplicates cause silent failures (
    ok: true
    but no code created).
  • delete_data
    uses
    customer_keys
    (plural list), NOT
    customer_key
    (singular). Different from
    push_data
    .
  • Wrap all Seam calls in try/catch — Seam errors shouldn't break the reservation flow.
  • customer_key
    ——使用您数据模型中的现有ID(物业ID、物业管理ID)。不要使用Seam生成的ID。
  • space_keys
    ——必须与在Seam中创建空间时使用的space_key匹配(通常是单元/房间ID)。
  • email_address
    ——每个客人必须唯一。重复会导致静默失败(返回
    ok: true
    但不会创建访问码)。
  • delete_data
    使用
    customer_keys
    (复数列表),而非
    customer_key
    (单数)。这与
    push_data
    不同。
  • 将所有Seam调用包裹在try/catch块中——Seam的错误不应中断预订流程。

3. Add push_data to reservation updates

3. 在预订更新时添加push_data调用

Same call in the update handler with the same
reservation_key
— Seam detects it's an update:
typescript
await seam.customers.pushData({
  customer_key: property.id,
  reservations: [{
    reservation_key: `res_${reservation.id}`,
    user_identity_key: `guest_${reservation.guestId}`,
    starts_at: reservation.checkIn,
    ends_at: reservation.checkOut,
    space_keys: [reservation.unitId]
  }]
});
在更新处理程序中使用相同的调用和
reservation_key
——Seam会识别出这是更新操作:
typescript
await seam.customers.pushData({
  customer_key: property.id,
  reservations: [{
    reservation_key: `res_${reservation.id}`,
    user_identity_key: `guest_${reservation.guestId}`,
    starts_at: reservation.checkIn,
    ends_at: reservation.checkOut,
    space_keys: [reservation.unitId]
  }]
});

4. Add delete_data to cancellations

4. 在预订取消时添加delete_data调用

typescript
await seam.customers.deleteData({
  customer_keys: [property.id],
  reservation_keys: [`res_${reservation.id}`],
  user_identity_keys: [`guest_${reservation.guestId}`]
});
python
seam.customers.delete_data(
    customer_keys=[property.id],
    reservation_keys=[f"res_{reservation.id}"],
    user_identity_keys=[f"guest_{reservation.guest_id}"]
)
typescript
await seam.customers.deleteData({
  customer_keys: [property.id],
  reservation_keys: [`res_${reservation.id}`],
  user_identity_keys: [`guest_${reservation.guestId}`]
});
python
seam.customers.delete_data(
    customer_keys=[property.id],
    reservation_keys=[f"res_{reservation.id}"],
    user_identity_keys=[f"guest_{reservation.guest_id}"]
)

5. Add webhook endpoint

5. 添加Webhook端点

Find existing webhook handlers and add a Seam endpoint following the same pattern:
typescript
router.post("/seam", (req, res) => {
  const { event_type, ...data } = req.body;
  switch (event_type) {
    case "access_code.set_on_device":
      console.log("Access code set:", data.access_code_id);
      break;
    case "access_code.failed_to_set_on_device":
      console.log("Access code failed:", data.access_code_id);
      break;
    case "device.disconnected":
      console.log("Device disconnected:", data.device_id);
      break;
  }
  res.json({ received: true });
});
找到现有的Webhook处理程序,按照相同的模式添加Seam端点:
typescript
router.post("/seam", (req, res) => {
  const { event_type, ...data } = req.body;
  switch (event_type) {
    case "access_code.set_on_device":
      console.log("Access code set:", data.access_code_id);
      break;
    case "access_code.failed_to_set_on_device":
      console.log("Access code failed:", data.access_code_id);
      break;
    case "device.disconnected":
      console.log("Device disconnected:", data.device_id);
      break;
  }
  res.json({ received: true });
});

6. Make functions async

6. 将函数改为异步

Make service functions async and update callers to await them.
If something goes wrong, read
references/troubleshooting.md
. For production readiness, read
references/production-checklist.md
.
将服务函数改为异步,并更新调用方以使用await等待结果。
如果出现问题,请阅读
references/troubleshooting.md
。如需确保生产环境就绪,请阅读
references/production-checklist.md