デベロッパー

Sellioをhttp経由で連携するか、AIエージェントを接続

シンプルなREST APIとネイティブなMCPサーバー。同じキー、同じテナントスコープ、同じレート制限で動作します。任意のオブジェクトのフィールドを検出し、数分でレコードの読み書きを始められます。

クイックスタート

ゼロから最初の呼び出しまで3ステップ:

  1. CRMで「設定 → API&開発者」を開き、APIキーを生成します。安全に保管してください。二度と表示されません。
  2. そのキーをAuthorization: Bearerヘッダーで使います。キーは所有テナントを識別するため、すべてが自動的にそのテナントにスコープされます。
  3. 最初の呼び出しを行い、オブジェクトを一覧表示します。
curl -H "Authorization: Bearer sk_live_..." \
  https://www.selliocrm.com/api/v1/objects

認証

すべてのリクエストはAuthorization: BearerヘッダーにAPIキーを含みます。そのキーは所有テナントを識別するため、すべてが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/objectsテナントのオブジェクトを一覧表示します。
GET/objects/{apiName}オブジェクトのフィールド(ディスカバリ)。
GET/{object}レコードの一覧表示と検索(豊富なフィルタ、並べ替え、ページネーション)。
GET/{object}/{id}idで1件のレコードを取得。
POST/{object}レコードを作成します。
POST/{object}/bulk一括作成(最大500件、項目ごとに部分的な成功)。
PATCH/{object}/{id}フィールドを更新(部分的)。
PATCH/{object}/bulk一括更新({ updates: [{ id, ...fields }] })。
DELETE/{object}/{id}削除(ソフト削除 → ゴミ箱)。キーに削除スコープが必要です。
GET/data/{object}行としてフラット化されたレコード(BI/自動化用)。
GET/activitiesアクティビティを一覧表示(1件のレコードには?recordIdを使用)。
POST/activitiesレコードに紐づくアクティビティを作成します。
GET/line-itemsProduct line-items of an opportunity (?opportunityId), plus the total.
POST/line-itemsAdd a line-item; recomputes totals and the opportunity amount.
PATCH/line-itemsUpdate quantity, price, discount, tax or term of one line.
DELETE/line-itemsRemove a line-item (?id) and recompute the totals.
GET/attachmentsFiles attached to a record (?recordId and ?objectApiName).
POST/attachments/upload-urlUpload step 1: returns the signed upload URL.
POST/attachmentsUpload step 3: registers the uploaded file as an attachment.
GET/attachments/{id}Signed download URL (5 min). There is never a public URL.
DELETE/attachments/{id}Delete the attachment. Requires the delete scope on the key.

一覧パラメータ(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はありません)で結合し、1リクエストあたり最大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"

# 1件のレコード
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、加えて各フィールドごとに1列)。並び順は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: 1つのオブジェクトのフィールド(必須、型、選択肢)。
  • list_records: レコードの一覧表示と検索。
  • get_record: idで1件のレコードを取得。
  • 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認可コードフローを使います。ユーザーは要求されたスコープが表示された同意画面を見て承認し、あなたのアプリは同意された範囲だけを実行できるアクセストークンを受け取ります。アプリは審査制です。マーケットプレイスでアプリを登録・公開してclient_idとclient_secretを取得します。4ステップのフロー:

  1. client_id、redirect_uri(アプリの許可リストと完全一致)、scope、state、PKCE(code_challenge_method=S256付きのcode_challenge)とともに、ユーザーを/api/oauth/authorizeにリダイレクトします。PKCEは必須です。
  2. ログイン中のユーザーが同意画面を見て承認します。CRMはcodeと同じstateを付けて、あなたのredirect_uriにリダイレクトして戻します。
  3. あなたのサーバー上で、POST /api/oauth/token(code_verifier、client_id、client_secret、redirect_uri付き)でcodeをアクセストークン(Bearer、約1時間)とリフレッシュトークンに交換します。
  4. Authorization: Bearer at_...を付けて、同意にスコープされたREST v1 APIとMCPサーバーを呼び出します。grant_type=refresh_tokenで更新します。リフレッシュはローテートされ(古いものは使用時に無効化されます)、再利用するとトークンファミリー全体が失効します。
GET/api/oauth/authorizeユーザーの同意(セッションが必要)。codeを発行します。
POST/api/oauth/tokencodeをトークンに交換し、更新(refresh_token)します。
POST/api/oauth/revokeアクセストークンまたはリフレッシュトークンを失効させます。
# 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)アクセストークンでv1 / MCP APIを呼び出す(同意にスコープされている)
curl -H "Authorization: Bearer at_..." https://www.selliocrm.com/api/v1/contact

# 4)リフレッシュトークンで更新する(ローテート:古い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を使います。

  1. アプリでウィジェットを宣言し(key、title、配置場所recordまたはdashboard、embedUrl)、embedUrlのオリジンをアプリのオリジン許可リストに登録します。
  2. ウィジェットではホストからのメッセージを受信し、ホストオリジン(event.origin)からのものだけを受け入れます。ホストは{ recordId, objectApiName, locale, theme, installId }とともにsellio:widget:context(バージョン1)を送ります。
  3. ウィジェットが返送できるのは、sellio:widget:ready(コンテキストを再受信するため)と、{ height }付きのsellio:widget:resize(高さを合わせるため、上限あり)だけです。それ以外のメッセージは無視されます。
  4. データには、アプリのトークンで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を登録し、購読するイベントを選びます。各配信は、JSONボディ、イベント名を含むx-sellio-eventヘッダー、ボディのHMAC-SHA256署名を含むx-sellio-signatureヘッダーを持つPOSTです。シークレット(whsec_...)はwebhookの作成時に表示されます。

イベントカタログ

record.createdrecord.updatedflow.enrolledflow.message_sentflow.repliedflow.step_completedflow.completed

ペイロードの例

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();
});

レート制限

各キーには1分あたりの上限があります(既定120、設定可能)。レスポンスにはX-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Resetヘッダーが含まれます。上限を超えると、APIはRetry-Afterヘッダー付きで429を返します。

エラー形式

エラーは、対応するHTTPステータスとともに{ "error": "message" }の形式でJSONを返します:

{ "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にインポートするか、すべてのエンドポイントとapiKey・baseUrl変数を備えた、すぐ使えるPostmanコレクションをダウンロードしてください。

アカウントを作成し、最初のキーを生成する

無料アカウントを作成
デベロッパー · Sellio