ドキュメント

あなたのボードのマニュアル

1ページに3つのレーン。まずはここから始め、2つ目はケース対応の担当者へ、3つ目はコードを書く開発者へお渡しください。

まずはここから

管理者の方へ

プランを有効化し、チームを招待し、ケースのプレフィックスを設定し、請求を管理します。

スタートガイド →
御社のWebサイト

Web担当者の方へ

スクリプト1行で埋め込める3つのウィジェット。お問い合わせフォーム、ケース起票、エンドクライアント向けボード。

ウィジェット →
システム連携

開発者の方へ

専用認証情報付きのREST API、署名付きWebhook、増分同期。

APIリファレンス →

サポートボードとは

マルチブランドのサポートボード。当社のインフラの上で、御社ブランドのまま、御社のお客様に対応できます。

サポートボードは、御社のオペレーションのためのケースの一元キューです。お客様はWebサイト(ウィジェット)、API、メールからケースを起票し、御社のチームはdash.elportaldelcliente.comの専用パネルで対応します。誰も起きていなくても、ケースは受け付けられ、前へ進み、エスカレーションされます — ただし、担当者の名前なしに完結することはありません。

御社のボードは分離されたテナントです。御社のケース、エンドクライアント、エージェントが他社と混ざることはありません。この分離は忘れうる設定項目ではなく、システム設計そのものに組み込まれています。当社スタッフが最終レベルのサポートとして御社のケースに触れた場合は、アクセスが必ず記録され、御社が確認できます。

御社のお客様に当社のアカウントは不要です。お客様が接するのは御社ブランド — ウィジェット、御社のWebサイト、御社のメールだけです。アカウント(と管理権限)を持つのは御社です。

スタートガイド

ゼロから運用開始まで、5つのステップで。

  1. アカウントを作成します。dash.elportaldelcliente.com から登録できます。
  2. プランを有効化します。お支払いはアカウント残高から(エコシステム全体で共通のウォレットです)。残高が足りない場合は、不足分ちょうどのチャージを画面がご案内します。
  3. エージェントを招待します。「エージェント」タブでメールアドレスとロール(エージェントまたは管理者)を指定すると、お渡し用のアクセスリンクが発行されます。
  4. ウィジェットを有効にします。「ウィジェットとAPI」タブで御社サイトのドメインを許可オリジンとして登録し、スクリプトをコピーしてサイトに貼り付けます。
  5. コードで連携する場合は?同じタブでtab_live_認証情報を発行し、このページのAPIリファレンスに沿って進めてください。
ケースのプレフィックス:「ウィジェットとAPI」で御社独自の4文字(例:ACME)を設定でき、ケースはACME-1044のように採番されます。すでに発行済みのケースの番号は変わりません。

ボードの管理パネル

dash.elportaldelcliente.comのテナントパネルを、タブごとにご紹介します。

タブ役割
概要サブスクリプションの状態、有効期限、更新、自動更新。解約もここから行えます。
エージェントメールでエージェントまたは管理者として招待、ロール変更、アクセスの削除。オーナーは保護されます。
ウィジェットとAPIケースのプレフィックス、許可オリジン(CORS)、スクリプト付きの3つのウィジェット、そしてAPI認証情報。
プロバイダーのアクセス監査ログ:当社スタッフによる御社ケースへの各アクセスを、誰が・何を・いつとともに記録します。

招待したエージェントは御社ボードのケースを閲覧・対応できます。管理者はさらに、サブスクリプション、チーム、連携の管理も行えます。

Web用ウィジェット

3つのウィジェット、それぞれスクリプト1行。サードパーティのiframeもトラッキングCookieもありません。

パネルの「ウィジェットとAPI」タブで、ウィジェットを有効にし、御社サイトのドメインを許可オリジンとして登録し、生成されたスクリプトをコピーします。data-colorパラメータでブランドカラーを指定できます。

