通过 HTTP 集成 Sellio,或连接你的 AI 代理
一套简洁的 REST API 与一个原生 MCP 服务器,共用同一个密钥、同一个租户范围、同一个速率限制。发现任意对象的字段,几分钟内即可开始读写记录。
快速开始
三步从零到你的第一次调用:
- 在 CRM 中,打开「设置 → API 与开发者」并生成一个 API key。请妥善保存;它不会再次显示。
- 在 Authorization: Bearer 请求头中使用该密钥。它标识所属租户,因此一切都已限定在该租户范围内。
- 发起你的第一次调用,列出你的对象。
curl -H "Authorization: Bearer sk_live_..." \
https://www.selliocrm.com/api/v1/objects认证
每个请求都在 Authorization: Bearer 请求头中携带一个 API key。该密钥标识所属租户,因此一切都会自动限定在该租户范围内,并配合 RLS 与 RBAC。切勿在浏览器中暴露密钥;仅在服务器端使用。你可在「设置 → API 与开发者」中生成和吊销密钥。
密钥范围
在生成密钥时,你可选择其范围,只授予每个集成所需的访问权限。这些限制在 REST 与 MCP 中同样适用,因为两个接口共用同一个密钥和同一套控制。未设置范围的密钥(默认)拥有对所有对象的完整读写权限,与以往一致。
- 只读:该密钥可读取数据,但不能创建、编辑或删除。它会在 REST 中阻止 POST、PATCH 和 DELETE,在 MCP 中阻止 create_record、update_record 和 delete_record 工具,并返回 403 和 { "error": "errors.apiKeyReadOnly" }。
- 限定对象:选择该密钥可访问的对象。列表之外的任何对象都会返回 403 和 { "error": "errors.apiKeyObjectDenied" }。对象列表已按范围过滤,活动记录计为 activity 对象。
- 允许删除:默认情况下密钥永远不会删除(即便启用了写入也不行)。在生成密钥时开启此项,即可启用 DELETE /{object}/{id} 和 delete_record 工具。若未开启,删除操作会返回 403 和 { "error": "errors.apiKeyDeleteDenied" }。删除为软删除:记录进入回收站,可以恢复。
REST API v1
任意对象的记录,收发均为 JSON。{object} 为 apiName(例如 contact、lead、opportunity),{id} 为记录的 uuid。自定义对象使用同样的通用端点。
列表参数(GET /{object}):limit(1 到 500,默认 50)、offset(分页偏移量,默认 0;总数在 total 字段中)、search(按名称搜索,不区分重音和大小写)、order(字段附带 :asc 或 :desc)以及 filter。丰富的过滤:重复 filter=field:operator:value 以组合多个(例如 filter=amount:gte:1000&filter=stage:eq:won)。运算符:eq、neq、contains、gt、lt、gte、lte、empty、not_empty(empty 和 not_empty 不带值)。过滤条件以逻辑 AND 组合(没有 OR),每个请求最多 12 个。旧写法 filter=field:value(不带运算符)仍表示精确相等。
# 列表(limit、offset、search、filter、order)
curl -H "Authorization: Bearer sk_live_..." \
"https://www.selliocrm.com/api/v1/opportunity?limit=20&order=updated_at:desc&filter=stage:won"
# 丰富的过滤:重复 filter=field:operator:value(彼此之间为 AND)
curl -H "Authorization: Bearer sk_live_..." \
"https://www.selliocrm.com/api/v1/opportunity?filter=amount:gte:1000&filter=stage:eq:won&filter=name:contains:acme"
# 单条记录
curl -H "Authorization: Bearer sk_live_..." \
https://www.selliocrm.com/api/v1/contact/8f3c...
# 创建
curl -X POST -H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"name":"Ana Souza","email":"ana@acme.com","source":"site"}' \
https://www.selliocrm.com/api/v1/contact
# 批量创建(最多 500 条;响应按条目部分成功)
curl -X POST -H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"records":[{"name":"Ana"},{"name":"Bruno"}]}' \
https://www.selliocrm.com/api/v1/contact/bulk
# → { "results": [ { "index": 0, "ok": true, "id": "..." },
# { "index": 1, "ok": false, "error": "..." } ],
# "created": 1, "failed": 1 }
# 更新(部分)
curl -X PATCH -H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"source":"referral"}' \
https://www.selliocrm.com/api/v1/contact/8f3c...
# 删除(软删除,进入回收站;需要密钥具备删除范围)
curl -X DELETE -H "Authorization: Bearer sk_live_..." \
https://www.selliocrm.com/api/v1/contact/8f3c...对象与字段发现
在创建或更新记录之前,先发现对象的字段:有哪些字段、哪些是必填、select 接受哪些值。无需猜测,也无需检视已有记录。GET /objects/{apiName} 会返回该对象及其字段,包含 required、options(用于 select)、targetObject(用于 lookup)、unique 以及 readOnly(公式或汇总字段,不可写入)。
GET https://www.selliocrm.com/api/v1/objects/contact
# → {
# "apiName": "contact",
# "label": "Contact",
# "fields": [
# { "apiName": "name", "label": "Name", "type": "text", "required": true },
# { "apiName": "email", "label": "Email", "type": "email", "required": false },
# { "apiName": "source", "label": "Source", "type": "select", "required": true,
# "options": [ { "value": "site", "label": "Website" },
# { "value": "referral", "label": "Referral" } ] },
# { "apiName": "company", "label": "Company", "type": "lookup",
# "required": false, "targetObject": "company" }
# ]
# }在 MCP 中,describe_object 工具会向代理返回同样的字段。
面向 BI 与自动化的数据
GET /data/{object} 会将记录扁平化为稳定的表格行(固定列 id、created_at、updated_at、owner_id,外加每个字段一列),按 updated_at 倒序排列。它支持按 page 和 pageSize(或 limit 和 offset)分页、增量过滤 updated_since 和 created_since(ISO 8601),以及 filter=field:value。专为 Power BI、Tableau、Looker 以及从 Zapier、Make 和 n8n 轮询而打造。
curl -H "Authorization: Bearer sk_live_..." \
"https://www.selliocrm.com/api/v1/data/opportunity?pageSize=100&updated_since=2026-01-01T00:00:00Z"
# → { "object": "opportunity",
# "columns": [ { "name": "id", "type": "id" }, ... ],
# "page": 1, "pageSize": 100, "total": 42,
# "rows": [ { "id": "...", "created_at": "...", "amount": 1200, ... } ] }面向 AI 代理的 MCP 服务器
Sellio exposes a native MCP (Model Context Protocol) server so your AI agent can read and write the CRM safely. It is the same API key, the same rate limit, the same validations and the same RBAC. The server URL is https://www.selliocrm.com/api/mcp. Available tools:
list_objects: 列出租户的对象。describe_object: 单个对象的字段(必填项、类型、选项)。list_records: 列出并搜索记录。get_record: 按 id 获取单条记录。create_record: 创建一条记录。update_record: 更新字段。delete_record: 删除(软删除 → 回收站)。需要密钥具备删除范围。
支持通过 HTTP 使用远程 MCP 的客户端,可搭配 Authorization: Bearer 请求头使用该 URL。对于不原生支持远程 HTTP 的客户端,请使用 mcp-remote 桥接:
{
"mcpServers": {
"sellio-crm": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://www.selliocrm.com/api/mcp",
"--header", "Authorization: Bearer sk_live_..."
]
}
}
}OAuth 与已连接的应用
要代表用户进行集成(无需客户粘贴管理员密钥),请使用带 PKCE 的 OAuth 2.0 授权码流程。用户会看到一个列出所请求范围的授权页面,批准后你的应用会收到一个只能执行已授权操作的 access token。应用需经审核:在市场中注册并发布应用即可获得 client_id 和 client_secret。流程分四步:
- 将用户重定向到 /api/oauth/authorize,携带 client_id、redirect_uri(须与应用白名单精确匹配)、scope、state 以及 PKCE(code_challenge 搭配 code_challenge_method=S256)。PKCE 为必需项。
- 已登录的用户看到授权页面并批准。CRM 会重定向回你的 redirect_uri,携带 code 和相同的 state。
- 在你的服务器上,通过 POST /api/oauth/token(携带 code_verifier、client_id、client_secret 和 redirect_uri)用 code 换取一个 access token(Bearer,有效期约 1 小时)和一个 refresh token。
- 使用 Authorization: Bearer at_... 调用 REST v1 API 和 MCP 服务器,权限限定于所授权的范围。用 grant_type=refresh_token 续期;refresh token 会轮换(旧的一经使用即失效),重复使用会吊销整个令牌族。
# 1) 将用户引导至授权页面(PKCE S256 + state)
GET https://www.selliocrm.com/api/oauth/authorize
?response_type=code
&client_id=app_...
&redirect_uri=https://your-app.example.com/callback # 与白名单精确匹配
&scope=records:read%20records:write:opportunity%20activities:read
&state=<random>
&code_challenge=<base64url(sha256(code_verifier))>
&code_challenge_method=S256
# → 用户批准 → 302 redirect_uri?code=<authcode>&state=<...>
# 2) 用 code 换取令牌(服务器端;发送 client_secret)
curl -X POST https://www.selliocrm.com/api/oauth/token \
-d grant_type=authorization_code \
-d code=<authcode> \
-d code_verifier=<code_verifier> \
-d client_id=app_... \
-d client_secret=secret_... \
-d redirect_uri=https://your-app.example.com/callback
# → { "access_token": "at_...", "token_type": "Bearer",
# "expires_in": 3600, "refresh_token": "rt_...",
# "scope": "records:read records:write:opportunity activities:read" }
# 3) 用 access token 调用 v1 / MCP API(范围限定于所授权内容)
curl -H "Authorization: Bearer at_..." https://www.selliocrm.com/api/v1/contact
# 4) 用 refresh token 续期(会轮换:旧的 rt_ 一经使用即失效)
curl -X POST https://www.selliocrm.com/api/oauth/token \
-d grant_type=refresh_token -d refresh_token=rt_... \
-d client_id=app_... -d client_secret=secret_...OAuth 范围与密钥采用相同的强制机制(读取、写入以及按对象)。只请求所需的最小范围;用户在安装时授予其中一部分,令牌仅在该范围内运作。
- records:read 和 records:write:读写所有对象的记录(粗粒度)。
- records:read:contact 和 records:write:opportunity:按对象细化(apiName),当应用只需部分对象时使用。
- activities:read 和 activities:write:读写活动。
- objects:read:发现对象与字段的结构。
嵌入式小组件
你的应用可在 CRM 内嵌入自己的界面(小组件):位于记录详情页或仪表盘上。小组件运行于沙箱化的 iframe 中,由你自己的来源(在应用白名单上)提供。宿主仅通过 postMessage 向小组件发送 UI 上下文:recordId、objectApiName、locale 和 theme。该消息中不会传递任何业务数据、令牌或密钥。要读写数据,你的小组件需使用 OAuth API 及其自有令牌(租户在安装时授予的范围)。
- 在你的应用中声明小组件(key、title、位置 record 或 dashboard,以及 embedUrl),并将 embedUrl 的来源列入应用来源白名单。
- 在你的小组件中,监听宿主消息,且只接受来自宿主来源(event.origin)的消息。宿主会发送 sellio:widget:context(版本 1),携带 { recordId, objectApiName, locale, theme, installId }。
- 你的小组件只能回发 sellio:widget:ready(以再次接收上下文)和携带 { height } 的 sellio:widget:resize(用于适配其高度,有上限)。任何其他消息都会被忽略。
- 要获取数据,请用应用令牌调用 OAuth API(Bearer)。宿主绝不会通过 postMessage 传递令牌或数据。
// 在你自己的小组件内部(即运行于 iframe 中的 https://widgets.yourapp.com 页面)。
// 宿主只发送 UI 上下文。要获取数据,请用你自己的令牌调用 OAuth API。
const HOST = 'https://www.selliocrm.com'; // 始终校验宿主来源
window.addEventListener('message', (event) => {
if (event.origin !== HOST) return; // 只接受宿主来源
const msg = event.data;
if (!msg || msg.version !== 1) return;
if (msg.type === 'sellio:widget:context') {
const { recordId, objectApiName, locale, theme, installId } = msg.payload;
render(recordId, objectApiName, locale, theme);
// 用你自己的 OAuth 令牌获取数据(绝不会通过 postMessage 传来):
// fetch(HOST + '/api/v1/' + objectApiName + '/' + recordId,
// { headers: { Authorization: 'Bearer ' + accessToken } })
}
});
// 在加载时请求上下文,并根据你的内容调整高度:
parent.postMessage({ type: 'sellio:widget:ready', version: 1 }, HOST);
parent.postMessage({ type: 'sellio:widget:resize', version: 1,
payload: { height: document.body.scrollHeight } }, HOST);安全性:iframe 是沙箱化且跨来源的,因此小组件无法触及宿主的 DOM 或 cookie。宿主会在每次 postMessage(进出)时校验精确来源,且 embedUrl 始终会与应用白名单核对。要放置小组件,请请求 widgets:embed 范围。
出站 webhook
实时接收 CRM 事件。在设置中注册一个目标 URL,并选择你订阅的事件。每次投递都是一个 POST,携带 JSON 主体、带事件名称的 x-sellio-event 请求头,以及带主体 HMAC-SHA256 签名的 x-sellio-signature 请求头。密钥(whsec_...)会在你创建 webhook 时显示。
事件目录
示例载荷
POST https://your-server.example.com/webhook
x-sellio-event: record.created
x-sellio-signature: sha256=<hmac-hex>
Content-Type: application/json
{
"event": "record.created",
"tenantId": "…",
"objectApiName": "lead",
"recordId": "8f3c…",
"data": { "name": "Ana Souza", "email": "ana@acme.com" },
"timestamp": "2026-07-23T12:00:00.000Z"
}营销活动与流程事件(flow.*)会携带额外的报名字段:
{
"event": "flow.replied",
"tenantId": "…",
"flowId": "…",
"flowName": "Outbound Q3",
"recordId": "8f3c…",
"enrollmentId": "…",
"objectApiName": "lead",
"data": { "name": "Ana Souza", "email": "ana@acme.com" },
"meta": {},
"timestamp": "2026-07-23T12:00:00.000Z"
}如何验证签名
使用你的 whsec_... 密钥,对原始主体(完全按接收时的样子,不要重新序列化)计算 HMAC-SHA256,形式为 sha256=<hex>,并以恒定时间与 x-sellio-signature 请求头比对。不匹配时拒绝。
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody = 完全按接收到的主体原样(字符串),不重新序列化。
function isValid(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(signatureHeader || '');
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}
// Express:使用 express.raw({ type: 'application/json' }) 获取原始主体。
app.post('/webhook', (req, res) => {
const ok = isValid(req.body.toString('utf8'), req.header('x-sellio-signature'), process.env.SELLIO_WHSEC);
if (!ok) return res.status(401).end();
const event = req.header('x-sellio-event');
// …… 处理该事件
res.status(200).end();
});速率限制
每个密钥都有每分钟的限制(默认 120,可配置)。响应中会包含 X-RateLimit-Limit、X-RateLimit-Remaining 和 X-RateLimit-Reset 请求头。超出时,API 会返回 429 并附带 Retry-After 请求头。
错误格式
错误以 { "error": "message" } 形式返回 JSON,并附带相应的 HTTP 状态码:
{ "error": "required field: source" } # HTTP 400- 200 和 201:成功(创建时为 201)。
- 400:校验或业务规则错误。
- 401:密钥缺失或无效。
- 403:对该对象无权限(RBAC),或被密钥范围拦截(只读、对象在范围之外,或未启用删除)。
- 404:未找到对象或记录(包括对不存在的 id 执行 DELETE/PATCH)。
- 429:超出速率限制(参见 Retry-After 请求头)。
已知限制
- 过滤条件以逻辑 AND 组合(须同时全部成立);过滤条件之间没有 OR。
- 更新为部分更新(PATCH):你只发送需要更改的字段。没有用于整条记录替换的 PUT。
规范与集合
将 OpenAPI 3.1 规范导入 Swagger、Insomnia 或 Postman,或下载即用的 Postman 集合,其中包含每个端点以及 apiKey 和 baseUrl 变量。