DM Champ Docs

予約

Appointments APIを使用すると、連絡先の予約をイベントタイプに基づいて行い、取得、一覧表示、更新、キャンセル、削除することができます。また、ほとんどの予約フローで最初に発生する「どの時間が実際に空いているか」という疑問に答え、カレンダー側(接続済みのGoogleカレンダーの一覧表示や、既存のイベントのインポート)もカバーします。Googleカレンダーの接続が有効な場合、対応するカレンダーイベントが自動的にバックグラウンドで作成され、同期が維持されます。Zenchef、Formitable、OpenTable、またはTheForkを独自の予約システムとして使用しているレストランもここで検証および接続できるため、AIエージェントは内部的な予定ではなく実際のテーブルを予約します。Trafftでスケジュールを管理している予約ビジネスも同様の方法で接続可能です。

このページのすべてのパスは、ベースURL https://api.dmchamp.com/v1 からの相対パスです。すべてのリクエストにはAPIキーが必要です。送信方法の全リストについては認証を参照してください。以下の例では X-API-Key ヘッダーを使用しており、1つのcURL例では ?apiKey= クエリ形式も示しています。

イベントと予約の違い: イベントタイプとは、予約可能なスロットの定義(会議の種類、長さ、部屋など)です。予約とは、特定の連絡先に対してイベントタイプを予約した1つのインスタンスです。連絡先とイベントタイプを参照することで予約を行います。


予約オブジェクト

予約を返す各エンドポイントは、同じ形式を使用します。

フィールド 説明
id 予約の一意のID。
contact_id 予約した連絡先のID。
event_id 予約されたイベントタイプのID。
status Confirmed または Canceled
start_time 予約の開始日時(ISO 8601形式、UTC)。
end_time 予約の終了日時(ISO 8601形式、UTC)。
created_at 予約が作成された日時。
last_modified_at 予約が最後に変更された日時。
room_name イベントタイプで部屋を使用している場合、予約された部屋またはリソース。
description 予約の自由形式の説明。
summary 短い概要またはタイトル。
cancelation_reason 予約がキャンセルされた場合に提供された理由(ある場合)。
google_calendar_event_id リンクされたGoogleカレンダーイベントのID。カレンダー同期が完了すると設定されます。カレンダーが接続されていない場合や同期中の場合は null となります。
calendar_synced 予約がカレンダーイベントにリンクされると true になります。
imported 直接予約されたのではなく、外部カレンダーからインポートされた予約の場合に true となります。
is_recurring 予約が定期的なシリーズの一部である場合に true となります。
recurrence_frequency 定期的な予約の場合の繰り返し頻度。
recurring_event_id この予約が属する定期的なシリーズのID。
recurring_interval 定期的な予約の場合の繰り返し間隔。
recurring_sequence 定期的なシリーズ内でのこの予約の位置。
end_after_x_occurrences 定期的なシリーズが終了するまでの発生回数。
booking_provider 接続された予約プロバイダーを通じて予約された場合の、予約元のシステム。

カレンダー同期について: 予約の直後や変更直後は、同期がバックグラウンドで少し遅れて実行されるため、google_calendar_event_idnull のまま、calendar_syncedfalse になっている場合があります。少し時間を置いてから予約を再度取得すると、カレンダーのフィールドが反映されていることが確認できます。


空き枠の検索

GET /appointments/available-slots

2つの時点の間で、特定のイベントタイプにおいて実際に空いている時間を返します。これは通常、予約フローにおける最初の呼び出しとなります。これらの枠を表示し、ユーザーに1つ選択してもらい、その選択された時間を予約の登録にPOSTします。

この回答には、イベントタイプ自体の営業時間と枠の長さ、部屋、すでに予約済みの予定、および接続されたGoogleカレンダーでブロックされているすべての予定がすでに考慮されています。そのため、ここで返される枠は予約可能なものとなります。

クエリパラメータ 必須 説明
event_id はい 確認するイベントタイプ。アカウントに属している必要があります。
start_time はい 枠を取得したい期間の開始日時(ISO 8601形式)。
end_time はい 期間の終了日時(ISO 8601形式)。終了日全体が含まれます。

結果は日ごとにグループ化されて返されます。イベントタイプで部屋を使用している場合は、日ごと、かつ部屋ごとにグループ化されます。

フィールド 説明
date グループが対象とする日付(DD/MM/YYYY形式)。
day 曜日の小文字表記(例: monday)。
room_name イベントタイプで部屋を使用している場合、このグループが属する部屋またはリソース。
available_slots その日の予約可能なブロック(早い順)。

available_slotsの各エントリには以下が含まれます。

フィールド 説明
start_time ブロックの開始時刻(HH:mm形式)。
end_time ブロックの終了時刻(HH:mm形式)。
available true — 空き時間のみが返されます。
spots_left このブロックにあと何件の予約が可能か。1つの枠で複数の予約を受け付けるイベントタイプの場合のみ表示されます。

時間はUTCではなく、イベントタイプのローカル時間です。 datestart_time、およびend_timeは、イベントタイプ自身のタイムゾーン(オーバーライド設定、または設定がない場合はアカウントのタイムゾーン)における時計の時刻です。予約の登録ではISO 8601形式のUTC時刻が期待されるため、選択した枠をPOSTする前に変換してください。

cURL

