Developer Hub
此為系統自動產生的翻譯

API 設定

本節將介紹成功與我們的 API 整合所需的基本步驟。無論您是想透過 Webhooks 接收推播事件,還是從我們的端點擷取資料,我們都能滿足您的需求。

  • 推播 API: 推播事件非常適合 TAAP 以及白標旅遊平台合作夥伴,可將 real-time 的更新直接傳送至您的系統。瞭解如何設定訂閱、管理驗證以及處理重試。
  • Pull API: 此服務專為白標旅遊平台合作夥伴設計,讓您能在需要時隨時請求資料。我們將向您說明如何設定「token-based」驗證機制,以確保存取安全。

請遵循以下指引,以確保整合過程順利進行,並確保資料傳輸的安全性。

Push-based 送貨

如果您是 TAAP,或是對行程資料感興趣的白標旅遊平台合作夥伴,這則資訊可能與您相關。推播事件是透過 Webhook 傳送的,並會以HTTP POST 訊息的形式發送至您提供的 URL。

若要開始接收事件,您需要訂閱某種事件類型,並將 Expedia 驗證為發送者。

訂閱與活動

我們的訂閱 API 可讓您建立並管理您希望透過我們的 push-based 傳送服務接收的事件。目前您可以建立並管理「行程更新」事件的訂閱,我們將在相關功能推出後陸續新增更多選項。

您需要一個 API 客戶端 ID 和密鑰,您的商業聯絡人可提供這些資訊。

存取訂閱 API

您將在所有 API 請求中包含一個專屬於您企業的存取憑證。請使用您的 API 憑證,透過 HTTP 基本驗證機制來請求此憑證。

  1. 請在令牌端點中新增一個「Authorization」標頭,並將您的 API 客戶端 ID 和密鑰以 Base64 編碼的字串形式填入其中https://analytics.ean.com/*/v1/oauth/token。請根據您的合作夥伴關係,將網址中的* 替換為templatetaap
  2. 該憑證端點將回傳一個存取憑證,您可將其用於後續的 API 請求。
  3. 請在日後的 API 端點請求中包含存取憑證的值。

>> 進一步了解存取憑證

初始授權標頭範例

Authorization: Basic base64.b64encode({client-id}:{client-secret})

代幣請求範例

securitySchemes:
  oauth:
    type: oauth2
    flows:
      clientCredentials:
        tokenUrl: https://analytics.ean.com/taap/v1/oauth/token

經過驗證的授權標頭範例

Authorization: Bearer {access-token}

管理您的訂閱

在透過訂閱 API 完成驗證後,您即可管理您的訂閱,包括列出現有的訂閱、建立新的訂閱,以及刪除不再適用的訂閱。

建立訂閱

建立訂閱時,您需要指定:

  • 您希望接收事件的端點 URL。
  • 您要訂閱的事件類型,包括您的合作夥伴關係標示:taap.itinerary.changetemplate.itinerary.change

注意:雖然您可以建立多個訂閱,但重複的訂閱會導致事件重複傳送。為避免這種情況,請在建立新訂閱之前,先列出您現有的訂閱。

建立訂閱時,您將收到一組唯一的密鑰,用以驗證事件傳送中包含的 HMAC (hash-based 訊息認證碼)。

Information

重要事項

收到密鑰後,請務必將其儲存於安全的檔案中——基於安全考量,該密鑰將不會再次顯示。

若要列出或刪除訂閱,請分別使用HTTP GET /subscriptionsHTTP DELETE /subscriptions/{subscription_id} 端點。您必須使用有效的憑證。

>> 進一步了解訂閱方案

驗證 Expedia 為寄件者

我們將向您提供的端點發送推播事件,每個事件的授權標頭中都會包含一個 hash-based 訊息認證碼 (HMAC) 簽名。您應驗證此簽名,以確保透過我們在您建立訂閱時所提供的共享密鑰,實現安全且值得信賴的資料傳輸。

授權標頭範例

