激活码服务

会员产品 / 兑换码 / 兑换记录

激活码服务覆盖会员产品定义、批量发码、用户兑换、记录查询、运营作废全套链路。所有接口的X-Service-Codeactivation

数据模型

ts
interface ActivationProduct {
  id: string;
  code: string;          // 业务侧用来对齐自己的会员等级(monthly / quarterly / yearly / 自定义)
  name: string;
  durationDays: number;
  price?: number;
  benefits: Record<string, any>;
  isActive: boolean;
}

interface ActivationCode {
  id: string;
  code: string;          // ABCD-1234-EFGH-5678 格式
  productId: string;
  status: "unused" | "used" | "revoked" | "expired";
  expiresAt?: string;
  usedAt?: string;
  usedByPlatformId?: string;
  usedByUserId?: string;
  batchId?: string;
}

列出会员产品

GET/v1/activation/products

返回 { products: ActivationProduct[] }

ts
const { products } = await smp("GET", "/v1/activation/products", "activation");

验证激活码

POST/v1/activation/codes/validate
ts
const r = await smp("POST", "/v1/activation/codes/validate", "activation", {
  code: "ABCD-1234-EFGH-5678"
});
// { valid, code, product? }

兑换

POST/v1/activation/codes/redeem
ts
const r = await smp("POST", "/v1/activation/codes/redeem", "activation", {
  code: "ABCD-1234-EFGH-5678",
  platform_user_id: user.id,                 // 接入方系统中的用户 id
  request_id: `${user.id}-${code}`,           // 幂等键,建议 platformUserId+code
});
// { success, redemptionId, membership: { startDate, endDate, durationDays }, isDuplicate? }

重复请求带相同 request_id 会返回 isDuplicate: true,安全幂等。

查询会员状态

GET/v1/activation/memberships/{platformUserId}
ts
const status = await smp(
  "GET",
  `/v1/activation/memberships/${encodeURIComponent(userId)}`,
  "activation",
);
// { isActive, currentPlan: { productName, startDate, endDate, daysRemaining, benefits }, history: [...] }

兑换记录

GET/v1/activation/redemptions?platform_user_id=&page=&limit=

[Admin] 批量生成

POST/v1/activation/codes/generate
ts
const { batchId, codes, count } = await smp(
  "POST",
  "/v1/activation/codes/generate",
  "activation",
  {
    product_id: "<product id>",
    quantity: 100,
    expires_at: "2027-01-01T00:00:00Z",   // 可选
    notes: "Q4 promo",                    // 可选
  },
);

[Admin] 列出激活码

GET/v1/activation/codes?product_id=&status=&batch_id=&page=&limit=

[Admin] 作废

PATCH/v1/activation/codes/{codeId}/revoke
ts
await smp("PATCH", `/v1/activation/codes/${codeId}/revoke`, "activation");

最佳实践

  • 把 product 的 code 设成接入方系统中可识别的值(如 monthly / yearly),方便业务层做映射。
  • 每个用户触发兑换时用 userId + code 作为 request_id,避免误重发造成多次入会。
  • 批量发码后保留 batchId,运营回查 / 作废用得上。

如果激活码兑换后还要触发自家系统的会员升级逻辑,建议在兑换 API 调用成功后**同步**写自己的 user_membership 表 — 不要依赖 webhook(激活码服务不主动推送)。可以参考快速开始里的 smp() 工具。