APIドキュメント

登録システムとConnectellyを連携するために必要なすべて。

クイックスタート

Connectelly External API は2段階認証を採用しています。API キーを短期間有効な access token と交換し、実際の呼び出しはそのトークンで行います。

  1. パートナー申請を行い API キーを受け取る — 契約締結後、マスター管理者がキーを発行します。
  2. access token を発行する — POST /api/external/v1/token
  3. トークンで呼び出す — Authorization: Bearer <access_token>
# 1) トークンを発行 (API キーはここでのみ使用)
curl -X POST https://connectelly.com/api/external/v1/token \
  -H "X-Connectelly-Api-Key: ck_live_..."

# → {"access_token":"eyJ...","token_type":"Bearer","expires_in":1800,
#    "event_id":"af2f95b4..."}   ← eventId はここで取得します

# 2) 発行したトークンで連絡先を送信
curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{"external_id":"REG-001","name":"John Smith","email":"john@example.com"}'

レスポンスが 200 なら保存完了です。アプリユーザーが REG-001 の QR をスキャンすると、リードが自動キャプチャされます。

認証

2段階認証

長期間有効な API キーはトークンの発行にのみ使い、実際の API 呼び出しは短期間有効な access token で行います。通常のトラフィックにキーが含まれないため、パートナー側のサーバーログやプロキシ経由での漏えいを防げます。

API キー

  • 形式: ck_live_<32 url-safe base64>
  • POST /api/external/v1/token でのみ X-Connectelly-Api-Key ヘッダーとして使用
  • イベント単位で発行。他のイベントには使用できません (404 event_not_found)
  • サーバーサイド専用。クライアントコードや公開リポジトリに含めないでください

Access Token

  • 有効期間は 30分(1800秒)。期限が切れたら再発行してください。
  • すべての API 呼び出しに Authorization: Bearer <access_token> を付けます。
  • キーが失効すると、発行済みのトークンも即座に無効になります。

キーが漏えいした場合

直ちに管理者に連絡し、キーを失効させてください。失効と同時に、そのキーと、そのキーで発行されたすべてのトークンが遮断されます。新しいキーを再発行すると、既存のキーは 24時間の猶予期間の後に失効するため、無停止で切り替えられます。

IP 制限 (推奨)

許可する IP/CIDR を登録すると、そのアドレスからのみトークンを発行できます。キーが漏えいしても、他の場所からは使用できません。管理者に設定を依頼してください。

トークン API

API キーを短期間有効な access token と交換します。API キーをヘッダーに含めるエンドポイントはここだけで、その他のすべての API はここで取得したトークンで呼び出します。

リクエスト

POST /api/external/v1/token

ヘッダー必須説明
X-Connectelly-Api-Key必須発行された API キー (ck_live_...)

リクエスト body は不要です。

curl -X POST https://connectelly.com/api/external/v1/token \
  -H "X-Connectelly-Api-Key: ck_live_..."

レスポンス 200

{
  "access_token": "eyJhbGciOiJIUzM4NCJ9...",
  "token_type": "Bearer",
  "expires_in": 1800,
  "expires_at": "2026-09-07T05:18:35Z",
  "event_id": "af2f95b402794c8f9289360fc8765b8e"
}
フィールド型説明
access_tokenstring以降すべてのリクエストの Authorization ヘッダーに使用
token_typestring常に Bearer
expires_ininteger残り有効期間(秒)。既定値 1800 = 30分
expires_atstring有効期限 (ISO-8601 UTC)
event_idstringこのキーに紐づくイベント ID。以降すべてのエンドポイントのパス {eventId} にそのまま使用

eventId はどこで取得しますか?

API キーは1つのイベントに紐づけて発行されるため、eventId を別途管理する必要はありません。次の2つの方法で確認できます。

  • トークンレスポンスの event_id — 上記のレスポンスから直接取得します。ハードコーディングせず、この値を使うことを推奨します。
  • キー発行時の案内 — 担当者が API キーをお渡しする際に併せてお知らせします。

他のイベントの eventId を指定すると、404 event_not_found が返されます。

エラー

