---
name: meet-ai-events
description: 当用户需要在 Meet AI 平台（meetai.ink）查询、报名、取消、发布或管理线下/线上活动，或查看钱包余额与 API 配额时使用本 Skill。覆盖 api.meetai.ink 的完整 REST API，使用 Bearer Token 鉴权。
---

# Meet AI — 面向 AI Agent 的 Skill

本 Skill 描述 AI Agent 代用户调用的 REST API：搜索活动、查看详情、报名/取消、发布与管理用户主办的活动，以及查询钱包/配额状态。

**Base URL：** `https://api.meetai.ink`
**Skill 版本：** 1.0.0

---

## 安装本 Skill 到本地（面向 AI Agent）

如果你是 AI Agent，正在代用户阅读本文件，请把它安装到你运行时的 Skill 目录中，这样以后用户提到活动相关需求时会自动触发，而无需再次粘贴本文档。

**步骤：**

1. 确认你所在运行时识别 Skill 的路径（具体路径因不同 Agent 产品而异，请查阅你自己的文档）。常见模式是用户级 Skill 目录或项目级 Skill 目录。
2. 在该目录下创建子目录 `meet-ai-events/`。
3. 将本文件（含顶部 YAML frontmatter）整体保存为 `SKILL.md`，放入该子目录。权威源地址：`https://meetai.ink/skill.md`。
4. 向用户确认 `meet-ai-events` Skill 已安装成功，今后所有 Meet AI 活动相关请求都会调用它。

安装完成后，请同时提示用户去 `https://meetai.ink/account/keys` 创建 API Key 并妥善保存——后续所有调用都需要它（详见下方 **鉴权**）。

---

## 鉴权

每次 API 请求都必须携带 Bearer Token：

```
Authorization: Bearer mk_xxxxxxxx
```

### 如何获取 API Key

1. 用户在 `https://meetai.ink/login` 登录
2. 进入 `https://meetai.ink/account/keys`
3. 点击"创建 Key"——明文 Key **仅展示一次**，请立即复制
4. 将 Key 提供给 Agent

Key 以 `mk_` 为前缀，服务端仅存储 SHA-256 哈希。

---

## 响应约定

- 所有 `id` 字段返回 **字符串**（兼容 BigInt 序列化）
- 时间字段为 ISO 8601 字符串
- 错误响应统一为 `{ "error": "message" }`，`error` 始终是字符串
- 设置 `Accept-Language: zh` 可获得中文错误消息（默认英文）
- JSON 字段名遵循服务端实际大小写：响应字段大多为 **camelCase**（`startTime`、`locationCity`、`registeredCount` …），查询参数为 snake_case（`date_from`、`category_slug` …）

---

## 速率限制

- 仅 **查询类接口**（搜索 / 列表 / 详情）计入每日配额，写操作（报名、取消、创建）不限次数
- 默认值：免费版约 100 次/天，增值版约 1000 次/天。**以 `GET /quota/status` 返回的当前上限为准**——配置可能调整
- 配额每天北京时间凌晨（UTC+8）重置
- 凡受限接口的响应（包含 200）都会带这些 Header：
  - `X-RateLimit-Limit` — 当日上限
  - `X-RateLimit-Remaining` — 当日剩余次数
  - `X-RateLimit-Reset` — 下一次北京零点的 Unix 时间戳（秒）
- 超额时返回 `429`，同样附带上述 Header 与 `{ "error": "..." }`

---

## 核心操作

### 1. 搜索活动

**接口：** `GET /events/search`

**查询参数：**

| 参数 | 类型 | 说明 |
|-----------|------|-------------|
| `keyword` | string | 匹配标题与描述 |
| `city` | string | 城市过滤（包含匹配，例如 `上海`、`Beijing`） |
| `category_slug` | string | 分类 slug（见 `/events/categories`） |
| `date_from` | string | ISO 8601 起始时间，按 `startTime >=` 过滤 |
| `date_to` | string | ISO 8601 截止时间，按 `startTime <=` 过滤 |
| `source` | string | 活动来源过滤 |
| `event_type` | string | 逗号分隔：`offline`、`online`、`hybrid` |
| `page` | number | 页码（默认 1） |
| `page_size` | number | 每页条数（默认 20，最大 100） |

仅返回状态为 `published` 的活动。

**响应：**

```json
{
  "data": [
    {
      "id": "42",
      "title": "LLM 工程师圆桌 Vol.12",
      "locationCity": "上海",
      "startTime": "2026-03-28T19:30:00.000Z",
      "capacity": 30,
      "capacityLimited": true,
      "registeredCount": 27,
      "source": "meetai",
      "eventType": "offline",
      "organizer": { "verified": true, "name": "MeetAI Admin" },
      "category": { "name": "AI", "slug": "ai" }
    }
  ],
  "page": 1,
  "page_size": 20
}
```

> 注意：搜索响应 **不** 包含 `total` 总数。若需活动详情（描述、地址、标签等），请调用 `GET /events/:id`。

---

