两种密钥作用域,因为调用方本来就有两类
工作区密钥在单个工作区内生效:链接、数据分析、该工作区可用的域名,以及它自身的用量。合作伙伴密钥作用于整个业务:客户及其订阅、你出售的套餐、全部域名、带手续费明细的支付、结算,以及一份聚合的数据分析总览。两种前缀肉眼可辨,因此密钥粘错了服务会立刻失败,而不是做出什么出人意料的事。
密钥在控制台创建,只展示一次,并且只以哈希形式存储。每把密钥都带有自己的作用域列表,因此一个只需要读取数据分析的集成,可以拿到一把无法创建或删除任何东西的密钥。密钥可以设置过期日期,也可以随时立即吊销,页面上还会显示每把密钥最后一次被使用的时间——你正是靠它找出那个没人记得是谁配置的集成。
- POST /links, GET /links, GET /links/{id}, PATCH /links/{id}, DELETE /links/{id}
- POST /links/bulk:单次调用最多 100 条链接
- GET /links/{id}/qr:PNG 或 SVG,可指定预设和尺寸
- GET /analytics/summary, /timeseries, /breakdown, /links/top, /export.csv
- GET 和 POST /domains:接入一个域名,并读取它所需的 DNS 记录
- GET /workspace:套餐限制与当前用量
- GET /partner/clients, /partner/plans, /partner/payments, /partner/payouts
在凌晨三点最要紧的那种可预测性
每一个错误都是同一种形状——一个错误码、一段人类可读的说明、一个文档 URL——因此客户端库可以按错误码分支,而人可以直接读说明。列表用游标分页而不是页码,于是在你翻页的同时不断有链接被创建,结果依然稳定。
速率限制默认为工作区密钥每分钟 600 次请求,合作伙伴密钥是它的两倍,每个响应都以头部返回限额、剩余次数和重置时间。超限返回 429 并带上 Retry-After 头,而不是直接断开连接,于是守规矩的客户端能正确退避。数据分析导出采用流式,因此 10 万行数据不需要在任何一端把整份报表放进内存。
Webhook 顶替那些你本来只能轮询的事件
注册一个端点,就能收到链接的创建、更新和删除;主机名从「等待 SSL」走向「已生效」或进入错误状态时的域名生命周期事件;以及在合作伙伴密钥下,客户的订阅与支付事件。每分钟轮询一次域名状态端点,正是那种不该再有人去写的代码。
每一次投递都带有一个含时间戳的 HMAC-SHA256 签名头,你的接收端可以据此验证载荷确实来自我们、并且不是重放。投递失败会重试五次,间隔逐次拉长——1 分钟、5 分钟、30 分钟、2 小时、12 小时——之后该端点被标记为失败,并发出邮件。控制台可以发送一个测试事件,因此集成在有任何真实业务依赖它之前就能验证。
由真正在运行的代码生成的文档
OpenAPI 规范由 API 用于校验的同一批 schema 构建,因此它不可能像手写参考文档那样与实现脱节。它既作为文件发布,可以直接喂给客户端生成器,也在本站渲染成可浏览的参考文档,旁边还配有手写的快速上手、分页、错误、Webhook 和速率限制指南。
第一版已经冻结。可以新增字段,已有行为不会改变,任何会让调用方出问题的改动都要等到位于另一条路径上的第二版。如果你挑选一个短链接服务是为了在它之上做开发,而不只是使用它,那么这个承诺比任何单个端点都值钱。
代码本身就是说明
curl -X POST https://api.linkprofit.com/v1/links \
-H 'Authorization: Bearer lp_live_XXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com/spring-collection",
"domain_id": "dom_8kq2vn41",
"slug": "spring",
"title": "Spring collection",
"utm": {
"utm_source": "newsletter",
"utm_medium": "email",
"utm_campaign": "spring-2026"
}
}'const response = await fetch("https://api.linkprofit.com/v1/links", {
method: "POST",
headers: {
Authorization: "Bearer lp_live_XXXXXXXX",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/spring-collection",
domain_id: "dom_8kq2vn41",
slug: "spring",
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(error.code + ": " + error.message);
}
const link = await response.json();
console.log(link, response.headers.get("X-RateLimit-Remaining"));import requests
response = requests.post(
"https://api.linkprofit.com/v1/links",
headers={"Authorization": "Bearer lp_live_XXXXXXXX"},
json={
"url": "https://example.com/spring-collection",
"domain_id": "dom_8kq2vn41",
"slug": "spring",
},
timeout=10,
)
if response.status_code == 429:
raise SystemExit("rate limited, retry after " + response.headers["Retry-After"])
response.raise_for_status()
print(response.json())常见问题
哪些套餐包含 API 访问权限?
对合作伙伴来说,API 访问从 Growth 套餐开始提供,更高的套餐全部包含。对你自己的客户则由你决定:API 访问是你创建的每个套餐上的一个开关,因此它既可以是你服务里的高级档位,也可以处处包含。
API 能跑在我自己的主机名上吗?
第一版还不行。API 由 api.linkprofit.com 提供,合作伙伴在给客户的文档里把它写成自家服务的 API。客户在浏览器里看到的一切——控制台、链接、邮件、结账——都在你的域名上;API 主机名是唯一一处如实承认的例外。
有用于测试的沙盒吗?
用一个专门的工作区,加一把限定在它范围内的密钥即可。在那里创建的链接会在真实域名上解析,并产生真实的数据分析——当你要验证跳转、定向和 Webhook 是否与文档一致时,这比模拟环境有用得多。