API 参考
基础 URL: https://open.utm.bar/v1
认证方式: Authorization: Bearer sk_live_xxxx 或 X-API-Key: sk_live_xxxx
短链接
创建短链接
POST /v1/links
所需权限: links:write
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
original_url | string | ✅ | 目标跳转 URL |
title | string | — | 链接展示名称 |
custom_code | string | — | 自定义短码(a-z A-Z 0-9 - _,长度 2–64) |
external_id | string | — | 外部系统引用 ID,透传存储(最大 255 字符) |
expires_at | ISO 8601 | — | 过期时间,null 表示永不过期 |
utm_source | string | — | UTM source 参数 |
utm_medium | string | — | UTM medium 参数 |
utm_campaign | string | — | UTM campaign 参数 |
utm_term | string | — | UTM term 参数 |
utm_content | string | — | UTM content 参数 |
campaign_id | string | — | 将链接归入指定活动(活动 UUID) |
domain_id | string | — | 自定义域名 ID(来自 POST /v1/domains) |
curl -X POST https://open.utm.bar/v1/links \
-H "Authorization: Bearer sk_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"original_url": "https://example.com/page",
"title": "我的链接",
"custom_code": "launch-2026",
"utm_source": "twitter",
"utm_medium": "social"
}'
响应 201 Created
{
"data": {
"id": "...",
"code": "launch-2026",
"short_url": "https://utm.bar/launch-2026",
"original_url": "https://example.com/page",
"title": "我的链接",
"is_active": true,
"click_count": 0,
"external_id": "order_98765",
"expires_at": null,
"domain_id": null,
"domain": null,
"campaign_id": null,
"utm_source": "twitter",
"utm_medium": "social",
"created_at": "2026-05-25T00:00:00Z"
}
}
传入
domain_id可绑定自定义域名,详见自定义域名。绑定后short_url将使用你自己的域名替代utm.bar。 自定义短码冲突时返回409 Conflict。
列出短链接
GET /v1/links
所需权限: links:read
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page | integer | 1 | 页码 |
page_size | integer | 20 | 每页条数(最大 100) |
q | string | — | 按标题或目标 URL 搜索 |
is_active | boolean | — | 按启用/禁用状态过滤 |
curl "https://open.utm.bar/v1/links?page=1&page_size=20" \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
{
"data": {
"items": [ /* 链接对象数组 */ ],
"total": 42,
"page": 1,
"page_size": 20
}
}
获取单条链接
GET /v1/links/:id
所需权限: links:read
curl https://open.utm.bar/v1/links/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK — 返回单个链接对象。路径参数为创建时返回的链接 id (UUID)。
按 External ID 获取链接
GET /v1/links/external/:external_id
所需权限: links:read
根据创建时传入的 external_id 反向查找短链接,语义与按链接 ID 查找对称。未找到返回 404。
curl https://open.utm.bar/v1/links/external/order_98765 \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
{
"data": {
"id": "...",
"code": "launch-2026",
"short_url": "https://utm.bar/launch-2026",
"original_url": "https://example.com/page",
"external_id": "order_98765",
"is_active": true,
"click_count": 42,
"domain_id": null,
"domain": null,
"campaign_id": null,
"created_at": "2026-05-25T00:00:00Z"
}
}
更新链接元数据
PATCH /v1/links/:id
所需权限: links:write
original_url和code创建后不可修改。如需更换目标地址,请创建新链接并停用旧的。
请求体(所有字段可选)
| 字段 | 类型 | 说明 |
|---|---|---|
title | string | 新标题 |
expires_at | ISO 8601 / null | 更新或清除过期时间 |
utm_source | string | 更新 UTM source |
utm_medium | string | 更新 UTM medium |
utm_campaign | string | 更新 UTM campaign |
utm_term | string | 更新 UTM term |
utm_content | string | 更新 UTM content |
curl -X PATCH https://open.utm.bar/v1/links/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer sk_live_xxxx" \
-H "Content-Type: application/json" \
-d '{ "title": "新标题", "expires_at": "2026-12-31T23:59:59Z" }'
响应 200 OK — 返回更新后的链接对象。
禁用链接
POST /v1/links/:id/disable
所需权限: links:delete
curl -X POST https://open.utm.bar/v1/links/550e8400-e29b-41d4-a716-446655440000/disable \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
启用链接
POST /v1/links/:id/enable
所需权限: links:write
curl -X POST https://open.utm.bar/v1/links/550e8400-e29b-41d4-a716-446655440000/enable \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
删除链接
DELETE /v1/links/:id
所需权限: links:delete
删除操作不可撤销。如果日后可能还需要这个链接,建议改用禁用操作。
curl -X DELETE https://open.utm.bar/v1/links/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer sk_live_xxxx"
响应 204 No Content
获取点击统计
GET /v1/links/:id/stats
所需权限: links:read
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
start | YYYY-MM-DD | 近 7 天 | 起始日期(含) |
end | YYYY-MM-DD | 今天 | 截止日期(含) |
tz | IANA 时区名 | UTC | 用于按时区聚合日期边界 |
granularity | string | day | 聚合粒度:day / week / month / year |
daily 中的 date 始终为 YYYY-MM-DD 格式,表示该周期的起始日(week 为周一,month 为1日,year 为1月1日)。
curl "https://open.utm.bar/v1/links/550e8400-e29b-41d4-a716-446655440000/stats?start=2026-01-01&end=2026-05-25&granularity=month&tz=Asia/Shanghai" \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
{
"data": {
"total_clicks": 1024,
"unique_clicks": 876,
"tz": "Asia/Shanghai",
"granularity": "month",
"daily": [
{ "date": "2026-01-01", "clicks": 200, "unique_clicks": 180 },
{ "date": "2026-02-01", "clicks": 180, "unique_clicks": 160 }
],
"countries": [
{ "name": "China", "clicks": 600 },
{ "name": "United States", "clicks": 200 }
],
"devices": [
{ "name": "Mobile", "clicks": 700 },
{ "name": "Desktop", "clicks": 300 }
],
"browsers": [
{ "name": "Chrome", "clicks": 500 }
],
"oses": [
{ "name": "Android", "clicks": 400 }
],
"referers": [
{ "name": "Direct", "clicks": 300 },
{ "name": "https://twitter.com", "clicks": 150 }
]
}
}
批量获取点击统计
POST /v1/links/batch-stats
所需权限: links:read
一次请求最多查询 50 条短链接的点击统计,格式与单链接统计接口一致,适合批量展示仪表盘数据。
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
ids | string[] | ✅ | 链接 ID 数组(UUID,最多 50 条) |
start | YYYY-MM-DD | — | 起始日期,默认近 7 天 |
end | YYYY-MM-DD | — | 截止日期,默认今天 |
tz | IANA 时区名 | — | 时区,默认 UTC |
granularity | string | — | 聚合粒度:day(默认)/ week / month / year |
curl -X POST https://open.utm.bar/v1/links/batch-stats \
-H "Authorization: Bearer sk_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"ids": ["550e8400-e29b-41d4-a716-446655440000", "660e8400-e29b-41d4-a716-446655440001"],
"start": "2026-05-01",
"end": "2026-05-25",
"tz": "Asia/Shanghai",
"granularity": "week"
}'
响应 200 OK
{
"data": {
"start": "2026-05-01",
"end": "2026-05-25",
"tz": "Asia/Shanghai",
"granularity": "week",
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"total_clicks": 1024,
"unique_clicks": 876,
"daily": [
{ "date": "2026-04-28", "clicks": 200, "unique_clicks": 180 }
],
"countries": [{ "name": "China", "clicks": 600 }],
"devices": [{ "name": "Mobile", "clicks": 700 }],
"browsers": [{ "name": "Chrome", "clicks": 500 }],
"oses": [{ "name": "Android", "clicks": 400 }],
"referers": [{ "name": "Direct", "clicks": 300 }]
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"total_clicks": 0,
"unique_clicks": 0,
"daily": [],
"countries": [], "devices": [], "browsers": [], "oses": [], "referers": []
}
]
}
}
无权限或不存在的链接 ID 该条目会附带
"error"字段说明原因,不影响其他条目返回。
活动(Campaigns)
活动用于将多条短链接归组,便于整体追踪一次营销投放的效果。
创建活动
POST /v1/campaigns
所需权限: campaigns:write
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | ✅ | 活动名称 |
description | string | — | 活动描述 |
base_url | string | ✅ | 关联的目标网站域名 |
external_id | string | — | 外部系统活动 ID(最大 255 字符,团队内唯一) |
curl -X POST https://open.utm.bar/v1/campaigns \
-H "Authorization: Bearer sk_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Q2 增长活动",
"base_url": "https://example.com",
"external_id": "campaign_q2_2026"
}'
响应 201 Created
{
"data": {
"id": "...",
"name": "Q2 增长活动",
"description": "",
"base_url": "https://example.com",
"external_id": "campaign_q2_2026",
"total_links": 0,
"total_clicks": 0,
"created_at": "2026-05-25T00:00:00Z",
"updated_at": "2026-05-25T00:00:00Z"
}
}
列出活动
GET /v1/campaigns
所需权限: campaigns:read
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page | integer | 1 | 页码 |
limit | integer | 20 | 每页条数(最大 100) |
响应 200 OK — items 为活动对象数组,附带 total、page、page_size。
获取活动详情
GET /v1/campaigns/:id
所需权限: campaigns:read
响应 200 OK — 返回单个活动对象。
按 External ID 获取活动
GET /v1/campaigns/external/:external_id
所需权限: campaigns:read
根据创建时传入的 external_id 反向查找活动。未找到返回 404。
删除活动
DELETE /v1/campaigns/:id
所需权限: campaigns:write
删除活动不会删除其下的短链接,链接会变为无活动归属状态。
响应 204 No Content
获取活动下的链接
GET /v1/campaigns/:id/links
所需权限: campaigns:read
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page | integer | 1 | 页码 |
limit | integer | 50 | 每页条数(最大 200) |
响应 200 OK — 结构与列出短链接一致。
获取活动统计
GET /v1/campaigns/:id/stats
所需权限: campaigns:read
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
days | integer | 30 | 统计近 N 天(最大 365) |
curl "https://open.utm.bar/v1/campaigns/campaign-uuid/stats?days=30" \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
{
"data": {
"campaign_id": "...",
"days": 30,
"total_clicks": 3840,
"unique_clicks": 2910,
"daily": [
{ "date": "2026-05-01", "clicks": 120, "unique_clicks": 95 }
],
"links": [
{
"short_code": "launch-tw",
"utm_source": "twitter",
"utm_medium": "social",
"utm_campaign": "launch-2026",
"clicks": 1200
}
],
"sources": [
{ "name": "twitter", "clicks": 1200 },
{ "name": "email", "clicks": 980 }
],
"mediums": [
{ "name": "social", "clicks": 1200 },
{ "name": "cpc", "clicks": 980 }
]
}
}
自定义域名
绑定你自己的域名(如 s.example.com)作为短链接域名,代替默认的 utm.bar。域名绑定并验证通过后,创建短链时传入 domain_id 即可使用该自定义域名生成 short_url。
绑定域名
POST /v1/domains
所需权限: domains:write
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
domain | string | ✅ | 要绑定的域名(如 s.example.com 或 example.com) |
- 子域名(如
s.example.com):通过 CNAME 记录验证,指向平台提供的公共域名。 - Apex 域名(如
example.com):通过 A 记录验证,指向平台提供的公共 IP。
curl -X POST https://open.utm.bar/v1/domains \
-H "Authorization: Bearer sk_live_xxxx" \
-H "Content-Type: application/json" \
-d '{ "domain": "s.example.com" }'
响应 201 Created
{
"data": {
"id": "d_abc123...",
"domain": "s.example.com",
"status": "pending",
"is_apex": false,
"verification_type": "cname",
"verification_value": "redirect.utm.bar",
"created_at": "2026-07-03T00:00:00Z"
}
}
列出已绑定域名
GET /v1/domains
所需权限: domains:read
返回当前团队绑定的所有域名,按创建时间倒序。
curl https://open.utm.bar/v1/domains \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
{
"data": {
"items": [
{
"id": "d_abc123...",
"domain": "s.example.com",
"status": "active",
"is_apex": false,
"verification_type": "cname",
"verification_value": "redirect.utm.bar",
"verified_at": "2026-07-03T01:00:00Z",
"cert_expires_at": "2026-10-01T00:00:00Z",
"created_at": "2026-07-03T00:00:00Z"
}
]
}
}
获取域名详情
GET /v1/domains/:id
所需权限: domains:read
curl https://open.utm.bar/v1/domains/d_abc123... \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK — 返回单个域名对象。
删除域名绑定
DELETE /v1/domains/:id
所需权限: domains:write
删除域名绑定不会删除关联的短链接,它们会回退到默认的
utm.bar域名。
curl -X DELETE https://open.utm.bar/v1/domains/d_abc123... \
-H "Authorization: Bearer sk_live_xxxx"
响应 204 No Content
验证域名 DNS
POST /v1/domains/:id/verify
所需权限: domains:write
触发 DNS 验证检查。如果 DNS 记录配置正确,域名将被标记为已验证,SSL 证书将在后台自动签发。
域名状态流转:
pending→(DNS 匹配)→verifying→(SSL 签发完成)→active
curl -X POST https://open.utm.bar/v1/domains/d_abc123.../verify \
-H "Authorization: Bearer sk_live_xxxx"
响应 200 OK
{
"data": {
"matched": true,
"message": "DNS 验证成功,SSL 证书正在后台签发。"
}
}
DNS 尚未配置时:
{
"data": {
"matched": false,
"message": "DNS 记录尚未配置,请按要求添加 DNS 记录后重试。"
}
}
频率限制
限流以团队为粒度,同一团队下所有 API Key 共享配额。
| 请求类型 | 限制 |
|---|---|
| 写操作(创建 / 更新 / 禁用 / 删除) | 60 次 / 分钟 |
| 读操作(列表 / 详情 / 统计) | 300 次 / 分钟 |
超限时返回 429 Too Many Requests,响应头包含:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1748140860
Retry-After: 30
权限范围
| Scope | 授权操作 |
|---|---|
links:read | 列表查询、获取详情、获取统计、批量统计 |
links:write | 创建链接、更新元数据、启用链接 |
links:delete | 禁用链接、删除链接 |
campaigns:read | 列出活动、获取活动详情/链接/统计 |
campaigns:write | 创建活动、删除活动 |
domains:read | 列出域名、获取域名详情 |
domains:write | 绑定域名、删除域名、验证 DNS |
错误响应
所有错误使用统一的结构:
{
"error": "error_code",
"message": "人类可读的错误描述",
"request_id": "req_abc123"
}
| 状态码 | error | 含义 |
|---|---|---|
400 | invalid_request | 参数校验失败 |
401 | unauthorized | Key 缺失或无效 |
403 | forbidden | Key 缺少所需权限 |
404 | not_found | 资源不存在 |
409 | conflict | 自定义短码已被占用 |
429 | rate_limited | 超出频率限制 |
500 | internal_error | 服务端错误 |