"authorization": "MAC ts='1731524372777',nonce='f88e57ed-aaf5-4edd-8e58-9105817fb4cb',bodyhash='8YLHy71r5dx3PQjdcOkRuVYXaakjhbJSROEnlreQEIA=',mac='bDxvx41INtDxtkbZwTmAMADZGiFl6/xyXC1lE5ixPuY='"

請在接收推播事件的端點中加入以下邏輯,以驗證 HMAC 簽名。這將確保您收到的事件均來自 Expedia,且在傳輸過程中未遭篡改。

註: 此範例展示如何在 Java 中實作此驗證邏輯。您可以根據自己偏好的程式設計語言調整這套邏輯,但核心步驟將保持不變。

步驟 1:解析授權標頭

透過將字串解析為其基本組成部分,從授權標頭中提取所需資訊。

程式碼範例

/**
 * Parse the signature string into components
 * @param signature The signature string in format "MAC ts='...', nonce='...', bodyhash='...', mac='...'"
 * @return Map of signature components
 */
private Map<String, String> parseSignature(String signature) {
    // Pattern for key='value' or key="value"
    Pattern pattern = Pattern.compile("([a-zA-Z]+)=['\"]([^'\"]*)['\"]");
    Matcher matcher = pattern.matcher(signature);

    Map<String, String> components = new HashMap<>();
    while (matcher.find()) {
        components.put(matcher.group(1), matcher.group(2));
    }
    return components;
}

步驟 2:驗證所需元件

請確認所需元件ts(時間戳記)、noncebodyhash 以及mac 是否存在且格式正確。

程式碼範例

private Boolean validateSignatureComponents(Map<String, String> components) {
    if (components.isEmpty()) {
        return false;
    }

    return components.containsKey("ts") &&
            components.containsKey("nonce") &&
            components.containsKey("bodyhash") &&
            components.containsKey("mac");
}

步驟 3:產生並驗證正文雜湊值

使用 HMAC SHA-256 及sharedSecretKey 生成請求主體的雜湊值,並確認其與請求主體的雜湊值相符,以確保資料完整性。

程式碼範例

/**
 * Compute body hash (HMAC-SHA256 of the request body)
 * @param body The raw request body
 * @return Base64 encoded body hash
 */
private String computeBodyHash(String body) {
    try {
        Mac mac = Mac.getInstance(HMAC_SHA256);
        SecretKeySpec secretKeySpec = new SecretKeySpec(
                sharedSecretKey.getBytes(StandardCharsets.UTF_8),
                HMAC_SHA256);
        mac.init(secretKeySpec);
        byte[] hmacBytes = mac.doFinal(body.getBytes(StandardCharsets.UTF_8));
        return bytesToBase64(hmacBytes);
    } catch (Exception e) {
        throw new RuntimeException("Failed to compute body hash", e);
    }
}

private Boolean validateBodyHash(String requestBody, String bodyHashFromHeader) {
    String computedBodyHash = computeBodyHash(requestBody != null ? requestBody : "");
    return computedBodyHash.equals(components.get('bodyhash'));
}

步驟 4:產生並驗證 HMAC 簽名

產生包含時間戳記、隨機數、HTTP 方法、請求路徑、主機網域、連接埠及生成的內容雜湊值的 HMAC 簽名,並與標頭中收到的值進行比對以驗證其真實性。

程式碼範例

/**
 * Generate HMAC signature using the provided components
 * @param components Parsed signature components
 * @param computedBodyHash Computed body hash
 * @param method HTTP method (e.g., "POST", "GET")
 * @param path Request path (e.g., "/api/webhooks/events")
 * @param host Host name (e.g., "api.example.com")
 * @param port Port number
 * @return Base64 encoded HMAC signature
 */
private String generateHmacSignature(Map<String, String> components, String computedBodyHash,
                                     String method, String path, String host, int port) {
    try {
        // Normalize port (use 443 for standard HTTPS ports)
        String portString = (port == 80 || port == 443) ? DEFAULT_PORT : String.valueOf(port);

        // Build signature string with newline-delimited components
        String signatureString = String.format("%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
                components.get("ts"),
                components.get("nonce"),
                method.toUpperCase(),
                path,
                host,
                portString,
                computedBodyHash);

        return calculateHMAC(signatureString);
    } catch (Exception e) {
        throw new RuntimeException("Failed to generate HMAC signature", e);
    }
}