<script src="https://api.elportaldelcliente.com/api/tablero/widget/tablero.js"
        data-tenant="su-tablero" data-widget="contacto" data-color="#a177ff"></script>
data-widget役割必要条件
contactoお問い合わせフォーム:名前、メールアドレス、メッセージ。ボードにケースを作成します。ウィジェット有効 + 許可オリジン
abrir-caso件名付きのケース起票:訪問者にケース番号を返します。ウィジェット有効 + 許可オリジン
tableroエンドクライアント向けボード:お客様が御社サイト上で自分のケースを閲覧・起票・返信できます。上記 + クライアントトークン(下記参照)

ウィジェットの保護機構

匿名ウィジェットは、ボードごとに訪問者(IP)あたり10分間に10回まで受け付けます。ウィジェットが無効、オリジンが未許可、またはサブスクリプションが期限切れの場合、ウィジェットは404 widget no disponibleを返します — 御社ボードの設定を外部に漏らさないよう、意図的に区別のつかない応答にしています。

「ボード」ウィジェット:お客様を識別する

ボードウィジェットは、各エンドクライアントに本人のケースだけを表示します。そのために、御社サーバーがクライアントごとの短命トークンを引き換えます。API認証情報を使ってPOST /v1/clientes/:ref/token-widgetを呼び出し(サーバーサイド限定、ブラウザからは絶対に不可)、取得したトークンをウィジェットに渡してください。

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/clientes/cli-842/token-widget \
  -H "Authorization: Bearer $TABLERO_KEY"

HTTP/1.1 201
{"success":true,"data":{"token":"tabw_…","expires_at":"2026-08-18 21:15:00"}}
window.TableroPortal.setToken(token);
tabw_トークンの有効期間は15分で、更新はされません。期限が切れるとウィジェットは401 token_vencidoを受け取ります。新しいトークンを引き換えてください。tab_live_認証情報は決してブラウザに置かないでください — 短命トークンは、まさにそのために存在します。

API認証情報

連携ごとに1つのBearer認証情報。スコープを絞れて、いつでも失効できます。

認証情報はパネル(「ウィジェットとAPI」→「API認証情報」)で発行します。形式はtab_live_…で、表示は一度きりです。シークレットマネージャーに保管してください。当社が保存するのはハッシュのみです。

curl -H "Authorization: Bearer tab_live_…" \
  https://api.elportaldelcliente.com/api/tablero/v1/

発行時にスコープを絞ることができます。スコープを明示しない認証情報は、ボード全体へのアクセス権を持ちます:

Scopeできること
casos.readケースとその返信の読み取り
casos.writeケースの作成、返信、ステータス/優先度の変更
clientes.readエンドクライアントの読み取り
clientes.writeエンドクライアントの作成/無効化と、ウィジェットトークンの発行
departamentos.manage部門の読み取りと管理(IMAPメールボックスを含む)
webhooks.manageWebhookの読み取りと管理
accesos.readプロバイダーアクセス監査の読み取り
  • ボードあたり有効な認証情報は最大5件です。使わなくなったものは失効させてください。
  • 認証情報自体がボードを識別します。tenant_idをボディに含めないでください — APIは400で拒否します。
  • サブスクリプションが期限切れでも、認証情報は読み取り(GET)を継続できます。書き込みはすべて402 suscripcion_vencidaを返します。
  • 失効した認証情報は、すべてのルートで即座に401を返します。
サーバーサイド限定です。tab_live_認証情報を、ブラウザ、モバイルアプリ、リポジトリに置くことは絶対に避けてください。ブラウザには短命トークンtabw_があります。

APIリファレンス

HTTPS上のREST、送受信ともJSON、レスポンスは{success, data}形式です。

規約:リクエストボディはContent-Type: application/json、日時はUTCのYYYY-MM-DD HH:MM:SS、ページネーション付きの一覧はtotalpagelimitを返します。自分のものでないリソースには403ではなく、必ず404を返します。APIは他者のリソースの存在を確認させません。

https://api.elportaldelcliente.com/api/tablero/v1