curl "https://api.dmchamp.com/v1/appointments/available-slots?event_id=event_xyz789&start_time=2026-06-15T00:00:00.000Z&end_time=2026-06-19T00:00:00.000Z" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({
  event_id: "event_xyz789",
  start_time: "2026-06-15T00:00:00.000Z",
  end_time: "2026-06-19T00:00:00.000Z",
});
const res = await fetch(
  `https://api.dmchamp.com/v1/appointments/available-slots?${params}`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.data);

Python

import requests

res = requests.get(
    "https://api.dmchamp.com/v1/appointments/available-slots",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={
        "event_id": "event_xyz789",
        "start_time": "2026-06-15T00:00:00.000Z",
        "end_time": "2026-06-19T00:00:00.000Z",
    },
)
print(res.json()["data"])

レスポンス (200 OK):

{
  "success": true,
  "data": [
    {
      "date": "15/06/2026",
      "day": "monday",
      "room_name": "Room A",
      "available_slots": [
        { "start_time": "10:00", "end_time": "10:30", "available": true },
        { "start_time": "10:30", "end_time": "11:00", "available": true }
      ]
    },
    {
      "date": "16/06/2026",
      "day": "tuesday",
      "room_name": "Room A",
      "available_slots": [
        { "start_time": "09:00", "end_time": "09:30", "available": true, "spots_left": 2 }
      ]
    }
  ]
}

空きがない日は単純に表示されません。event_idstart_time、またはend_timeが欠落している場合は400が返されます。アカウントに存在しないイベントタイプを指定した場合は404が返されます。


予約の登録

POST /appointments

連絡先に対して、イベントタイプに基づいた新しい予約を登録します。終了時刻は、イベントタイプに設定されたスロット時間から自動的に計算されます。

予約には競合チェックが行われます。リクエストされたスロットが同じイベントタイプ上の既存の確定済み予約と重複する場合、リクエストは 409 で失敗し、何も作成されません。

フィールド 必須 説明
contact_id はい 予約する連絡先のID。アカウントに属している必要があります。
event_id はい 予約するイベントタイプのID。アカウントに属している必要があります。
start_time はい 希望する開始日時(ISO 8601形式)。
room_name いいえ イベントタイプで部屋を使用している場合の、部屋またはリソース名。

cURL (?apiKey= クエリ形式を使用)

curl -X POST "https://api.dmchamp.com/v1/appointments?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "contact_abc123",
    "event_id": "event_xyz789",
    "start_time": "2026-06-15T10:00:00.000Z",
    "room_name": "Room A"
  }'

JavaScript

const res = await fetch("https://api.dmchamp.com/v1/appointments", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    contact_id: "contact_abc123",
    event_id: "event_xyz789",
    start_time: "2026-06-15T10:00:00.000Z",
    room_name: "Room A",
  }),
});
const data = await res.json();
console.log(data.appointment_id);

Python

import requests

res = requests.post(
    "https://api.dmchamp.com/v1/appointments",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "contact_id": "contact_abc123",
        "event_id": "event_xyz789",
        "start_time": "2026-06-15T10:00:00.000Z",
        "room_name": "Room A",
    },
)
print(res.json()["appointment_id"])

レスポンス (201 Created):

{
  "success": true,
  "appointment_id": "aBcD1234eFgH5678",
  "appointment": {
    "id": "aBcD1234eFgH5678",
    "contact_id": "contact_abc123",
    "event_id": "event_xyz789",
    "status": "Confirmed",
    "start_time": "2026-06-15T10:00:00.000Z",
    "end_time": "2026-06-15T10:30:00.000Z",
    "created_at": "2026-06-10T09:00:00.000Z",
    "last_modified_at": "2026-06-10T09:00:00.000Z",
    "room_name": "Room A",
    "google_calendar_event_id": null,
    "calendar_synced": false
  }
}

予約の取得

GET /appointments/{appointmentId}

IDを指定して単一の予約を取得します。これにはカレンダーの同期状態も含まれます。

cURL

curl "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const res = await fetch(
  "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.appointment);

Python

import requests

res = requests.get(
    "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["appointment"])

レスポンス (200 OK):

{
  "success": true,
  "appointment": {
    "id": "aBcD1234eFgH5678",
    "contact_id": "contact_abc123",
    "event_id": "event_xyz789",
    "status": "Confirmed",
    "start_time": "2026-06-15T10:00:00.000Z",
    "end_time": "2026-06-15T10:30:00.000Z",
    "room_name": "Room A",
    "google_calendar_event_id": "abc123googleevent",
    "calendar_synced": true
  }
}

予約の一覧表示

GET /appointments

アカウントの予約を新しい順に一覧表示します。カーソルベースのページネーションを使用します。

クエリパラメータ 必須 説明
contact_id いいえ 指定した連絡先の予約のみを返します。連絡先でフィルタリングされた一覧には確定済みの予約のみが含まれます。
date いいえ 指定したカレンダーの日付(YYYY-MM-DD)の予約のみを返します。contact_idが必要です。
status いいえ ConfirmedまたはCanceledでフィルタリングします。contact_id指定していない場合のみ利用可能です。
limit いいえ 1から100までの整数でページサイズを指定します。デフォルトは50です。
cursor いいえ 前回のレスポンスから取得したnext_cursorの値です。

留意すべきいくつかのルール:

  • フィルタなしの場合、アカウント上のすべての予約をページごとに取得します。
  • 連絡先別contact_idを設定すると、特定の連絡先の確定済み予約を表示できます。dateも併せて渡すことで、特定の日付に絞り込むことも可能です。
  • ステータス別statusを設定(contact_idは指定しない)すると、アカウント全体でConfirmedまたはCanceledの予約のみを一覧表示できます。
  • contact_idなしでのdateフィルタ、またはstatus=Canceledcontact_idを組み合わせた場合は、400が返されます。

cURL

curl "https://api.dmchamp.com/v1/appointments?contact_id=contact_abc123&date=2026-06-15" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const params = new URLSearchParams({
  contact_id: "contact_abc123",
  date: "2026-06-15",
});
const res = await fetch(
  `https://api.dmchamp.com/v1/appointments?${params}`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.appointments, data.next_cursor);

Python

import requests

res = requests.get(
    "https://api.dmchamp.com/v1/appointments",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"contact_id": "contact_abc123", "date": "2026-06-15"},
)
data = res.json()
print(data["appointments"], data["next_cursor"])