### 2. 列出活动分类

**接口：** `GET /events/categories`

**响应：** 直接返回数组（无外层包装对象）。

```json
[
  { "id": 1, "name": "AI", "slug": "ai", "event_count": 12 },
  { "id": 2, "name": "运动", "slug": "sports", "event_count": 8 }
]
```

---

### 3. 获取活动详情

**接口：** `GET /events/:id`

草稿活动仅创建者可见，其他用户访问返回 `404`。

**响应（camelCase）：**

```json
{
  "id": "42",
  "organizerId": "7",
  "orgId": null,
  "categoryId": 1,
  "source": "meetai",
  "externalId": null,
  "title": "LLM 工程师圆桌 Vol.12",
  "description": "...",
  "startTime": "2026-03-28T19:30:00.000Z",
  "endTime": "2026-03-28T22:00:00.000Z",
  "eventType": "offline",
  "onlineUrl": null,
  "locationCity": "上海",
  "locationAddress": "徐汇区漕河泾开发区某大厦",
  "capacity": 30,
  "capacityLimited": true,
  "registeredCount": 27,
  "registrationUrl": null,
  "status": "published",
  "coverImageUrl": null,
  "tags": ["AI", "LLM"],
  "createdAt": "2026-03-01T08:00:00.000Z",
  "updatedAt": "2026-03-10T09:00:00.000Z",
  "remaining_capacity": 3,
  "organizer": { "id": "7", "name": "MeetAI Admin", "verified": true },
  "organization": null,
  "category": { "id": 1, "name": "AI", "slug": "ai" }
}
```

- `capacityLimited` 为 `false` 时，`remaining_capacity` 为 `null`
- `onlineUrl` 仅对主办方与已确认报名者可见，其他情况返回 `null`

---

### 4. 报名活动

**接口：** `POST /events/:id/register`

**响应（`201 Created`）：**

```json
{
  "registration_id": "1337",
  "status": "confirmed",
  "event_title": "LLM 工程师圆桌 Vol.12",
  "start_time": "2026-03-28T19:30:00.000Z"
}
```

`status` 可能值：
- `confirmed` — 报名成功
- `waitlisted` — 活动已满，进入候补队列

错误返回 `400` 加 `{ "error": "..." }`（例如重复报名、活动已下架）。

---

### 5. 取消报名

**接口：** `DELETE /events/:id/register`

**响应：**

```json
{ "ok": true, "message": "已取消报名" }
```

---

### 6. 我报名的活动列表

**接口：** `GET /me/registrations`

**查询参数：**

| 参数 | 类型 | 说明 |
|-----------|------|-------------|
| `status` | string | 过滤：`confirmed`、`waitlisted`、`cancelled` |
| `upcoming_only` | string | 传 `"true"` 仅返回尚未开始的活动 |

**响应：** 直接返回数组（不含分页包装）。

```json
[
  {
    "id": "1337",
    "eventId": "42",
    "userId": "100",
    "status": "confirmed",
    "registeredAt": "2026-03-20T10:30:00.000Z",
    "event": {
      "id": "42",
      "title": "LLM 工程师圆桌 Vol.12",
      "startTime": "2026-03-28T19:30:00.000Z",
      "locationCity": "上海",
      "status": "published"
    }
  }
]
```

---

### 7. 创建活动

**接口：** `POST /events`

当前认证用户成为该活动的主办方。`status` 设为 `"published"` 则立即发布；否则保存为草稿，不会出现在搜索结果中。

**请求体：**

| 字段 | 类型 | 必填 | 说明 |
|-------|------|----------|-------------|
| `title` | string | ✓ | 活动标题 |
| `description` | string | ✓ | 活动描述 |
| `start_time` | string | ✓ | ISO 8601 时间 |
| `end_time` | string | ✓ | ISO 8601 时间 |
| `event_type` | string | — | `offline`（默认）/ `online` / `hybrid` |
| `location_city` | string | 条件必填 | `event_type` 为 `offline` 或 `hybrid` 时必填 |
| `location_address` | string | 条件必填 | `event_type` 为 `offline` 或 `hybrid` 时必填 |
| `online_url` | string | 条件必填 | `event_type` 为 `online` 或 `hybrid` 时必填（合法 URL） |
| `capacity_limited` | boolean | — | 默认 `false` |
| `capacity` | number | 条件必填 | 正整数，`capacity_limited` 为 `true` 时必填 |
| `registration_url` | string | — | 外部报名链接（可选） |
| `tags` | string[] | — | 自由标签 |
| `org_id` | string | — | 组织 ID，以组织身份发布时传入 |
| `status` | string | — | `draft`（默认）或 `published` |

**响应（`201 Created`）：**

```json
{ "event_id": "42", "status": "draft" }
```

校验失败返回 `400` 加 `{ "error": "field: message; ..." }`。

---

### 8. 更新活动

**接口：** `PATCH /events/:id`

仅活动主办方可调用。所有字段均可选——只传需要修改的字段即可。