ルート:識別・プラン・使用状況

GET /は嘘をつけない契約です。あなたが誰か、この認証情報が持つスコープ、上限を含むプラン、サブスクリプションの状態、現在の使用量を返します。

curl -H "Authorization: Bearer $TABLERO_KEY" \
  https://api.elportaldelcliente.com/api/tablero/v1/

{"success":true,"data":{
  "tenant":{"slug":"su-tablero","nombre":"Su Marca"},
  "scopes_de_esta_credencial":["casos.read","casos.write"],
  "plan":{"id":"tablero-base","nombre":"BASE","limites":{"max_agentes":5,"max_departamentos":5,"max_articulos_kb":100}},
  "suscripcion":{"estado":"active","current_period_end":"2027-08-18"},
  "uso":{"agentes":3,"departamentos":2},
  "recursos":["/casos","/clientes","/departamentos","/accesos","/webhooks"],
  "version":"v1"}}

エンドクライアント

エンドクライアントとは、御社のお客様のことです(当社エコシステムのアカウントではありません)。external_ref — 御社のシステムでそのお客様が持つID — で識別されます。

メソッドパスScope役割
GET/clientesclientes.readクライアントの一覧(最大500件、新しい順)
POST/clientesclientes.writeexternal_refによる作成または更新(冪等なupsert)
GET/clientes/:refclientes.readexternal_refでクライアントを1件取得
DELETE/clientes/:refclientes.write無効化(削除はされず、ケース履歴は保持されます)
POST/clientes/:ref/token-widgetclientes.write「ボード」ウィジェット用の短命トークンを発行(15分)
curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/clientes \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"external_ref":"cli-842","email":"[email protected]","name":"Maria Rojas"}'
安全な再試行:POST /clientesexternal_refによるupsertです — 同じ呼び出しを繰り返してもクライアントは重複しません。一方、ケース作成では、ネットワークの再試行が新しいケースを作ってしまいます。レスポンスを受け取れなかった場合にのみ再試行してください。

ケース

中心となるリソースです。ケースは、ステータス、優先度、任意のエンドクライアント、そして返信による会話を持ちます。エージェントの内部メモがAPIに公開されることは決してありません。

メソッドパスScope役割
GET/casoscasos.readフィルタ付き一覧:ステータス、クライアント、updated_since、limit(1-100)、page
POST/casoscasos.writeケースを作成(subject必須。cliente_ref、priority、department_id、body/body_htmlは任意)
GET/casos/:idcasos.read会話全体を含む詳細(返信は時系列順)。ID・ケース番号(例: SOLC-1051)のどちらでも受け付けます
POST/casos/:id/respuestascasos.writeチームとして返信、またはen_nombre_deでクライアントとして返信
PATCH/casos/:idcasos.writestatusおよび/またはpriorityを変更

エンドクライアントに紐づけてケースを作成する例:

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/casos \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subject":"No puedo entrar al panel","cliente_ref":"cli-842","priority":"high",
       "body":"Al iniciar sesion la pagina queda en blanco."}'

HTTP/1.1 201
{"success":true,"data":{"id":"…","numero":"SOLC-1051"}}

フィルタ付きの一覧と、updated_since(ISO 8601)による増分同期。このモードではupdated_atの昇順で返され、変更を取りこぼさずにページを進められるよう設計されています。処理した中で最大のupdated_atを保存し、次回の実行のカーソルとして使ってください。

curl -H "Authorization: Bearer $TABLERO_KEY" \
  "https://api.elportaldelcliente.com/api/tablero/v1/casos?estado=open&cliente=cli-842&limit=50&page=1"

# 増分同期(順序:updated_at 昇順)
curl -H "Authorization: Bearer $TABLERO_KEY" \
  "https://api.elportaldelcliente.com/api/tablero/v1/casos?updated_since=2026-08-18T00:00:00Z&limit=100"