HTTPcode原因
401auth_missingヘッダーがない
401auth_invalidキーを認識できない
401key_expiredキーの有効期限切れ (または再発行の猶予期間終了)
401key_revokedキーが失効済み
403ip_not_allowed許可されていない IP

運用のヒント

  • リクエストのたびに発行せず、トークンをキャッシュしてください。有効期限の1〜2分前に更新することを推奨します。
  • 401 token_invalid を受け取ったら、トークンを再発行して1回だけ再試行してください。
  • トークンはサーバーのメモリ上にのみ保持し、ログや URL に残さないでください。

連絡先の登録・更新

連絡先を1件登録または更新します。external_id がすでに存在する場合は上書きします(UPSERT)。登録時点で呼び出しておくと、アプリで QR をスキャンした際にリードが自動キャプチャされます。

POST /api/external/v1/events/{eventId}/contacts

リクエストヘッダー

ヘッダー必須説明
Authorization必須Bearer <access_token>
Content-Type必須application/json
Idempotency-Key任意同じキーで再試行すると、再処理せず最初のレスポンスを返します。「冪等性」の項を参照

リクエスト body

フィールド型必須説明
external_idstring必須登録システムの一意な ID。最大100文字。QR の値と一致している必要があります
namestring任意氏名。最大200文字
emailstring任意メールアドレス。保存時に AES-256-GCM で暗号化
phonestring任意電話番号。保存時に暗号化
companystring任意会社名。最大200文字
positionstring任意役職。最大100文字
extraobject任意自由形式の JSON。パートナー独自の拡張フィールド
curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "REG-001",
    "name": "John Smith",
    "email": "john@example.com",
    "phone": "010-1234-5678",
    "company": "Acme Inc.",
    "position": "CEO",
    "extra": { "booth": "A-12" }
  }'

レスポンス 200

送信した値をそのまま返します(送信内容の確認用)。フィールドの形式は連絡先の取得と同じです。ただし、このレスポンスの qr_image_url は常に null です — QR 画像の URL は連絡先の取得・一覧で取得してください。

{
  "id": "con_af2f95b4_REG-001",
  "object": "external_contact",
  "event_id": "af2f95b402794c8f9289360fc8765b8e",
  "external_id": "REG-001",
  "name": "John Smith",
  "email": "john@example.com",
  "phone": "010-1234-5678",
  "company": "Acme Inc.",
  "position": "CEO",
  "extra": {"booth": "A-12"},
  "created_at": "2026-09-07T04:50:38Z",
  "updated_at": "2026-09-07T04:50:38Z",
  "qr_image_url": null
}

エラー

HTTPcode原因
400validation_failedexternal_id の欠落、またはフィールドの長さ超過
400invalid_jsonリクエスト本文が有効な JSON ではない
401token_missing / token_invalidトークンがない / 不正・期限切れ
404event_not_foundイベントが存在しないか、キーの範囲外
409idempotency_conflict同じ Idempotency-Key を異なるリクエストに使用
409idempotency_in_progress同じ Idempotency-Key の最初のリクエストがまだ処理中
429rate_limitedレート制限超過

一括登録

最大 500件を一度に UPSERT します。初期データの投入や夜間の同期に使用してください。

POST /api/external/v1/events/{eventId}/contacts/batch

リクエスト body

フィールド型必須説明
contactsarray必須連絡先の配列。1〜500件。各要素は単件登録と同じ形式
curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts/batch \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "external_id": "REG-001", "name": "John Smith", "email": "john@example.com" },
      { "name": "Jane Doe", "email": "jane@example.com" }
    ]
  }'

レスポンス 200

例の2件目は external_id がないため、その件のみ失敗し、残りは保存されます。

{
  "total": 2,
  "created": 1,
  "updated": 0,
  "failed": 1,
  "errors": [
    {
      "external_id": null,
      "code": "validation_failed",
      "message": "external_id is required.",
      "param": "external_id"
    }
  ]
}
フィールド型説明
totalintegerリクエストに含まれる総件数
createdinteger新規作成した件数
updatedinteger既存データを上書きした件数
failedinteger保存されなかった件数
errorsarray失敗した項目のみ (external_id、code、message、param)。すべて成功した場合は空配列

