本文へスキップ
トップ / クラコールSIP trunk / AI・CPaaS BYOC / OpenAI との接続ガイド

OpenAI との接続ガイド

OpenAI 側(外部サービス)の設定を含む、クラコールSIP trunkとの接続手順です。

公開日 更新日

  • このガイドでは、クラコールSIP trunkとの接続に必要なOpenAI 側(お客様が契約された外部サービス)の設定手順もご案内します。
  • 各社の画面や仕様は変わることがあります。最新の内容は、各社の公式ドキュメントをご確認ください。

お客様がご自身で契約された OpenAI の Realtime API(SIP 接続)に、クラコールSIP trunkをつなぐ手順です。OpenAI の Realtime API(SIP)は、着信を受ける仕組みです。対応しているのは OpenAI の Realtime API(SIP による着信)です。Live API(GPT-Live)には対応していません。

OpenAI との接続には TLS・SRTP が必要なため、暗号化の有料オプションのお申し込みが必要です。通信の暗号化(TLS・SRTP)は有料オプション(料金はお問い合わせください)です。標準ではご利用いただけません。

通話の流れ

通話は必ずクラコールの SBC(東京・大阪)を通ります。OpenAI の Realtime API の SIP は着信を受ける仕組みのため、通話の向きは着信の1つです。

着信日本の電話から、OpenAI へ

  1. 電話回線日本
  2. クラコールの SBC東京・大阪(TLS・SRTP)
  3. sip.api.openai.comOpenAI の SIP の宛先(手順4)
  4. Project の Webhookrealtime.call.incoming(手順2)
  5. お客様のサーバーaccept で受け入れる(手順3)

クラコールの SBC は、着信を OpenAI の SIP の宛先(sip:[email protected];transport=tls)へ送ります。OpenAI は Webhook でお客様のサーバーに知らせ、お客様のサーバーが accept を送ると、着信がつながります。OpenAI の Realtime API の SIP は着信のみです(参考:Live API の発信は、Opus の音声と SIP のダイジェスト認証を使います。Live API(GPT-Live)には、クラコールは対応していません)。

どの接続先にも共通のルール(認証・電話番号の形式など)は、接続の基本ルールをご覧ください。

つなぐ手順