レスポンス (200 OK):

{
  "success": true,
  "appointments": [
    {
      "id": "aBcD1234eFgH5678",
      "contact_id": "contact_abc123",
      "event_id": "event_xyz789",
      "status": "Confirmed",
      "start_time": "2026-06-15T10:00:00.000Z",
      "end_time": "2026-06-15T10:30:00.000Z",
      "calendar_synced": true
    }
  ],
  "next_cursor": null
}

結果をページ送りするには、あるレスポンスのnext_cursorを次のリクエストのcursorとして渡します。next_cursornullになるまで繰り返します。共通のページネーションパターンについてはエラーとページネーションを参照してください。


予約の更新

PUT /appointments/{appointmentId}

予約の日時変更や詳細の変更を行います。変更したいフィールドのみを送信してください(少なくとも1つは必須です)。開始時刻と終了時刻を組み合わせた場合、時系列順である必要があります(end_timestart_timeより後である必要があります)。変更内容はリンクされたカレンダーイベントに自動的に同期されます。

フィールド 説明
start_time 新しい開始日時(ISO 8601形式)。
end_time 新しい終了日時(ISO 8601形式)。開始日時より後の時刻である必要があります。
room_name 新しい会議室またはリソース名。
description 新しい説明。クリアする場合は null を指定します。
summary 新しい概要。クリアする場合は null を指定します。

cURL

curl -X PUT "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "start_time": "2026-06-16T10:00:00.000Z",
    "end_time": "2026-06-16T10:30:00.000Z"
  }'

JavaScript

const res = await fetch(
  "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      start_time: "2026-06-16T10:00:00.000Z",
      end_time: "2026-06-16T10:30:00.000Z",
    }),
  }
);
const data = await res.json();
console.log(data.appointment);

Python

import requests

res = requests.put(
    "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "start_time": "2026-06-16T10:00:00.000Z",
        "end_time": "2026-06-16T10:30:00.000Z",
    },
)
print(res.json()["appointment"])

レスポンス (200 OK):

{
  "success": true,
  "appointment_id": "aBcD1234eFgH5678",
  "appointment": {
    "id": "aBcD1234eFgH5678",
    "contact_id": "contact_abc123",
    "event_id": "event_xyz789",
    "status": "Confirmed",
    "start_time": "2026-06-16T10:00:00.000Z",
    "end_time": "2026-06-16T10:30:00.000Z",
    "calendar_synced": true
  }
}

予約のキャンセル

POST /appointments/{appointmentId}/cancel

確定済みの予約をキャンセルします(オプションで理由を記録可能)。予約はステータス Canceled としてアカウント内に保持され、リンクされているカレンダーイベントはバックグラウンドで自動的に削除されます。すでにキャンセル済みの予約をキャンセルしようとすると、400 が返されます。

フィールド 必須 説明
cancellation_reason いいえ キャンセルの理由。予約情報に保存されます。

cURL

curl -X POST "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678/cancel" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cancellation_reason": "Client asked to reschedule next month"
  }'

JavaScript

const res = await fetch(
  "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678/cancel",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      cancellation_reason: "Client asked to reschedule next month",
    }),
  }
);
const data = await res.json();
console.log(data.success);

Python

import requests

res = requests.post(
    "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678/cancel",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"cancellation_reason": "Client asked to reschedule next month"},
)
print(res.json()["success"])

レスポンス (200 OK):

{
  "success": true,
  "appointment_id": "aBcD1234eFgH5678"
}

予約の削除

DELETE /appointments/{appointmentId}

予約とその参照情報を完全に削除します。記録を残したまま予約を取り消したい場合は、代わりに キャンセル を使用してください。

cURL

curl -X DELETE "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const res = await fetch(
  "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678",
  { method: "DELETE", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.success);

Python

import requests

res = requests.delete(
    "https://api.dmchamp.com/v1/appointments/aBcD1234eFgH5678",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["success"])

レスポンス (200 OK):

{
  "success": true
}

接続済みGoogleカレンダーの一覧表示

GET /appointments/google-calendars

このアカウントで利用可能なGoogleカレンダーをGoogleから直接返します。これは、アカウント所有者にインポート元のカレンダーを選択させるピッカーを表示する場合や、接続が有効であることを確認する場合に便利です。