機能しないフィルタはエラーより悪いものです。有効な一覧にないestado(または認識できないパラメータ)は詳細付きで400を返します — 黙って無視したり、警告なしに全件を返したりすることはありません。

ケースへの返信。en_nombre_deなしの場合はチーム名義(author_type: agent)、en_nombre_deありの場合はそのエンドクライアント名義(author_type: client)になります:

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/casos/$CASO_ID/respuestas \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body":"Ya lo revisamos: intente de nuevo.","autor_nombre":"Soporte Acme"}'

# ...またはエンドクライアント名義で:
  -d '{"body":"Sigue igual desde mi lado.","en_nombre_de":"cli-842"}'
フィールド
statusopen · pending · resolved · closed
prioritylow · medium · high · urgent
author_typeclient · agent
検証可能な分離:ケースへのすべてのクエリは、サーバー側でテナントのスコープを通ります。他のボードのケースIDには404を返します — APIは存在しないかのように振る舞います。あなたにとって、実際に存在しないからです。

部門

ボード内部のキューです(営業、請求、技術サポートなど)。各部門は専用のIMAPメールボックスを持てます。ボードがそれをポーリングし、受信メールをケースに変換します。

メソッドパスScope役割
GET/departamentosdepartamentos.manage部門の一覧(メール設定を含む。パスワードは除く)
POST/departamentosdepartamentos.manage作成(name必須。IMAPメールボックスは任意。プランの上限に従う)
PUT/departamentos/:iddepartamentos.manage任意のフィールドを編集。email_passwordを空にすると認証情報を削除
DELETE/departamentos/:iddepartamentos.manageアーカイブ(既存のケースには影響しません)

メールボックスは常にIMAPです(email_protocol: imap)。パスワードは保存時に暗号化され、決して返されません。email_polling_enabled: 1でポーリングが自動実行されます。

アクセス監査

当社スタッフによる御社ボードのケースへのアクセスは、すべて記録されます。「プロバイダーのアクセス」タブと同じ監査ログを、APIからも読み取れます:

curl -H "Authorization: Bearer $TABLERO_KEY" \
  https://api.elportaldelcliente.com/api/tablero/v1/accesos

Webhook

御社のシステムに、その瞬間に通知が届きます。各イベントは署名付きで御社のHTTPS URLに送信されます。

イベント発生するタイミング
caso.creadoボードにケースが生まれたとき — API、ウィジェット、受信メールのいずれか経由
caso.respondido誰かが返信したとき:御社チーム(パネルまたはAPI)、またはエンドクライアント(ウィジェット、API、メール)
caso.estado_cambiadoケースのステータスが変わったとき(御社チーム、API、当社システムのいずれかによる)

POST /webhooksで必要な分だけ登録できます:httpsのURL、受け取りたいイベント、そして各配信の署名に使う16文字以上のシークレットを指定します。

curl -X POST https://api.elportaldelcliente.com/api/tablero/v1/webhooks \
  -H "Authorization: Bearer $TABLERO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://su-sistema.com/hooks/tablero",
       "eventos":["caso.creado","caso.respondido","caso.estado_cambiado"],
       "secret":"un-secreto-de-al-menos-16-caracteres"}'

各配信は、イベント、発生時刻、対応に必要な最小限のデータを含むPOSTです。署名の対象はtimestamp.本文です:

POST /hooks/tablero
Content-Type: application/json
X-Tablero-Evento: caso.respondido
X-Tablero-Timestamp: 1765432100
X-Tablero-Firma: 3f1a…  # HMAC-SHA256(secret, timestamp + "." + 本文)

{"evento":"caso.respondido","emitido_at":"2026-08-18T20:15:00.000Z",
 "data":{"caso_id":"…","numero":"SOLC-1051","respuesta_id":"…","autor_tipo":"agent"}}

署名の検証

署名が検証できない配信、またはtimestampが時計から5分以上ずれている配信は拒否してください。比較は定数時間で行ってください。

// Node.js
const crypto = require('node:crypto');