注意

  • 配列が空、または500件を超える場合は、リクエスト全体が 400 validation_failed になります。
  • 部分的な成功を許可します。一部が失敗しても、正しい項目は保存されます。errors の項目だけを修正して再送信してください。UPSERT のため重複は発生しません。
  • 大量投入時に 429 を避けるには、「レート制限」の項を参照して間隔を空けてください。
  • Idempotency-Key ヘッダーに対応しています。タイムアウト時に同じキーで再試行すれば、一度だけ処理されます。「冪等性」の項を参照してください。

連絡先の一覧

このイベントに保存されている連絡先をすべて一度に取得します。送信したデータの照合や、名札印刷用の QR 画像の一括取得に使います。

GET /api/external/v1/events/{eventId}/contacts

curl https://connectelly.com/api/external/v1/events/<eventId>/contacts \
  -H "Authorization: Bearer eyJ..."

レスポンス 200

クエリパラメータとページネーションはありません。contacts の各要素は連絡先の取得レスポンスと同じフィールドを持ち、氏名・メールアドレス・電話番号も同じ方法でマスキングされます。

{
  "total": 2,
  "returned": 2,
  "truncated": false,
  "contacts": [
    {
      "id": "con_af2f95b4_REG-002",
      "object": "external_contact",
      "event_id": "af2f95b402794c8f9289360fc8765b8e",
      "external_id": "REG-002",
      "name": "J******e",
      "email": "ja**@example.com",
      "phone": null,
      "company": null,
      "position": null,
      "extra": null,
      "created_at": "2026-09-07T05:02:11Z",
      "updated_at": "2026-09-07T05:02:11Z",
      "qr_image_url": "https://cdn.connectelly.com/qr/af2f95b402794c8f9289360fc8765b8e/REG-002.png"
    },
    {
      "id": "con_af2f95b4_REG-001",
      "object": "external_contact",
      "event_id": "af2f95b402794c8f9289360fc8765b8e",
      "external_id": "REG-001",
      "name": "J********h",
      "email": "jo**@example.com",
      "phone": "010-****-5678",
      "company": "Acme Inc.",
      "position": "CEO",
      "extra": {"booth": "A-12"},
      "created_at": "2026-09-07T04:50:38Z",
      "updated_at": "2026-09-07T04:50:38Z",
      "qr_image_url": "https://cdn.connectelly.com/qr/af2f95b402794c8f9289360fc8765b8e/REG-001.png"
    }
  ]
}
フィールド型説明
totalintegerこのイベントに保存されている連絡先の総数
returnedintegerこのレスポンスに含まれる連絡先の数(最大 10,000)
truncatedbooleantrue の場合、10,000 件の上限に達し、最新の 10,000 件のみが返されています。担当者にお問い合わせください
contactsarray連絡先の一覧。登録が新しい順
  • 並び順は初回登録日時(created_at)の新しい順です。更新(UPSERT)しても順序は変わりません。
  • 一覧の取得では QR 画像を新たに生成しません。qr_image_url は登録時に画像が保存される URL のため、登録時に生成に失敗した連絡先はリンクが開けない場合があります。その連絡先を連絡先の取得 API で一度取得すると画像が生成されます。

エラー

HTTPcode原因
404event_not_foundイベントが存在しないか、キーの範囲外

連絡先の取得

登録済みの連絡先を1件取得します。

GET /api/external/v1/events/{eventId}/contacts/{externalId}

レスポンス 200 — 個人情報はマスキングされます

取得レスポンスの氏名・メールアドレス・電話番号は中央部分が伏せられます。API キーやトークンが漏えいした際に、連絡先が大量に収集されるのを防ぐための措置です。パートナーは元データをすでに保有しているため、実務上の支障はありません。

{
  "id": "con_af2f95b4_REG-001",
  "object": "external_contact",
  "event_id": "af2f95b402794c8f9289360fc8765b8e",
  "external_id": "REG-001",
  "name": "J********h",
  "email": "jo**@example.com",
  "phone": "010-****-5678",
  "company": "Acme Inc.",
  "position": "CEO",
  "extra": {"booth": "A-12"},
  "created_at": "2026-09-07T04:50:38Z",
  "updated_at": "2026-09-07T04:50:38Z",
  "qr_image_url": "https://cdn.connectelly.com/qr/af2f95b402794c8f9289360fc8765b8e/REG-001.png"
}
元の値取得レスポンス
john@example.comjo**@example.com
010-1234-5678010-****-5678
John SmithJ********h
홍길동홍*동