これは、アカウントが(設定 → 連携)からGoogleカレンダーに接続し、少なくとも読み取り権限が付与されている場合にのみ機能します。接続されていない場合、または付与された権限にカレンダーの読み取りスコープが含まれなくなった場合は、接続(または再接続)を促す400が返されます。

cURL

curl "https://api.dmchamp.com/v1/appointments/google-calendars" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const res = await fetch("https://api.dmchamp.com/v1/appointments/google-calendars", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.data);

Python

import requests

res = requests.get(
    "https://api.dmchamp.com/v1/appointments/google-calendars",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["data"])

レスポンス (200 OK):

{
  "success": true,
  "data": [
    {
      "id": "primary",
      "summary": "jane@example.com",
      "timeZone": "America/New_York",
      "accessRole": "owner",
      "primary": true
    },
    {
      "id": "abcdefg1234567890@group.calendar.google.com",
      "summary": "Bookings",
      "timeZone": "America/New_York",
      "accessRole": "writer"
    }
  ]
}

各エントリはGoogle独自のCalendarListEntry形式であるため、フィールド名は本APIの一般的なsnake_caseではなく、GoogleのcamelCaseに従います。これはGoogleのデータをそのまま渡しているものであり、当社のデータではありません。接続が欠落しているか取り消されている場合は、Googleカレンダーの接続(または再接続)が必要であることを説明するエラーとともに400が返されます。


Googleカレンダーからイベントをインポートする

POST /appointments/import-calendar-events

キャンペーンまたはAIエージェントの接続済みGoogleカレンダーに既に存在するイベントを取得し、アポイントメントに変換します。これは、既に予約が入っているカレンダーを初めて接続する場合に便利です。各イベントの抽出処理(誰のための予約かを判断するため)に時間がかかる可能性があるため、インラインでは実行されません。リクエストはバックグラウンドジョブとしてキューに入れられ、ポーリング用のjob_idが返されます。

フィールド 必須 説明
campaign_id どちらか一方 インポート元の接続済みカレンダーを持つキャンペーン。
agent_id どちらか一方 インポート元の接続済みカレンダーを持つAIエージェント。
identifier はい "EMAIL"または"PHONE_NUMBER" — 各カレンダーイベントから抽出して、所属する連絡先を照合または作成するために使用する連絡先情報。

campaign_idまたはagent_idのいずれか一方のみを送信してください。両方送信したり、どちらも送信しなかったりすると、400が返されます。送信するIDは、ご自身のアカウントに属している必要があります。そうでない場合は404が返されます。

cURL

curl -X POST "https://api.dmchamp.com/v1/appointments/import-calendar-events?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agent_abc123",
    "identifier": "EMAIL"
  }'

JavaScript

const res = await fetch("https://api.dmchamp.com/v1/appointments/import-calendar-events", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    agent_id: "agent_abc123",
    identifier: "EMAIL",
  }),
});
const data = await res.json();
console.log(data.job_id);

Python

import requests

res = requests.post(
    "https://api.dmchamp.com/v1/appointments/import-calendar-events",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"agent_id": "agent_abc123", "identifier": "EMAIL"},
)
print(res.json()["job_id"])

レスポンス (202 Accepted):

{
  "success": true,
  "job_id": "jK9mQ2xR7pL4wN1t",
  "status": "queued",
  "campaign_id": null,
  "agent_id": "agent_abc123"
}

campaign_idagent_idは送信した値をそのまま返します。もう一方は常にnullとなります。

インポートジョブをポーリングする

GET /appointments/import-calendar-events/{jobId}

curl "https://api.dmchamp.com/v1/appointments/import-calendar-events/jK9mQ2xR7pL4wN1t" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK):

{
  "success": true,
  "job_id": "jK9mQ2xR7pL4wN1t",
  "status": "completed",
  "message": "Imported 12 events as appointments.",
  "error": null
}
status 意味
queued まだ処理されていません。ポーリングを続けてください。
processing インポートを実行中です。ポーリングを続けてください。
completed 完了しました。messageに人間が読める形式の短い要約が含まれています。
failed 何らかのエラーが発生しました。errorに理由が記載されています。

存在しない(または別のアカウントに属する)jobIdに対してGETを実行すると、404が返されます。


外部予約連携 (Zenchef / Formitable / OpenTable / TheFork / Trafft)

ZenchefとFormitableは、AIエージェントが実際のテーブルを予約できるレストラン予約システムです。Trafftは予約ビジネス向けのスケジューリングプラットフォームであり、レストランごとではなくアカウントごとに1回接続します。2つのレストランプラットフォームにはそれぞれ、ダイナー(食事客)のためにチャット内でレンダリングされる公開された認証不要の予約ウィジェットhttps://api.dmchamp.com/v1/zenchef-widget/...およびhttps://api.dmchamp.com/v1/formitable-widget/...)があります。これらのウィジェットルートはブラウザで開くことを目的としたプレーンなHTMLページであり、JSON APIエンドポイントではないため、ここではドキュメント化されていません。以下はアカウント管理エンドポイントであり、レストランIDがアカウント所有者に属していることを確認し、追加、更新、または削除を行うためのものです。

Zenchef

