关于 raindrop-api
raindrop-api 是面向 Raindrop.io 用户的技能,通过 REST API 管理书签、集合、标签和高亮,并要求破坏性操作先确认。
主要功能
- 01读写书签与批量管理
- 02管理集合和标签
- 03读取与管理高亮
- 04搜索、筛选及导出数据
- 05执行破坏性操作前确认
适用场景
- 01按集合检索或导出书签
- 02创建书签并添加标签
- 03查看书签高亮和过滤统计
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ intellectronica/ agent-skills --skill raindrop-api安装后在 Claude Code 中输入/raindrop-api确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/collections-sharing.mdhighlights.mdsearch-operators.md详细介绍
Raindrop.io API 技能
此技能可通过 REST API 与 Raindrop.io 书签服务交互。使用 curl 和 jq 直接调用 REST API。
官方 API 文档:https://developer.raindrop.io/
身份验证
令牌解析
按以下顺序解析 API 令牌:
- 检查环境变量
RAINDROP_TOKEN - 检查用户是否已在对话上下文中提供令牌
- 如果两者都不可用,则使用 AskUserQuestion 向用户索取令牌
验证环境中是否存在令牌:
[ -n "$RAINDROP_TOKEN" ] && echo "Token available" || echo "Token not set"
快速设置:个人使用或开发时,可在 https://app.raindrop.io/settings/integrations 生成测试令牌——打开应用并复制“Test token”。测试令牌不会过期。
完整的 OAuth2 流程详情请参阅下方的身份验证部分。
发起经过身份验证的请求
所有请求都需要在 Authorization 标头中携带 Bearer 令牌:
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/ENDPOINT"
对于带有 JSON 请求体的 POST/PUT 请求:
curl -s -X POST \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"key": "value"}' \
"https://api.raindrop.io/rest/v1/ENDPOINT"
验证身份验证
通过获取当前用户来测试令牌:
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/user" | jq '.user.fullName'
基础 URL 和约定
- 基础 URL:
https://api.raindrop.io/rest/v1/ - 数据格式:所有请求/响应体均为 JSON
- 时间戳:ISO 8601 格式
- 速率限制:每位经过身份验证的用户每分钟 120 个请求
- CORS:支持基于浏览器的应用
确认要求
执行任何破坏性操作(DELETE、批量更新、移至回收站)之前,务必使用 AskUserQuestion 征求用户确认。 对于一组逻辑上相关的操作,只需确认一次。
破坏性操作包括:
- 删除 raindrop、集合或标签
- 批量更新或移动 raindrop
- 合并或移除标签
- 从共享集合中移除协作者
- 清空回收站
只读操作(GET 请求)无需确认。
端点参考
Raindrop(书签)
文档:https://developer.raindrop.io/v1/raindrops
单个 Raindrop 操作
| 操作 | 方法 | 端点 |
|---|---|---|
| 获取 raindrop | GET | /raindrop/{id} |
| 创建 raindrop | POST | /raindrop |
| 更新 raindrop | PUT | /raindrop/{id} |
| 移除 raindrop | DELETE | /raindrop/{id} |
| 上传文件 | PUT | /raindrop/file |
| 上传封面 | PUT | /raindrop/{id}/cover |
| 获取永久副本 | GET | /raindrop/{id}/cache |
| 建议(新 URL) | POST | /raindrop/suggest |
| 建议(现有项目) | GET | /raindrop/{id}/suggest |
文档:https://developer.raindrop.io/v1/raindrops/single
Raindrop 创建/更新字段:
link(字符串,创建时必填)- 书签 URLtitle(字符串)- 书签标题excerpt(字符串)- 简短描述note(字符串)- 用户备注(支持 Markdown)tags(字符串数组)- 标签名称collection(对象)-{"$id": collectionId}type(字符串)-link、article、image、video、document、audioimportant(布尔值)- 标记为收藏order(数字)- 排序顺序(升序)media(数组)- 媒体/缩略图信息highlights(数组)- 文本高亮cover(字符串)- 封面图片 URL,或使用<screenshot>自动截取pleaseParse(对象)- 使用{}触发后台元数据解析created(字符串)- ISO 8601 创建日期lastUpdate(字符串)- ISO 8601 最后更新日期reminder(对象)- 提醒设置
删除行为:移除 raindrop 会将其移至回收站(集合 ID -99)。从回收站移除则会永久删除。
多个 Raindrop 操作
| 操作 | 方法 | 端点 |
|---|---|---|
| 获取 Raindrop | GET | /raindrops/{collectionId} |
| 创建多个 | POST | /raindrops |
| 更新多个 | PUT | /raindrops/{collectionId} |
| 移除多个 | DELETE | /raindrops/{collectionId} |
| 导出 | GET | /raindrops/{collectionId}/export.{format} |
文档:https://developer.raindrop.io/v1/raindrops/multiple
collectionId 值:
0- 所有 Raindrop-1- 未分类-99- 回收站- 任意正整数 - 指定集合
GET /raindrops/{collectionId} 的查询参数:
sort- 排序顺序:-created(默认)、created、score、-sort、title、-title、domain、-domainperpage- 每页结果数(最多 50)page- 页码(从 0 开始)search- 搜索查询(参见references/search-operators.md)nested- 布尔值,是否包含子集合中的书签
批量更新字段(使用 ids 数组或 search 查询执行 PUT):
important(布尔值)tags(数组)- 追加标签;空数组会清除所有标签media(数组)- 追加媒体;空数组会清除所有媒体cover(字符串)- URL 或<screenshot>collection(对象)- 使用{"$id": collectionId}移动
导出格式:csv、html、zip
集合
文档:https://developer.raindrop.io/v1/collections
| 操作 | 方法 | 端点 |
|---|---|---|
| 列出根集合 | GET | /collections |
| 列出子集合 | GET | /collections/childrens |
| 获取集合 | GET | /collection/{id} |
| 创建集合 | POST | /collection |
| 更新集合 | PUT | /collection/{id} |
| 上传封面 | PUT | /collection/{id}/cover |
| 删除集合 | DELETE | /collection/{id} |
| 删除多个集合 | DELETE | /collections |
| 重新排序/全部展开 | PUT | /collections |
| 合并集合 | PUT | /collections/merge |
| 移除空集合 | PUT | /collections/clean |
| 清空回收站 | DELETE | /collection/-99 |
| 系统集合计数 | GET | /user/stats |
| 搜索封面/图标 | GET | /collections/covers/{text} |
| 精选封面 | GET | /collections/covers |
文档:https://developer.raindrop.io/v1/collections/methods
集合字段:
title(字符串)- 集合名称view(字符串)- 显示样式:list、simple、grid、masonrypublic(布尔值)- 是否可公开访问parent(对象)- 使用{"$id": parentCollectionId}设置嵌套sort(数字)- 排序位置cover(数组)- 封面图片 URLexpanded(布尔值)- 是否展开子集合color(字符串)- 集合颜色
系统集合(不可移除):
- ID
-1- “未分类” - ID
-99- “回收站”
访问级别(access.level):
1- 只读2- 协作者(可写)3- 协作者(可写 + 管理)4- 所有者
有关共享/协作者的信息,请参见 references/collections-sharing.md。
标签
文档:https://developer.raindrop.io/v1/tags
| 操作 | 方法 | 端点 |
|---|---|---|
| 获取标签 | GET | /tags/{collectionId} |
| 重命名标签 | PUT | /tags/{collectionId} |
| 合并标签 | PUT | /tags/{collectionId} |
| 移除标签 | DELETE | /tags/{collectionId} |
collectionId:省略或使用 0 获取所有集合中的标签。
获取标签的响应:
{
"result": true,
"items": [{"_id": "tagname", "count": 42}]
}
重命名标签:
curl -s -X PUT \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"replace": "new-name", "tags": ["old-name"]}' \
"https://api.raindrop.io/rest/v1/tags/0"
合并标签(同一端点,数组中包含多个标签):
curl -s -X PUT \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"replace": "merged-name", "tags": ["tag1", "tag2", "tag3"]}' \
"https://api.raindrop.io/rest/v1/tags/0"
移除标签:
curl -s -X DELETE \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"tags": ["tag-to-remove"]}' \
"https://api.raindrop.io/rest/v1/tags/0"
高亮
文档:https://developer.raindrop.io/v1/highlights
| 操作 | 方法 | 端点 |
|---|---|---|
| 获取所有高亮 | GET | /highlights |
| 获取集合高亮 | GET | /highlights/{collectionId} |
| 获取 Raindrop 高亮 | GET | /raindrop/{id} |
| 添加高亮 | PUT | /raindrop/{id} |
| 更新高亮 | PUT | /raindrop/{id} |
| 删除高亮 | PUT | /raindrop/{id} |
详情请参见 references/highlights.md。
筛选器
文档:https://developer.raindrop.io/v1/filters
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/filters/{collectionId}" | jq '.'
使用 0 表示所有收藏集。返回失效链接、重复项、收藏项、未添加标签的项目、标签和内容类型的汇总计数。
查询参数:
tagsSort--count(默认)或_id(按字母顺序)search- 其他搜索筛选条件
用户
文档:https://developer.raindrop.io/v1/user
| 操作 | 方法 | 端点 |
|---|---|---|
| 获取当前用户 | GET | /user |
| 更新用户 | PUT | /user |
导入
文档:https://developer.raindrop.io/v1/import
| 操作 | 方法 | 端点 |
|---|---|---|
| 解析 URL | GET | /import/url/parse?url={url} |
| 检查 URL 是否存在 | POST | /import/url/exists |
| 解析 HTML 书签文件 | POST | /import/file |
备份
文档:https://developer.raindrop.io/v1/backups
| 操作 | 方法 | 端点 |
|---|---|---|
| 列出备份 | GET | /backups |
| 下载备份 | GET | /backup/{id}.{format} |
| 生成新备份 | GET | /backup |
格式:html 或 csv
身份验证:OAuth2 流程
文档:https://developer.raindrop.io/v1/authentication/token
对于访问其他用户数据的应用(非个人用途),请使用完整的 OAuth2 流程:
步骤 1:授权
将用户引导至:
https://raindrop.io/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code
步骤 2:用授权码交换令牌
curl -s -X POST "https://raindrop.io/oauth/access_token" \
-H "Content-Type: application/json" \
-d '{
"code": "AUTH_CODE",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"redirect_uri": "YOUR_REDIRECT_URI",
"grant_type": "authorization_code"
}' | jq '.'
响应:
{
"access_token": "...",
"refresh_token": "...",
"expires_in": 1209599,
"token_type": "Bearer"
}
步骤 3:刷新令牌
访问令牌在两周后过期。使用以下方式刷新:
curl -s -X POST "https://raindrop.io/oauth/access_token" \
-H "Content-Type: application/json" \
-d '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"refresh_token": "YOUR_REFRESH_TOKEN",
"grant_type": "refresh_token"
}' | jq '.'
错误处理
检查 HTTP 状态码:
200- 成功204- 成功,无内容400- 请求错误401- 身份验证失败(检查令牌)403- 禁止访问(权限不足)404- 未找到资源429- 超出速率限制(超过 120 次请求/分钟)5xx- 服务端错误
错误处理示例
response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/raindrops/0")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
echo "$body" | jq '.'
else
echo "Error: HTTP $http_code"
echo "$body"
fi
常见模式
列出收藏集中的所有书签
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/raindrops/COLLECTION_ID?perpage=50" | jq '.items[] | {title, link}'
创建书签
curl -s -X POST \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"link": "https://example.com",
"title": "Example Site",
"tags": ["reference", "example"],
"collection": {"$id": COLLECTION_ID},
"pleaseParse": {}
}' \
"https://api.raindrop.io/rest/v1/raindrop" | jq '.'
搜索书签
# Search across all collections
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/raindrops/0?search=YOUR_QUERY" | jq '.items[] | {title, link}'
# Search with tag filter
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/raindrops/0?search=%23tagname" | jq '.items[] | {title, link}'
完整的搜索查询语法请参阅 references/search-operators.md。
将书签移至收藏集
curl -s -X PUT \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"collection": {"$id": TARGET_COLLECTION_ID}}' \
"https://api.raindrop.io/rest/v1/raindrop/RAINDROP_ID" | jq '.'
获取所有标签
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/tags/0" | jq '.items[] | {tag: ._id, count}'
创建收藏集
curl -s -X POST \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "My Collection", "view": "list"}' \
"https://api.raindrop.io/rest/v1/collection" | jq '.'
列出所有收藏集(根级 + 子级)
# Root collections
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/collections" | jq '.items[] | {id: ._id, title}'
# Child collections
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/collections/childrens" | jq '.items[] | {id: ._id, title, parent: .parent."$id"}'
分页遍历所有书签
page=0
while true; do
response=$(curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/raindrops/0?perpage=50&page=$page")
count=$(echo "$response" | jq '.items | length')
echo "$response" | jq '.items[] | {title, link}'
if [ "$count" -lt 50 ]; then
break
fi
page=$((page + 1))
done
导出书签
# Export all bookmarks as CSV
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/raindrops/0/export.csv" -o bookmarks.csv
# Export as HTML
curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" \
"https://api.raindrop.io/rest/v1/raindrops/0/export.html" -o bookmarks.html
检查 URL 是否已保存
curl -s -X POST \
-H "Authorization: Bearer $RAINDROP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://example.com"]}' \
"https://api.raindrop.io/rest/v1/import/url/exists" | jq '.'
分页
Raindrop 使用基于页码的分页(而非基于游标的分页):
page- 页码(从 0 开始)perpage- 每页项目数(最多 50;高亮内容默认 25)
当返回的项目数少于 perpage 时,表示已到最后一页。
嵌套收藏集结构
收藏集按层级组织。要重建完整的侧边栏,需要:
GET /user- 返回包含收藏集排序信息的groups数组GET /collections- 根级收藏集GET /collections/childrens- 嵌套收藏集
根级收藏集的排序会保存在用户的 groups[].collections 数组中。子收藏集的排序保存在收藏集的 sort 字段中。
其他参考资料
有关具体主题的详细文档,请参阅:
references/search-operators.md- 搜索查询语法和运算符references/collections-sharing.md- 收藏集共享和协作者references/highlights.md- 高亮内容管理
工作流摘要
- 解析令牌 - 从环境、上下文中获取,或询问用户
- 验证身份验证 - 使用
GET /user进行测试 - 读取操作 - 无需确认,直接执行
- 写入操作 - 执行前先征求确认
- 处理分页 - 按页码循环,直到项目数少于
perpage - 解析响应 - 使用 jq 提取并格式化数据