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

API 設定

本節將說明成功整合我們 API 的關鍵步驟。無論您是想透過 Webhooks 接收推送事件,還是從我們的端點拉取資料,我們都能滿足您的需求。

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

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

Push-based 送貨

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

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

訂閱與活動

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

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

存取訂閱 API

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

  1. 請在 token 端點中新增一個 Authorization 標頭,並將您的 API 客戶端 ID 和密鑰以 Base64 編碼的字串形式加入其中https://analytics.ean.com/*/v1/oauth/token。請根據您的合作夥伴關係,將網址中的* 替換為templatetaap
  2. 該憑證端點將傳回一個存取憑證,您可將其用於後續的 API 請求。如需更多詳細資訊,請參閱訂閱 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} 端點。您必須使用有效的憑證。

如需更多詳細資訊,請參閱訂閱 API 說明

驗證 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}

收到憑證後,您即可開始對「累積點數」或「行程」任一端點發出請求。

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 交付

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