Zenchefレストランの接続は2段階の認証プロセスとなっており、ボットに接続する前に、アカウント所有者が実際にそのレストランを運営していることを証明する必要があります。まずIDが存在するかを確認し(名前は表示されません)、次にレストラン名を本人に入力してもらい、それが一致するかを検証します。

ステップ 1 — レストランIDの存在確認

POST /appointments/zenchef-restaurants/check

フィールド 必須 説明
restaurant_id はい 確認するZenchefレストランID。
curl -X POST "https://api.dmchamp.com/v1/appointments/zenchef-restaurants/check?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "12345" }'

レスポンス (200 OK):

{
  "success": true,
  "data": { "exists": true, "requiresNameVerification": true }
}

exists: falseは、そのIDを持つZenchefレストランが存在しないことを意味します。これ以上の操作は不要です。レート制限はアカウントごとに5分間で10回までです。これを超えると429が返されます。

ステップ 2 — レストラン名の検証

POST /appointments/zenchef-restaurants/verify-name

フィールド 必須 説明
restaurant_id はい ステップ1で取得したZenchefレストランID。
user_input_name はい アカウント所有者が入力した名前。Zenchef上の実際のレストラン名と照合されます(大文字小文字や空白は区別されません)。
curl -X POST "https://api.dmchamp.com/v1/appointments/zenchef-restaurants/verify-name?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "12345", "user_input_name": "The Blue Door Bistro" }'

レスポンス (200 OK):

{
  "success": true,
  "data": {
    "verified": true,
    "restaurantDetails": {
      "id": "12345",
      "name": "The Blue Door Bistro",
      "address": "1 Rue de Rivoli, Paris",
      "status": "active"
    }
  }
}

verified: falseは名前が一致しなかったことを意味します。restaurantDetailsは省略されるため、アカウント所有者に再試行を依頼してください。レート制限は5分間で3回までです(これが実際の証明ステップであるため、存在確認よりも厳しくなっています)。Zenchef上で解決できなくなったrestaurant_idは、404を返します。

ステップ 3 — レストランの保存

POST /appointments/zenchef-restaurants

フィールド 必須 説明
restaurant_id はい 1〜64文字。英数字、アンダースコア、ハイフンが使用可能です。
restaurant_name はい ステップ2で検証済みのレストラン名。
curl -X POST "https://api.dmchamp.com/v1/appointments/zenchef-restaurants?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "12345", "restaurant_name": "The Blue Door Bistro" }'

レスポンス (201 Created):

{ "success": true, "data": { "restaurantId": "12345" } }

保存されたZenchefレストランの更新

PUT /appointments/zenchef-restaurants/{restaurantId}

フィールド 必須 説明
restaurant_name いいえ 新しい表示名。
is_active いいえ レストランを削除せずにボットによる予約を停止するには、false を設定します。
curl -X PUT "https://api.dmchamp.com/v1/appointments/zenchef-restaurants/12345" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'

レスポンス (200 OK): 上記の保存レスポンスと同じ形式。

Zenchefレストランの削除

DELETE /appointments/zenchef-restaurants/{restaurantId}

curl -X DELETE "https://api.dmchamp.com/v1/appointments/zenchef-restaurants/12345" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK): { "success": true, "data": { "restaurantId": "12345" } }

アカウントに現在存在しない restaurantId を更新または削除しようとすると、404 が返されます。

Formitable

FormitableはZenchefのような2段階の名前確認を必要としません。レストランIDはすでにビジネスごとにスコープ設定されているため、1回の検証呼び出しで十分です。また、セットアップ中にレストランのウェブサイトURLをキャッシュするために使用される詳細ルックアップ機能もあります。

レストランIDの検証

POST /appointments/formitable-restaurants/verify

フィールド 必須 説明
restaurant_id はい FormitableのレストランID。
language いいえ プローブ要求の言語タグ。デフォルトは "nl" です。
curl -X POST "https://api.dmchamp.com/v1/appointments/formitable-restaurants/verify?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "the-blue-door", "language": "en" }'

レスポンス (200 OK):

{
  "success": true,
  "data": {
    "verified": true,
    "restaurantDetails": {
      "restaurantId": "the-blue-door",
      "productCount": 4,
      "sampleProductTitle": "Dinner for two",
      "language": "en"
    }
  }
}

Formitableが認識できない restaurant_id は、404 を返します。レート制限は、アカウントごとに5分間で10回までです。

レストラン詳細の取得

GET /appointments/formitable-restaurants/{restaurantId}/details?language=en

Formitableからレストランの公開プロフィール(ウェブサイトを含む)を取得します。これは、レストランのセットアップ中にウェブサイトURLをキャッシュするために使用されます。language はオプションのクエリパラメータで、デフォルトは "en" です。

curl "https://api.dmchamp.com/v1/appointments/formitable-restaurants/the-blue-door/details?language=en" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK):

{
  "success": true,
  "data": {
    "uid": "the-blue-door",
    "name": "The Blue Door Bistro",
    "website": "https://thebluedoorbistro.com",
    "email": "info@thebluedoorbistro.com",
    "telephone": "+31201234567",
    "streetAddress": "Prinsengracht 1",
    "zipcode": "1015 AB",
    "city": "Amsterdam",
    "country": "Netherlands",
    "countryCode": "NL",
    "currency": "EUR"
  }
}

レストランを保存する