会社名・役職・extra はマスキングされません。登録・更新(UPSERT)のレスポンスは送信した値をそのまま返すため、マスキングされません。

レスポンスのフィールド

フィールド型説明
idstringcon_ + event_id の先頭 8 文字 + _ + external_id
objectstring常に external_contact
event_idstringイベント ID(32 文字)。パスの eventId と同じです
external_idstring送信した external_id そのまま
name / email / phonestring | nullマスキングされた値。送信していなければ null
company / positionstring | null送信した値そのまま。送信していなければ null
extraobject | null送信した extra オブジェクトをそのまま返します(例: {"booth": "A-12"})。送信していなければ null
created_atstring初回登録日時。ISO 8601 (UTC)。以後更新しても変わりません
updated_atstring最終更新日時。ISO 8601 (UTC)
qr_image_urlstring | null名札印刷用 QR 画像の URL(PNG、600×600px)。QR の値は external_id そのままです。画像がない場合はこの取得時に生成します。画像を生成できない場合は null

エラー

HTTPcode原因
404contact_not_found該当する external_id の連絡先がない
404event_not_foundイベントが存在しないか、キーの範囲外

連絡先の削除

登録済みの連絡先を1件削除します。来場キャンセルや重複登録の訂正時に使用してください。

DELETE /api/external/v1/events/{eventId}/contacts/{externalId}

curl -X DELETE https://connectelly.com/api/external/v1/events/<eventId>/contacts/REG-001 \
  -H "Authorization: Bearer eyJ..."

レスポンス 204

本文なしで 204 No Content を返します。

注意

  • 削除後に同じ QR をスキャンしても、リードはキャプチャされません。
  • すでにキャプチャされたリードは削除されません — アプリユーザーが収集した名刺はそのまま残ります。
  • 元に戻すことはできません。再登録するには UPSERT を呼び出してください。
  • Idempotency-Key ヘッダーに対応しています。同じキーで再試行すると最初のレスポンス (204) がそのまま再生されます。キーなしで再送すると、すでに削除済みのため 404 contact_not_found になります。

エラー

HTTPcode原因
404contact_not_found該当する external_id の連絡先がない
409idempotency_conflict同じ Idempotency-Key を異なるリクエストに使用
409idempotency_in_progress同じ Idempotency-Key の最初のリクエストがまだ処理中

エラーコード

すべてのエラーは Stripe スタイルの形式で返されます。

{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "external_id must be 100 characters or less.",
    "param": "external_id",
    "doc_url": null,
    "request_id": "req_3f9a1c2b7d4e5f60"
  }
}

message は開発者のログ向けで、常に英語です。言語設定によって変わることはありません。エラー処理の分岐は code で行ってください。message の文言には依存しないでください。param は問題のあるフィールド名、request_id はお問い合わせ時にリクエストを追跡するために使います。

コードHTTP意味
validation_failed400リクエスト値の検証失敗 (必須項目の欠落・長さ超過・件数超過など)
invalid_json400リクエスト本文が有効な JSON ではない
auth_missing401X-Connectelly-Api-Key ヘッダーがない
auth_invalid401キーを認識できない
key_expired401キーの有効期限切れ (または再発行の猶予期間終了)
key_revoked401キーが失効済み
token_missing401Authorization: Bearer トークンがない
token_invalid401トークンが不正または期限切れ
ip_not_allowed403許可されていない IP
event_not_found404イベントが存在しないか、キーの範囲外
contact_not_found404該当する external_id の連絡先がない
idempotency_conflict409同じ Idempotency-Key を異なるリクエスト (メソッド・パス・本文) に使用 — 新しいキーで送信してください
idempotency_in_progress409同じ Idempotency-Key の最初のリクエストがまだ処理中 — 少し待ってから同じリクエストを再試行してください
payload_too_large413リクエスト本文が 2MB を超えています (Idempotency-Key 付きのリクエスト) — 分割して送信してください
rate_limited429レート制限超過
internal_error500サーバーエラー