「0 はじめに用意するもの」をそろえてから、次の5つの手順(1〜5)で進めます。各手順には、作業者(クラコール/お客様)を記載しています。

  1. 0
    お客様

    はじめに用意するもの

    • クラコールSIP trunk(BYOC 接続)のご契約
    • 暗号化の有料オプションのお申し込み
    • OpenAI のアカウントとプロジェクト(お客様がご自身で契約されたもの)と、API キー
    • インターネットから OpenAI の Webhook を受けられるお客様のサーバーと、Python 3.9 以上
    • ご利用になる電話番号(+81 から始まる E.164 形式)
  2. 1
    クラコール ⇄ お客様

    お申し込みと、接続に使う情報のやりとり

    お申し込み後に、クラコールから接続に使う情報をお渡しします。お客様からは、OpenAI 側の情報をお知らせください。

    クラコールからお渡しする情報

    • お客様専用のドメイン(例:xyz.customer.clocall.jp。実際のドメイン名はお申し込み後にお知らせします)
    • ご利用いただく電話番号(+81 から始まる E.164 形式)
    • 使える方式:UDP・TCP(暗号化の有料オプションをお申し込みの場合は TLS・SRTP)

    お客様からお知らせいただく情報

    • OpenAI の SIP の宛先(SIP URI。sip:[email protected];transport=tls。手順4)
    • 使う方式とポート番号(OpenAI では TLS・5061)
    • 暗号化(TLS・SRTP)の有料オプション(OpenAI では必須)
    • ご利用になる電話番号(+81 から始まる E.164 形式)

    お問い合わせの本文に「BYOC 接続」とお書きのうえ、お送りください。BYOC では、着信・発信とも、INVITE の宛先(Request-URI)・To・From の電話番号を +81 から始まる E.164 形式にしてください(例:03-1234-5678 → +81312345678)。

    • お客様専用のドメインには複数の IP アドレス(東京・大阪)が登録されています。返ってくるアドレスはすべて使えるようにしてください。
    • SIP の REFER(通話の転送)には、クラコールは対応していません(接続の基本ルール)。OpenAI の refer(SIP の REFER による転送)は、クラコール経由では使えません。
  3. 2
    お客様(OpenAI)

    Webhook を登録する

    OpenAI は、着信があると realtime.call.incoming というイベントを Webhook で知らせます。OpenAI の settings > Project > Webhooks(platform.openai.com)を開き、Create(作成)のボタンで Webhook を登録します。入れるのは、次の3つです。

    • 名前(ご自身が見分けるためのものです)
    • お客様のサーバーの公開 URL(手順3で動かすサーバーのアドレスです)
    • 受け取るイベントの種類:realtime.call.incoming

    Webhook を作ると、signing secret(署名用のシークレット)が表示されます。この値はあとからは見られないので、必ず保存してください。手順3で、この値を環境変数 OPENAI_WEBHOOK_SECRET に入れます。なくしたとき、うっかり公開してしまったときは、rotating the signing secret(シークレットの再発行)で新しいものを作れます。

    • OpenAI から届く知らせは、本文の type が realtime.call.incoming のイベントで、通話の ID は data の中の call_id です。ヘッダーには webhook-id・webhook-timestamp・webhook-signature が付きます。
    • 知らせを受けたお客様のサーバーは、すぐに 2xx(成功)の応答を返します。2xx でないときや応答が遅いときは、OpenAI は同じ知らせを再送します(最長 72 時間)。
    • 同じ知らせが重複して届くことがあります。webhook-id を重複を見分ける印(idempotency key)に使えます。
    参考(公式):OpenAI 公式ドキュメント:Telephony and SIP(英語)
    このページの Overview の項に、realtime.call.incoming の本文の例と、settings > Project > Webhooks の説明があります。
    OpenAI 公式ドキュメント:Webhooks(英語)
    このページの Creating webhook endpoints の項に、Create・名前・公開 URL・イベントの種類・signing secret の説明があります。同じページの Handling webhook requests on a server の項に、2xx の応答と再送・webhook-id の説明があります。
  4. 3
    お客様(サーバー)

    着信を受け入れるサーバーを動かす(webhook.py)

    次の webhook.py は、Webhook を受けて署名を確かめ、realtime.call.incoming なら accept で着信を受け入れます。Python の標準ライブラリだけで動くので、追加のインストールは要りません(Python 3.9 以上)。

    webhook.py

    import base64
    import hashlib
    import hmac
    import json
    import os
    import time
    import urllib.error
    import urllib.request
    from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
    
    OPENAI_BASE = os.environ.get("OPENAI_BASE", "https://api.openai.com")
    OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
    WEBHOOK_SECRET = os.environ["OPENAI_WEBHOOK_SECRET"]
    PORT = int(os.environ.get("PORT", "8000"))
    TOLERANCE_SECONDS = 300
    
    # シークレットが whsec_ で始まる場合は、その後ろを base64 として復号します(起動時に1回だけ)
    if WEBHOOK_SECRET.startswith("whsec_"):
        try:
            KEY = base64.b64decode(WEBHOOK_SECRET[6:], validate=True)
        except ValueError:
            raise SystemExit("OPENAI_WEBHOOK_SECRET が正しくありません。OpenAI の画面に表示された signing secret をそのまま設定してください。")
    else:
        KEY = WEBHOOK_SECRET.encode()
    
    # 着信を受け入れるときに送る内容(値は OpenAI 公式の例です。お客様の用途に合わせて変えてください)
    ACCEPT_BODY = {
        "type": "realtime",
        "model": "gpt-realtime-2.1",
        "instructions": "You are Alex, a friendly concierge for Example Corp.",
    }
    
    
    def signature_is_valid(headers, body):
        # Standard Webhooks の署名検証:msg_id.timestamp.payload を HMAC-SHA256 で署名し、base64 にしたものを比べます
        msg_id = headers.get("webhook-id", "")
        timestamp = headers.get("webhook-timestamp", "")
        signatures = headers.get("webhook-signature", "")
        try:
            if abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS:
                return False
        except ValueError:
            return False
        signed = msg_id.encode() + b"." + timestamp.encode() + b"." + body
        expected = base64.b64encode(hmac.new(KEY, signed, hashlib.sha256).digest()).decode()
        for item in signatures.split():
            version, _, value = item.partition(",")
            if version == "v1" and hmac.compare_digest(value.encode(), expected.encode()):
                return True
        return False
    
    
    def accept_call(call_id):
        accept_endpoint = f"{OPENAI_BASE}/v1/realtime/calls/{call_id}/accept"
        request = urllib.request.Request(
            accept_endpoint,
            data=json.dumps(ACCEPT_BODY).encode(),
            headers={
                "Authorization": f"Bearer {OPENAI_API_KEY}",
                "Content-Type": "application/json",
            },
            method="POST",
        )
        with urllib.request.urlopen(request, timeout=10) as response:
            return response.status
    
    
    class Handler(BaseHTTPRequestHandler):
        def do_POST(self):
            body = self.rfile.read(int(self.headers.get("Content-Length", "0")))
            if not signature_is_valid(self.headers, body):
                self.send_response(400)
                self.end_headers()
                return
            event = json.loads(body)
            if event.get("type") == "realtime.call.incoming":
                call_id = event["data"]["call_id"]
                try:
                    accept_call(call_id)
                    print("accepted", call_id)
                except urllib.error.HTTPError as error:
                    if error.code == 429 or error.code >= 500:
                        # 一時的なエラー:502 を返し、OpenAI に再送してもらいます
                        print("accept failed", call_id, error.code)
                        self.send_response(502)
                        self.end_headers()
                        return
                    # それ以外で断られた場合(恒久的):ログに残し、Webhook には 200 を返します(再送を避けるため)
                    print("accept refused", call_id, error.code)
                except OSError as error:
                    # ネットワークの失敗・タイムアウト:502 を返し、OpenAI に再送してもらいます
                    print("accept failed", call_id, error)
                    self.send_response(502)
                    self.end_headers()
                    return
            self.send_response(200)
            self.end_headers()
    
    
    ThreadingHTTPServer(("0.0.0.0", PORT), Handler).serve_forever()

    ターミナル

    export OPENAI_API_KEY="(OpenAI の API キー)"
    export OPENAI_WEBHOOK_SECRET="(Webhook の署名用のシークレット)"
    python3 webhook.py
    • OPENAI_API_KEY:OpenAI の API キーです。accept の呼び出しの Authorization: Bearer に使います。コードには書かず、環境変数で渡します。
    • OPENAI_WEBHOOK_SECRET:手順2で保存した signing secret です。コードは、値が whsec_ で始まる場合は、その後ろを base64 として復号して鍵にし、そうでない場合は、値をそのまま鍵にします。
    • 署名の検証は、Standard Webhooks の仕様のとおり、webhook-id・webhook-timestamp・本文を . でつないだものを HMAC-SHA256 で署名し、webhook-signature の v1, のあとの値と比べます。時刻が許容差(例では5分)を超えるものと、署名が合わないものは、400 で断ります。
    • accept の本文の type は realtime です。model と instructions の値は、OpenAI の公式の例のものです。お客様の用途に合わせて変えてください。
    • accept が成功すると、OpenAI は 200 OK を返し、通話の準備が始まります。お客様のサーバーも 200 を返します。
    • accept が一時的なエラー(429・5xx)や通信エラーの場合は 502 を返して再送してもらい、それ以外で断られた場合は 200 を返します。
    • 例の OPENAI_BASE は、試験用に宛先を切り替えるためのもので、通常は設定しません(標準は https://api.openai.com です)。
    参考(公式):OpenAI 公式ドキュメント:Telephony and SIP(英語)
    このページの Accept the call の項に、accept の呼び出し(Authorization: Bearer・本文の type・model・instructions)の例があります。
    OpenAI 公式ドキュメント:Webhooks(英語)
    このページの Verifying webhook signatures の項に、OPENAI_WEBHOOK_SECRET と、署名を自分で検証する場合は Standard Webhooks の仕様に従う、という説明があります。
    Standard Webhooks の仕様(英語)
    このページの Verifying webhook authenticity の項(見出しは英語の仕様のもの)に、署名の対象・HMAC-SHA256・whsec_ の説明があります。
  5. 4
    お客様 → クラコール

    SIP の宛先をクラコールにお知らせする

    クラコールの SBC が着信を送る先は、OpenAI の SIP の宛先(SIP URI)です。次の形で、$PROJECT_ID をお客様のプロジェクト ID に置き換えたものをクラコールへお知らせください。

    OpenAI の SIP の宛先(クラコールの SBC が着信を送る先)

    sip:[email protected];transport=tls
    • $PROJECT_ID:OpenAI のプロジェクト ID(proj_ の接頭辞が付いた文字列)に置き換えます。settings > Project > General で確認できます。
    • ポートは TCP/TLS の 5061 です。TLS を使うため、暗号化の有料オプションが必要です。
    • 着信の電話番号は、+81 から始まる E.164 形式で届きます。

    クラコールとの接続では、Realtime API の SIP の音声の形式は G.711 μ-law(PCMU)です。

    参考(公式):OpenAI 公式ドキュメント:Telephony and SIP(英語)
    このページの Overview の項に、SIP の宛先(sip:[email protected];transport=tls)と $PROJECT_ID の説明があります。SIP signaling and media IP ranges の項に、ポート 5061 の説明があります。
    お知らせいただいた SIP の宛先を、クラコール側で着信の宛先に設定します。設定が終わったら、手順5で確認します。
  6. 5
    クラコール ⇄ お客様

    つながることを確認する

    • 着信:クラコールの電話番号へ、携帯電話などから電話をかけ、お客様のサーバー(webhook.py)に、OpenAI から realtime.call.incoming が届くことを確認します(例のコードは、受け入れると accepted と通話の ID を表示します)。
    • 着信を受け入れたあと、相手の声が聞こえることを確認します。
    うまくつながらないときは、うまくつながらないときをご覧ください。

通信の暗号化(有料オプション)

通信の暗号化(TLS・SRTP)は有料オプション(料金はお問い合わせください)です。標準ではご利用いただけません。OpenAI との接続には TLS・SRTP が必要なため、お申し込みが必要です。お申し込みの場合の対応は次のとおりです。

  • TLS:TLS 1.3・1.2 に対応しています。
  • SRTP:RFC 3711 の RTP/SAVP です。RFC 5124 の RTP/SAVPF には対応していません。
  • SRTP の暗号方式:AES_CM_128_HMAC_SHA1_80
  • OpenAI の SIP の宛先は、末尾が ;transport=tls の形で、ポートは TCP/TLS の 5061 です。

うまくつながらないとき

  • 着信が届かない:SIP の宛先のプロジェクト ID が正しいか、暗号化の有料オプションをお申し込みか、確認してください。
  • Webhook が届かない:settings > Project > Webhooks に登録したか、realtime.call.incoming を受け取る設定か、送り先のサーバーがインターネットから届くか、確認してください。
  • Webhook は届くが 400 を返す:OPENAI_WEBHOOK_SECRET が正しいか、サーバーの時刻がずれていないか、確認してください。
  • 着信は届くが、つながらない:realtime.call.incoming を受け取ったあと、accept で着信を受け入れているか、OPENAI_API_KEY が正しいか、確認してください。
  • 上を確認してもつながらない場合は、お問い合わせの本文に「BYOC 接続」と書き、試した時刻をお知らせください。

OpenAI のマニュアル(英語)との用語対応

OpenAI のマニュアルで探すときの用語は、次のとおりです。

このページOpenAI のマニュアル
対応している API(着信)Realtime API(対応していないのは Live API(GPT-Live))
OpenAI の SIP の宛先(SIP URI)sip:[email protected];transport=tls
プロジェクト ID$PROJECT_ID(settings > Project > General で確認)
Webhook を登録する場所settings > Project > Webhooks(Create で登録)
着信を知らせるイベントrealtime.call.incoming
通話の IDcall_id(イベントの data の中)
着信を受け入れる APIaccept(POST /v1/realtime/calls/$CALL_ID/accept)
署名用のシークレットsigning secret(OPENAI_WEBHOOK_SECRET)
Webhook の署名の検証webhook-signature(Standard Webhooks の方式)
通話の転送refer

  • 記載の社名・サービス名は各社の商標または登録商標です。クラコールは各社と提携・協業しておらず、各社から推奨・承認・認定を受けているものではありません。
  • クラコールはAI機能を提供するものではありません。OpenAI の利用条件・料金・動作は同社の定めによります。
  • 最終確認日:2026.10.23(各社の公式ドキュメントを確認した日)
  • 掲載内容は最終確認日時点の公開情報に基づくもので、各社の仕様・条件の変更により変わることがあります。動作・互換性・継続的な利用を保証するものではありません。

まずはお気軽にご相談ください

導入のご相談・資料のご請求は、お気軽にお問い合わせください。

資料請求・お問い合わせ
電話でのご相談:03-6161-0011(平日 9:00〜18:00)
株式会社三通テレコムサービス
届出電気通信事業者
届出番号:A-25-13494
適格請求書発行事業者登録番号:T7013301034907
プライバシーマーク
JQA ISO 9001 登録マーク JQA-QMA14179 UKAS 認定シンボル
ETOC JUSA Smart SME Supporter

登録番号:プライバシーマーク 21001425(05)/ETOC 優良電話事業者 0002-U

株式会社三通 ISO 9001 認証取得(登録事業所:株式会社三通テレコムサービス/国内・国際通信サービスの提供・販売)

この登録マークは製品またはサービスを保証するものではありません。