/**
 * Calculate HMAC-SHA256
 * @param data Data to hash
 * @return Base64 encoded HMAC
 */
private String calculateHMAC(String data) {
    try {
        Mac mac = Mac.getInstance(HMAC_SHA256);
        SecretKeySpec secretKeySpec = new SecretKeySpec(
                sharedSecretKey.getBytes(StandardCharsets.UTF_8),
                HMAC_SHA256);
        mac.init(secretKeySpec);
        byte[] hmacBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return bytesToBase64(hmacBytes);
    } catch (Exception e) {
        throw new RuntimeException("Failed to calculate HMAC", e);
    }
}

private Boolean validateHmacSignature(Map<String, String> components, String computedBodyHash,
                                      String method, String path, String host, int port) {
    String generatedHmacSignature = generateHmacSignature(components, computedBodyHash, method, path, host, port);
    return generatedHmacSignature.equals(components.get("mac"));
}

事件失敗時的重試

若某個事件執行失敗,系統將在 7 天內採用指數退避模式進行重試:首先每 5 分鐘嘗試一次,接著每 60 分鐘嘗試一次,此後則每 12 小時嘗試一次。若發生以下任何情況導致失敗,我們將重新嘗試:

  • 非 200 的 HTTP 狀態碼
  • 暫停
  • 您的端點發生了一個例外狀況

訂閱 API 詳情

如需有關訂閱 API 的更多詳細資訊,請下載 OpenAPI 規格文件。




Pull-based 送貨

如果您擁有一個白標旅遊平台網站,您可以根據所使用的 API,為行程和忠誠度積分資料啟用 pull-based 傳輸功能。

若要存取「忠誠度積分」及「行程」端點,您需要一個 API 客戶端 ID 和密鑰,可向您的商業聯絡人索取。您將在所有 API 請求中包含一個專屬於您企業的存取憑證。請使用您的 API 憑證,透過 HTTP 基本驗證機制來請求此憑證。

  1. 請在令牌端點https://analytics.ean.com/template/v1/oauth/token 中,新增一個包含您的 API 客戶端 ID 和密鑰的 Base64 編碼字串的 Authorization 標頭。
  2. 該憑證端點將回傳一個存取憑證,您可將其用於後續的 API 請求。如需更多詳細資訊,請參閱 OpenAPI 規格。
  3. 請在日後的 API 端點請求中包含存取憑證的值。

初始授權標頭範例

Authorization: Basic base64.b64encode({client-id}:{client-secret})

代幣請求範例

securitySchemes:
    oauth:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://analytics.ean.com/template/v1/oauth/token

經過驗證的授權標頭範例

Authorization: Bearer {token}

收到您的存取憑證後,即可開始對「Loyalty Earn」或「Itineraries」的任何端點發出請求。

Information

重要事項

為了確保我們能為所有合作夥伴提供穩定且易於維護的服務,我們對所有 API 呼叫均採用流量限制。我們的系統會監控異常的 API 流量,並自動採取保護措施。在您對 API 呼叫進行變更,或針對 API 存取進行效能測試之前,請先與您的 Expedia 業務聯絡人確認相關計畫。

在請求此服務時,您需要指定您的 API 版本。請使用我們可下載的 OpenAPI 規格檔案頂端所列的「servers.url」值。它將始終與您正在測試的 API 服務的版本號相符。

網址應遵循以下結構:

https://analytics.ean.com/[product]/[API version]/[path]

您可以透過替換路徑在不同端點之間切換,但請務必按照 OpenAPI 規格中規定的方式,保留協定、網域標示、產品及 API 版本號。

端點範例

https://analytics.ean.com/template/v1/loyalty/earn/last_update
https://analytics.ean.com/template/v1/itineraries

若要了解資料範圍及 API 設定,請參閱 API 傳輸的資料結構:
>> 進一步了解「行程 API」的提供方式
>> 了解「Loyalty Earn API」的交付方式

這個頁面對您有幫助嗎?
我們能如何改善內容?
感謝您協助我們進行改善!