POST /appointments/formitable-restaurants

フィールド 必須 説明
restaurant_id はい 1〜64文字。英数字、アンダースコア、ハイフンが使用可能です。
restaurant_name はい 表示名。
language はい ISO言語タグ(例: "en""en-GB")。
website_url いいえ 上記の詳細検索で取得したレストランのウェブサイト。 http(s):// である必要があります。
curl -X POST "https://api.dmchamp.com/v1/appointments/formitable-restaurants?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "restaurant_id": "the-blue-door",
    "restaurant_name": "The Blue Door Bistro",
    "language": "en",
    "website_url": "https://thebluedoorbistro.com"
  }'

レスポンス (201 Created): { "success": true, "data": { "restaurantId": "the-blue-door" } }

保存済みのFormitableレストランを更新する

PUT /appointments/formitable-restaurants/{restaurantId}

フィールド 必須 説明
restaurant_name いいえ 新しい表示名。
language いいえ 新しいISO言語タグ。
is_active いいえ false を設定すると、レストランを削除せずにボットによる予約を停止できます。
website_url いいえ 新しいウェブサイトURL。
curl -X PUT "https://api.dmchamp.com/v1/appointments/formitable-restaurants/the-blue-door" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'

レスポンス (200 OK): 上記の保存レスポンスと同じ形式。

Formitableレストランを削除する

DELETE /appointments/formitable-restaurants/{restaurantId}

curl -X DELETE "https://api.dmchamp.com/v1/appointments/formitable-restaurants/the-blue-door" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK): { "success": true, "data": { "restaurantId": "the-blue-door" } }

アカウントに現在存在しない restaurantId を更新または削除しようとすると、404 が返されます。

OpenTable

OpenTableのレストランには、プラットフォームのOpenTableパートナー資格情報を通じてアクセスします。OpenTableでは、OpenTableの「Integrations Marketplace」内でプラットフォームのリスティングを接続したレストランのみが、これらの資格情報から参照可能になります。そのため、Formitableと同様に、1回の検証呼び出しで十分です。到達可能なレストランID(数値の「RID」)は、レストランが存在することと、統合が接続されていることの両方を証明します。OpenTableのパートナーリスティングがプラットフォーム上で有効になるまで、検証呼び出しは 503 を返します。

OpenTableレストランの検証

POST /appointments/opentable-restaurants/verify

フィールド 必須 説明
restaurant_id はい OpenTableレストランID(RID)。1038007のような数値です。
curl -X POST "https://api.dmchamp.com/v1/appointments/opentable-restaurants/verify?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "1038007" }'

レスポンス (200 OK):

{
  "success": true,
  "data": {
    "verified": true,
    "restaurantDetails": {
      "restaurantId": "1038007",
      "diningAreaCount": 2,
      "diningAreaNames": ["Main Room", "Garden"],
      "tableTypes": ["default", "outdoor", "bar"]
    }
  }
}

verified: false は、そのIDを持つOpenTableレストランが存在しないことを意味します。403 は、レストランは存在するものの、まだOpenTable内でプラットフォームの統合を接続していないことを意味します。アカウントごとに5分あたり10回までの試行にレート制限されています。

OpenTableレストランの追加

POST /appointments/opentable-restaurants

フィールド 必須 説明
restaurant_id はい 検証済みのレストランID。
restaurant_name はい 表示名(ラベル。AIがそのレストランを呼ぶ際の名前でもあります)。
website_url いいえ AIがゲストをレストランに引き継ぐ際に表示されるhttp(s) URL。
curl -X POST "https://api.dmchamp.com/v1/appointments/opentable-restaurants?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "1038007", "restaurant_name": "The Blue Door", "website_url": "https://thebluedoor.example" }'

レスポンス (201 Created): { "success": true, "data": { "restaurantId": "1038007" } }

保存済みOpenTableレストランの更新

PUT /appointments/opentable-restaurants/{restaurantId}

restaurant_nameis_activefalseで一時停止)、またはwebsite_url(空文字でクリア)のいずれかを送信します。省略されたフィールドは変更されません。

curl -X PUT "https://api.dmchamp.com/v1/appointments/opentable-restaurants/1038007" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'

レスポンス (200 OK): { "success": true, "data": { "restaurantId": "1038007" } }

OpenTableレストランを削除する

DELETE /appointments/opentable-restaurants/{restaurantId}

curl -X DELETE "https://api.dmchamp.com/v1/appointments/opentable-restaurants/1038007" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK): { "success": true, "data": { "restaurantId": "1038007" } }

現在アカウントに存在しない restaurantId を更新しようとすると、404 が返されます。

TheFork

TheForkのレストランには、プラットフォームのTheForkパートナー資格情報を通じてアクセスします。TheForkでは、その資格情報を持つユーザーは、TheForkアカウントでプラットフォームのパートナー機能が有効になっているレストランのみを参照できます。そのため、FormitableやOpenTableと同様に、1回の検証呼び出しで十分です。到達可能なレストランIDは、レストランが存在することと、そのレストランでパートナー機能が有効になっていることの両方を証明します。IDは、TheForkがTheFork Managerでレストランに割り当てるUUIDであり、文字列として送信されます。TheForkがプラットフォームをパートナーとして承認し、資格情報を発行するまで、検証呼び出しは 503 を返します。現在の状況については TheFork を参照してください。

