クイックスタート
Connectelly External API は2段階認証を採用しています。API キーを短期間有効な access token と交換し、実際の呼び出しはそのトークンで行います。
- パートナー申請を行い API キーを受け取る — 契約締結後、マスター管理者がキーを発行します。
- access token を発行する —
POST /api/external/v1/token - トークンで呼び出す —
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_token | string | 以降すべてのリクエストの Authorization ヘッダーに使用 |
| token_type | string | 常に Bearer |
| expires_in | integer | 残り有効期間(秒)。既定値 1800 = 30分 |
| expires_at | string | 有効期限 (ISO-8601 UTC) |
| event_id | string | このキーに紐づくイベント ID。以降すべてのエンドポイントのパス {eventId} にそのまま使用 |
eventId はどこで取得しますか?
API キーは1つのイベントに紐づけて発行されるため、eventId を別途管理する必要はありません。次の2つの方法で確認できます。
- トークンレスポンスの
event_id— 上記のレスポンスから直接取得します。ハードコーディングせず、この値を使うことを推奨します。 - キー発行時の案内 — 担当者が API キーをお渡しする際に併せてお知らせします。
他のイベントの eventId を指定すると、404 event_not_found が返されます。
エラー
| HTTP | code | 原因 |
|---|---|---|
| 401 | auth_missing | ヘッダーがない |
| 401 | auth_invalid | キーを認識できない |
| 401 | key_expired | キーの有効期限切れ (または再発行の猶予期間終了) |
| 401 | key_revoked | キーが失効済み |
| 403 | ip_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_id | string | 必須 | 登録システムの一意な ID。最大100文字。QR の値と一致している必要があります |
| name | string | 任意 | 氏名。最大200文字 |
| string | 任意 | メールアドレス。保存時に AES-256-GCM で暗号化 | |
| phone | string | 任意 | 電話番号。保存時に暗号化 |
| company | string | 任意 | 会社名。最大200文字 |
| position | string | 任意 | 役職。最大100文字 |
| extra | object | 任意 | 自由形式の 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
}
エラー
| HTTP | code | 原因 |
|---|---|---|
| 400 | validation_failed | external_id の欠落、またはフィールドの長さ超過 |
| 400 | invalid_json | リクエスト本文が有効な JSON ではない |
| 401 | token_missing / token_invalid | トークンがない / 不正・期限切れ |
| 404 | event_not_found | イベントが存在しないか、キーの範囲外 |
| 409 | idempotency_conflict | 同じ Idempotency-Key を異なるリクエストに使用 |
| 409 | idempotency_in_progress | 同じ Idempotency-Key の最初のリクエストがまだ処理中 |
| 429 | rate_limited | レート制限超過 |
一括登録
最大 500件を一度に UPSERT します。初期データの投入や夜間の同期に使用してください。
POST /api/external/v1/events/{eventId}/contacts/batch
リクエスト body
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| contacts | array | 必須 | 連絡先の配列。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"
}
]
}
| フィールド | 型 | 説明 |
|---|---|---|
| total | integer | リクエストに含まれる総件数 |
| created | integer | 新規作成した件数 |
| updated | integer | 既存データを上書きした件数 |
| failed | integer | 保存されなかった件数 |
| errors | array | 失敗した項目のみ (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"
}
]
}
| フィールド | 型 | 説明 |
|---|---|---|
| total | integer | このイベントに保存されている連絡先の総数 |
| returned | integer | このレスポンスに含まれる連絡先の数(最大 10,000) |
| truncated | boolean | true の場合、10,000 件の上限に達し、最新の 10,000 件のみが返されています。担当者にお問い合わせください |
| contacts | array | 連絡先の一覧。登録が新しい順 |
- 並び順は初回登録日時(
created_at)の新しい順です。更新(UPSERT)しても順序は変わりません。 - 一覧の取得では QR 画像を新たに生成しません。
qr_image_urlは登録時に画像が保存される URL のため、登録時に生成に失敗した連絡先はリンクが開けない場合があります。その連絡先を連絡先の取得 API で一度取得すると画像が生成されます。
エラー
| HTTP | code | 原因 |
|---|---|---|
| 404 | event_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.com | jo**@example.com |
| 010-1234-5678 | 010-****-5678 |
| John Smith | J********h |
| 홍길동 | 홍*동 |
会社名・役職・extra はマスキングされません。登録・更新(UPSERT)のレスポンスは送信した値をそのまま返すため、マスキングされません。
レスポンスのフィールド
| フィールド | 型 | 説明 |
|---|---|---|
| id | string | con_ + event_id の先頭 8 文字 + _ + external_id |
| object | string | 常に external_contact |
| event_id | string | イベント ID(32 文字)。パスの eventId と同じです |
| external_id | string | 送信した external_id そのまま |
| name / email / phone | string | null | マスキングされた値。送信していなければ null |
| company / position | string | null | 送信した値そのまま。送信していなければ null |
| extra | object | null | 送信した extra オブジェクトをそのまま返します(例: {"booth": "A-12"})。送信していなければ null |
| created_at | string | 初回登録日時。ISO 8601 (UTC)。以後更新しても変わりません |
| updated_at | string | 最終更新日時。ISO 8601 (UTC) |
| qr_image_url | string | null | 名札印刷用 QR 画像の URL(PNG、600×600px)。QR の値は external_id そのままです。画像がない場合はこの取得時に生成します。画像を生成できない場合は null |
エラー
| HTTP | code | 原因 |
|---|---|---|
| 404 | contact_not_found | 該当する external_id の連絡先がない |
| 404 | event_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) がそのまま再生されます。キーなしで再送すると、すでに削除済みのため 404contact_not_foundになります。
エラー
| HTTP | code | 原因 |
|---|---|---|
| 404 | contact_not_found | 該当する external_id の連絡先がない |
| 409 | idempotency_conflict | 同じ Idempotency-Key を異なるリクエストに使用 |
| 409 | idempotency_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_failed | 400 | リクエスト値の検証失敗 (必須項目の欠落・長さ超過・件数超過など) |
| invalid_json | 400 | リクエスト本文が有効な JSON ではない |
| auth_missing | 401 | X-Connectelly-Api-Key ヘッダーがない |
| auth_invalid | 401 | キーを認識できない |
| key_expired | 401 | キーの有効期限切れ (または再発行の猶予期間終了) |
| key_revoked | 401 | キーが失効済み |
| token_missing | 401 | Authorization: Bearer トークンがない |
| token_invalid | 401 | トークンが不正または期限切れ |
| ip_not_allowed | 403 | 許可されていない IP |
| event_not_found | 404 | イベントが存在しないか、キーの範囲外 |
| contact_not_found | 404 | 該当する external_id の連絡先がない |
| idempotency_conflict | 409 | 同じ Idempotency-Key を異なるリクエスト (メソッド・パス・本文) に使用 — 新しいキーで送信してください |
| idempotency_in_progress | 409 | 同じ Idempotency-Key の最初のリクエストがまだ処理中 — 少し待ってから同じリクエストを再試行してください |
| payload_too_large | 413 | リクエスト本文が 2MB を超えています (Idempotency-Key 付きのリクエスト) — 分割して送信してください |
| rate_limited | 429 | レート制限超過 |
| internal_error | 500 | サーバーエラー |
レート制限
既定値は 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 (単件 / 一括 / 取得 / 削除)