レート制限

既定値は 60 req/min per key per task です。Connectelly app-api は 2〜6 個の task でオートスケールするため、実質的な許容量は 120〜360 req/min です。

すべてのレスポンスに次のヘッダーが含まれます:

  • X-RateLimit-Limit — task あたりの許容量
  • X-RateLimit-Remaining — 現在のウィンドウで残っているリクエスト数
  • Retry-After — 429 の場合、再試行までの待機秒数

冪等性 (Idempotency)

リクエストがタイムアウトすると、サーバーがすでに処理したかどうかはわかりません。Idempotency-Key ヘッダーを付けて同じキーで再試行すれば、リクエストは一度だけ処理され、再試行には最初のレスポンスがそのまま返ります。

ヘッダー

ヘッダー必須説明
Idempotency-Key任意印字可能な ASCII 1〜255文字。UUID v4 を推奨。新しいリクエストごとに新しいキーを作成してください
  • 空の値、255文字超、制御文字を含む場合は 400 validation_failed になります (param: Idempotency-Key)。
  • 日本語など ASCII 以外の文字は、API に届く前に 403 で拒否される場合があります。ASCII のみを使用してください。
  • 対象は POST /contacts、POST /contacts/batch、DELETE /contacts/{externalId} です。GET リクエストと POST /token はこのヘッダーを無視します。
  • キーは API Key ごとに区別されます。他のパートナーのキーと混ざることはありません。
  • キーは最初のリクエストから24時間保持されます。その後、同じキーは新しいリクエストとして処理されます。
  • このヘッダーを付けたリクエストは、本文が 2MB を超えると 413 payload_too_large になります。一括登録の上限 500 件はこの範囲に収まります。

動作

ケース結果
キーを付けた最初のリクエスト通常どおり処理し、レスポンスを保存 (下記参照)
同じキー、同じリクエスト再処理しません。最初のレスポンスのステータスコードと本文をそのまま返し、Idempotent-Replayed: true ヘッダーを付けます
同じキー、異なるリクエスト409 idempotency_conflict — 新しいキーを使用してください
最初のリクエストが処理中に同じキー409 idempotency_in_progress — 少し待ってから同じリクエストを再送してください
  • 「同じリクエスト」とは、メソッド・パス・クエリ文字列・本文がバイト単位で同じものです。空白やフィールドの順序が違うだけでも別のリクエストになるため、最初に送ったバイトをそのまま再送してください。
  • 再生された本文の request_id は最初のリクエストの値で、レスポンスヘッダー X-Request-Id は再試行リクエストの新しい値です。
  • 再生されたレスポンスもレート制限の回数に含まれます。
HTTP/1.1 200
Content-Type: application/json
Idempotent-Replayed: true
X-Request-Id: req_8b2e4d1f0a9c3e75

保存されるレスポンス

レスポンス同じキーで再試行すると
2xx、および 400・404 などのクライアントエラー保存される — 同じレスポンスが再生されます
5xx、429、408、409、401、403保存されない — リクエストが再度処理されます

400 も再生されるため、400 を受けて修正したリクエストは新しいキーで送ってください。修正した本文を以前のキーで送ると 409 idempotency_conflict になります。

例: タイムアウト後の再試行

キーはリクエストごとに一度だけ作成し、再試行では同じキーを使います。以下の curl は、タイムアウト・408・429・5xx のときに同じキーで最大3回再試行します。再試行が 409 idempotency_in_progress を受けた場合は、少し待ってから同じリクエストを再送してください。

KEY=$(uuidgen)

curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $KEY" \
  --max-time 10 --retry 3 \
  -d '{ "external_id": "REG-001", "name": "John Smith" }'

変更履歴

  • 2026-10-14 — Idempotency-Key に対応 (連絡先の登録 / 一括 / 削除)、連絡先一覧 API を文書化、連絡先取得レスポンスのフィールドを拡充、extra を文字列ではなくオブジェクトで返すように変更
  • v1.0 (2026-09) — 初回リリース: Contacts API (単件 / 一括 / 取得 / 削除)