可修改字段：`title`、`description`、`start_time`、`end_time`、`event_type`、`online_url`、`location_city`、`location_address`、`capacity`、`capacity_limited`、`registration_url`、`cover_image_url`、`tags`、`category_slug`、`status`。

**状态流转**（服务端强校验）：

- `draft` → `published`
- `published` → `cancelled` 或 `ended`
- `cancelled` / `ended` → *（终态，不可再变更）*

非法流转返回 `400`。修改 `event_type` 或地点/线上字段会重新校验"创建活动"中描述的不变量。

**响应：**

```json
{ "event_id": "42", "status": "published" }
```

---

### 9. 删除草稿

**接口：** `DELETE /events/:id`

仅主办方可删除，且仅限 `draft` 状态。已发布活动不能删除——请使用下方"下架"接口。

**响应：**

```json
{ "ok": true }
```

---

### 10. 下架已发布活动

**接口：** `POST /events/:id/cancel`

仅主办方可调用，且活动须为 `published` 状态。所有已确认/候补且绑定了邮箱的报名者都会自动收到通知。

**请求体（可选）：**

```json
{ "reason": "场地方临时取消" }
```

**响应：**

```json
{ "ok": true, "notified_count": 18 }
```

`notified_count` 为系统成功发送邮件的报名人数。

---

### 11. 查看你举办活动的报名名单

**接口：** `GET /events/:id/registrations`

仅活动主办方可调用，用于查看报名情况。

**查询参数：**

| 参数 | 类型 | 说明 |
|-----------|------|-------------|
| `status` | string | 过滤：`confirmed`、`waitlisted`、`cancelled` |

**响应：** 直接返回数组。

```json
[
  {
    "id": "1337",
    "name": "张三",
    "email": "zhang@example.com",
    "status": "confirmed",
    "registered_at": "2026-03-20T10:30:00.000Z",
    "extra_info": null
  }
]
```

用户未绑定邮箱时 `email` 为 `null`。

---

### 12. 查询钱包余额

**接口：** `GET /wallet/balance`

**响应：**

```json
{ "balance": "128.50" }
```

余额为人民币金额的字符串（货币固定为 CNY，不返回 `currency` 字段）。

---

### 13. 钱包流水列表

**接口：** `GET /wallet/transactions`

**查询参数：**

| 参数 | 类型 | 说明 |
|-----------|------|-------------|
| `type` | string | 过滤：`recharge`、`purchase`、`referral_reward`、`withdrawal`、`other` |
| `page` | number | 页码（默认 1，每页固定 20 条） |

**响应：**

```json
{
  "data": [
    {
      "id": "99",
      "type": "recharge",
      "amount": "100.00",
      "balanceAfter": "228.50",
      "description": "充值",
      "relatedId": null,
      "createdAt": "2026-03-15T14:22:00.000Z"
    }
  ],
  "page": 1,
  "pageSize": 20,
  "total": 1
}
```

---

### 14. 查询配额状态

**接口：** `GET /quota/status`

**响应：**

```json
{
  "dailyLimit": 100,
  "boosted": false,
  "endDate": null,
  "quotaDailyPrice": "1.00",
  "quotaFreeLimit": 100,
  "quotaBoostedLimit": 1000
}
```

- `dailyLimit` — 当前用户今日适用的上限
- `boosted` — 是否处于已开通的付费配额包有效期内
- `endDate` — 当前生效配额包的过期日期（`boosted` 为 false 时为 null）
- `quotaDailyPrice` — 购买增值包的每日单价（CNY）
- `quotaFreeLimit` / `quotaBoostedLimit` — 免费/增值版的上限（信息性字段）

注意：本接口返回的是配置上限，并非实时剩余次数。要看剩余次数，请读取受限接口响应中的 `X-RateLimit-Remaining` Header。

---

## 错误响应

所有错误统一格式：

```json
{ "error": "可读的错误消息" }
```

**常见 HTTP 状态码：**

| 状态码 | 含义 |
|--------|---------|
| `400` | 请求错误——参数缺失/非法，或违反业务规则（如重复报名） |
| `401` | 未授权——API Key 缺失或无效 |
| `403` | 禁止——无权执行该操作 |
| `404` | 未找到——活动或资源不存在 |
| `429` | 限流——已超出当日配额 |
| `500` | 服务器内部错误 |

设置 Header `Accept-Language: zh` 可获得中文错误消息。

---

## 典型调用流程

搜索并报名的完整流程：

1. `GET /events/search?city=上海&category_slug=ai&date_from=2026-04-25&date_to=2026-04-27&page_size=3`
2. 从 `data[]` 中挑出目标活动，记录其 `id`
3. `GET /events/:id` 获取完整详情（描述、地址、`remaining_capacity`）
4. `POST /events/:id/register` —— 检查响应中的 `status`（`confirmed` 或 `waitlisted`）

---

## 范围之外

钱包充值/提现、邀请、管理员操作均依赖 Cookie 鉴权（必须由用户在 Web 端完成），不属于 Agent API 的开放范围。