TheForkレストランの検証

POST /appointments/thefork-restaurants/verify

フィールド 必須 説明
restaurant_id はい TheForkレストランID(9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60のようなUUID)。
curl -X POST "https://api.dmchamp.com/v1/appointments/thefork-restaurants/verify?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" }'

レスポンス (200 OK):

{
  "success": true,
  "data": {
    "verified": true,
    "restaurantDetails": {
      "restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60",
      "partySizes": [1, 2, 3, 4, 5, 6, 7, 8]
    }
  }
}

partySizes は、そのレストランが今後30日間にオンラインで受け付ける人数です。404 または 403 は、TheForkがそのIDを持つレストランを提供しなかったことを意味します(IDが間違っているか、そのレストランでプラットフォームのパートナー機能がまだ有効になっていないかのいずれかです)。400 は、IDがUUIDではないことを意味します。レート制限は、アカウントごとに5分間あたり10回までです。

TheForkレストランの追加

POST /appointments/thefork-restaurants

フィールド 必須 説明
restaurant_id はい 検証済みのレストランID(UUID)。
restaurant_name はい 表示名(ラベル。AIがレストランを呼ぶ際の名前でもあります)。
website_url いいえ AIがゲストをレストランに引き継ぐ際に表示されるhttp(s) URL。
curl -X POST "https://api.dmchamp.com/v1/appointments/thefork-restaurants?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "restaurant_id": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60", "restaurant_name": "The Blue Door", "website_url": "https://thebluedoor.example" }'

レスポンス (201 Created): { "success": true, "data": { "restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" } }

保存されたTheForkレストランの更新

PUT /appointments/thefork-restaurants/{restaurantId}

restaurant_nameis_activefalseで一時停止)、またはwebsite_url(空文字でクリア)のいずれかを送信します。省略されたフィールドは変更されません。

curl -X PUT "https://api.dmchamp.com/v1/appointments/thefork-restaurants/9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'

レスポンス (200 OK): { "success": true, "data": { "restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" } }

TheForkのレストランを削除する

DELETE /appointments/thefork-restaurants/{restaurantId}

curl -X DELETE "https://api.dmchamp.com/v1/appointments/thefork-restaurants/9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK): { "success": true, "data": { "restaurantId": "9f2a1c34-5b6d-4e7f-8a90-1b2c3d4e5f60" } }

アカウントに現在存在しない restaurantId を更新または削除しようとすると、404 が返されます。

Trafft

Trafftは場所ごとではなく、アカウント全体に対して1回接続します。会社のアドレスと、Trafft管理パネル(Features & Integrations → API & Connectors、Trafftのビジネスプランの一部)から取得したAPI認証情報が必要です。接続呼び出しは、何かを保存する前にTrafftに対してそれらの認証情報をチェックするため、アドレスや認証情報が間違っている場合、あるいはAPIアクセス権のないプランである場合は、顧客との会話中ではなくこの時点で失敗します。クライアントシークレットは暗号化されて保存され、どのエンドポイントからも返されることはありません。

3つの書き込み呼び出し(POSTPUTDELETE)はすべて、Integrationsの編集権限を必要とします。ステータスGETにはIntegrationsの表示権限が必要です。

Trafftを接続する

POST /appointments/trafft/connect

フィールド 必須 説明
subdomain はい 会社のアドレス。サインイン時のURLの.admin.trafft.comより前の部分(例: acme)。完全なアドレスも受け付けられ、同じ値に短縮されます。
client_id はい TrafftのAPI & Connectorsページから取得したクライアントID。
client_secret はい 同じページから取得したクライアントシークレット。暗号化して保存され、返されることはありません。
company_name いいえ 自身のリスト用のラベル。
curl -X POST "https://api.dmchamp.com/v1/appointments/trafft/connect?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subdomain": "acme",
    "client_id": "YOUR_TRAFFT_CLIENT_ID",
    "client_secret": "YOUR_TRAFFT_CLIENT_SECRET",
    "company_name": "Acme Salon"
  }'

レスポンス (200 OK):

{
  "success": true,
  "data": {
    "subdomain": "acme",
    "service_count": 12,
    "employee_count": 4,
    "location_count": 2
  }
}

カウント数はチェック中にTrafftから返されます。これは、認証情報が意図したアカウントを指していることを確認する最も迅速な方法です。

接続ステータスを取得する

GET /appointments/trafft

curl "https://api.dmchamp.com/v1/appointments/trafft" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK):

{
  "success": true,
  "data": {
    "connected": true,
    "subdomain": "acme",
    "hostname": "acme.admin.trafft.com",
    "client_id": "YOUR_TRAFFT_CLIENT_ID",
    "company_name": "Acme Salon",
    "is_active": true,
    "service_count": 12,
    "employee_count": 4,
    "location_count": 2
  }
}

connected: falseは、まだ何も設定されていないことを意味します。クライアントシークレットはこのレスポンスに含まれることはありません。

接続を更新する

PUT /appointments/trafft

フィールド 必須 説明
is_active いいえ false を設定して一時停止します。AIはTrafftへの予約を停止しますが、接続は維持されます。true で再開します。
company_name いいえ 新しいラベル。
curl -X PUT "https://api.dmchamp.com/v1/appointments/trafft" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'