function verificarFirma(rawBody, headers, secret) {
  const ts  = headers['x-tablero-timestamp'];
  const sig = headers['x-tablero-firma'];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const esperado = crypto.createHmac('sha256', secret)
    .update(ts + '.' + rawBody).digest('hex');
  return sig.length === esperado.length &&
    crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(sig));
}
# Python
import hashlib, hmac, time

def verificar_firma(raw_body: bytes, headers: dict, secret: str) -> bool:
    ts  = headers.get("x-tablero-timestamp", "")
    sig = headers.get("x-tablero-firma", "")
    if abs(time.time() - float(ts or 0)) > 300:
        return False
    esperado = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperado, sig)

配信のセマンティクス(信頼する前にお読みください)

  • イベントごとに1回のみ、再送はありません。エンドポイントが10秒以内に2xxを返さなければ、その配信は失われます — 実際の状態は、常にAPIから再取得できます。
  • 保険となるのは増分同期です:GET /casos?updated_since=…の定期実行で、失われたイベントをすべて回収できます。
  • GET /webhooksは、各Webhookのfail_countlast_ok_atlast_error_atを表示します。デバッグ時にご確認ください。
  • イベントは経路を問わず発行されます:API、ウィジェット、御社チームのパネル、当社スタッフ、エンドクライアントの受信メールのいずれでも。

エラー

エラーはsuccess:falseのJSONで返り、HTTPコードが正となります。

{"success":false,"error":"…"}
HTTP意味
400不正なリクエスト:必須フィールドの欠落、または値がバリデーションを通らない
401認証情報がない、無効、または失効済み
402サブスクリプション期限切れ:更新まで読み取り専用(suscripcion_vencida
403認証情報に、エンドポイントが要求するスコープがない
404あなたにとって存在しない:他者のリソースも存在しないルートも同じ応答
409競合:プランの上限に到達、またはスラッグが使用中
429試行回数の超過(匿名ウィジェット:IPあたり10分間に10回)
500当社側のエラーです。続く場合は、正確な発生時刻を添えてご連絡ください

errorのメッセージは人間向けの読みやすいテキストで、変更される可能性があります。コードの分岐はHTTPコードと、次の安定スラッグで行ってください:

安定スラッグ意味
suscripcion_vencidaサブスクリプション期限切れでの書き込み時の402
token_vencidotabw_トークン期限切れ時の「ボード」ウィジェットの401:新しいトークンを引き換えてください
saldo_insuficiente残高不足での有効化/更新時にパネルが返す402

プラン

5つの年間プラン、同じボード。違いは、収容できる人数と組織の規模です。

最新の料金はトップページと公開API(GET /api/public/tablero/plans)で公開しています。全プランにケース数無制限、ウィジェット、API、Webhook、アクセス監査が含まれます。

プランエージェント数部門数KB記事数
ZERO2225
BASE55100
PLUS1010250
PRO2015500
MAX50251000
無料トライアルは、意図的にご用意していません。ZEROプランは、本気の小さな一歩のためにあります。有効化の時点で、アカウント残高から1年分が引き落とされます。

サブスクリプションの期限が切れると猶予期間があり、その後ボードは読み取り専用になります(GETは応答し続け、書き込みは402を返します)。データが削除されることはありません。

運用上の制限

  • ケース:全プランで無制限。一覧は1ページあたりlimit 1〜100を受け付けます。
  • エンドクライアントと監査:一覧は最大500行(新しい順)を返します。個別の読み取りにはGET /clientes/:refをご利用ください。
  • 認証情報:ボードあたり有効なもの最大5件。
  • 匿名ウィジェット:訪問者(IP)あたり10分間に10回。
  • 添付ファイル:APIは現時点でファイルを受け付けません。受信メールの添付ファイルは、ケースとともに保持されます。

現在、トランクAPIに厳格な呼び出しクォータはありません。良識的なペースでご利用ください(ページ間の待機、指数バックオフでの再試行)。保証されたボリュームが必要な連携については、まずご相談ください