レスポンス (200 OK): 上記の GET と同じ接続オブジェクトです。

Trafftの接続解除

DELETE /appointments/trafft

curl -X DELETE "https://api.dmchamp.com/v1/appointments/trafft" \
  -H "X-API-Key: YOUR_API_KEY"

レスポンス (200 OK): { "success": true }

接続を解除すると、保存された認証情報のみが削除されます。Trafftにすでにある予約には影響しません。

Zenchef/Formitable/OpenTable/TheForkの全エンドポイントにおけるエラー形式: このページの他の箇所とは異なり、ここでのエラーはステータスを2回(HTTPステータスとして1回、ボディ内の error_code として1回)伝えます。例: { "success": false, "error": "Restaurant not found", "error_code": 404 }。他のエラーと同様に処理してください。success を確認し、error を読み取ってメッセージを取得します。


Appointments API エラー

Appointment エンドポイントは、標準的なエラーエンベロープを返します。

{
  "success": false,
  "error": "Appointment not found"
}
ステータス Appointment エンドポイントで発生する場合
400 必須フィールドが欠落しているか無効です。例:不正な start_timestart_time より後ではない end_time、無効なフィルターの組み合わせ、更新するフィールドがない、またはすでにキャンセル済みの予約など。
404 予約、連絡先、またはイベントタイプが見つかりませんでした。
409 要求された時間枠はすでに埋まっています(予約の競合)。

すべてのエンドポイントが返す共通コード(401403(プランにAPIアクセスが含まれていない)、429(レート制限)、500)については、再試行のガイダンスと共にエラーとページネーションに記載されています。


独自のGoogle OAuthクライアント(カレンダー同意画面)を使用する

アカウントがGoogleカレンダーに接続される際、GoogleのサインインウィンドウにはOAuthクライアントのプロジェクト名が表示されます(デフォルトではプラットフォーム名)。代理店は、代理店アカウント上で独自のGoogle OAuth 2.0クライアントを登録できます。それ以降、そのアカウントおよびその配下のすべてのサブアカウントのカレンダー接続は、そのクライアントを通じて実行されるため、同意画面には代理店の名前とロゴが表示されます。それ以外の変更はありません。接続フロー、双方向同期、および上記のアポイントメントエンドポイントは、これまでと全く同じように動作します。

Googleカレンダーのみ。 メールチャネル用のGmailメールボックスOAuthには影響しません。

クライアントが事前に必要なもの

  1. Google Cloudプロジェクト内のWebアプリケーションタイプの OAuth 2.0クライアント。そのプロジェクトで Google Calendar API が有効になっている必要があります。
  2. すべての redirect_uris エントリ(以下のエンドポイントによって返される)が、クライアントの「承認済みのリダイレクトURI」に追加されていること。最初のエントリは、検証済みの api. ドメイン(お持ちの場合)です。Googleは、所有するドメイン上にリダイレクト先があるブランドのみを検証します。その後に、それまで使用されるフォールバックとしてプラットフォームの中立的なホストが続きます。
  3. 同意画面。ブランド名、承認済みドメイン配下のドメイン、および宣言された2つのカレンダー範囲(レスポンス内の scopes)が含まれている必要があります。アプリが公開されGoogleによって検証されるまで、ユーザーには未検証アプリの警告が表示され、クライアントは100ユーザーまでに制限されます。

クライアントを保存する

PUT /account-config/google-oauth-client

フィールド 必須 説明
client_id はい .apps.googleusercontent.com で終わるOAuth 2.0クライアントID。
client_secret はい クライアントシークレット。保存前にGoogleに対して検証され、その後暗号化されます。どのエンドポイントからも返されることはありません。
curl -X PUT "https://api.dmchamp.com/v1/account-config/google-oauth-client?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "123456789012-abcdefghijklmnop.apps.googleusercontent.com",
    "client_secret": "GOCSPX-your-client-secret"
  }'

レスポンス

{
  "success": true,
  "configured": true,
  "client_id": "123456789012-abcdefghijklmnop.apps.googleusercontent.com",
  "redirect_uris": [
    "https://api.youragency.com/v1/auth-google-callback",
    "https://api.dmchamp.com/v1/auth-google-callback"
  ],
  "scopes": [
    "https://www.googleapis.com/auth/calendar.events",
    "https://www.googleapis.com/auth/calendar.readonly"
  ],
  "setup": ["…"]
}

誤ったシークレットや不明なクライアントIDは 400 で拒否され、error にGoogle独自の理由が示されます。また、何も保存されません。

読み取りまたは削除

GET /account-config/google-oauth-client はいつでも同じ概要を返します。configured: false に加え、保存される前の redirect_urisscopes が含まれるため、先に Google 側の設定を行うことができます。DELETE /account-config/google-oauth-client はクライアントを削除します。新しい接続はプラットフォームクライアントに戻り、削除されたクライアント経由で接続されていたカレンダーは再接続が必要になります。これは、接続を発行したクライアントのみがその接続を更新できるためです。

チームメンバーには、GET には Integrations: viewPUT / DELETE には Integrations: edit の権限が必要です。


次のステップ

  • 連絡先 — 予約対象の連絡先を作成および検索します。
  • メッセージと会話 — 連絡先に確認やリマインダーを送信します。
  • Webhook — 予約が変更されたときに通知を受け取ります。