Lo que necesitas saber para poner en marcha tu implementación
Nuestros equipos de integración y gestión de lanzamientos trabajarán en estrecha colaboración con tus equipos durante la implementación de la API de anuncios patrocinados de alojamiento. Si colaboramos estrechamente, se calcula que la implementación tardará unas 8 semanas, incluidas 2 semanas para las pruebas de « end-to-end ».
Con cada búsqueda válida, nos enviarás una lista preseleccionada de identificadores de propiedades de Expedia Group. Aprovecha esta oportunidad para decidir qué propiedades podrían aparecer en los anuncios patrocinados de tu web.
A grandes rasgos, esta es la secuencia de lo que ocurre por parte del viajero y lo que hará tu sistema:
Paso 1: Envía una solicitud a la API de anuncios patrocinados de alojamientos utilizando los datos del contexto de búsqueda
Nota: Esta llamada no tiene nada que ver con las llamadas que puedas estar haciendo para comparar precios, y se puede realizar antes, durante o después de haber consultado las tarifas y la disponibilidad.
Agrupa y ordena los resultados de disponibilidad como lo harías normalmente.
Asegúrate de que el ID del cliente se mantenga en todas las solicitudes.
Nota sobre el ID de cliente: Los anunciantes que invierten en clics esperan obtener información clara sobre el valor que generan sus inversiones. En el caso de los anuncios patrocinados de alojamiento, este valor se mide en función de las reservas que se generan a raíz de una impresión o un clic en un anuncio. Pero no podemos ofrecer datos completos de atribución de reservas cuando el inventario de alojamientos procede de varios canales, así que necesitamos un identificador de cliente fijo en todas las solicitudes de anuncios. Ese identificador debe conservarse durante todo el proceso de seguimiento de los anuncios e incluirse en la información de atribución de las reservas para que podamos vincular con precisión las interacciones con los anuncios y las reservas resultantes.
Paso 2: Buscal alojamiento correspondiente en los resultados de disponibilidad
Para conseguir la máxima cobertura publicitaria y una monetización óptima, es fundamental que asigne tus ID de propiedad a los ID de propiedad de Expedia, incluso en el caso de aquellas propiedades para las que no utilices Expedia. Es poco probable que haya una correspondencia completa entre los dos conjuntos de propiedades, ya que no todas las propiedades forman parte del programa de anuncios patrocinados.
Compara los ID de propiedad de « Expedia » que aparecen en la respuesta de entrega del anuncio con tus resultados de disponibilidad.
Combina el contenido del anuncio inmobiliario con el del anuncio patrocinado. Los resultados de la API de anuncios patrocinados de Lodging solo muestran el ID del alojamiento y el contenido del anuncio; nada más.
Paso 3: Intercala los anuncios patrocinados entre los resultados de disponibilidad (opcional)
Los anuncios patrocinados pueden aparecer en la parte superior de los resultados de búsqueda o repartidos entre los resultados orgánicos. No hay ningún requisito sobre dónde se coloquen los anuncios, siempre y cuando se mantenga el orden.
Elige cómo quieres que se muestren los anuncios patrocinados.
Asegúrate de que no cambie el orden en el que aparecen los anuncios patrocinados.
Aunque tanto el «rango del anuncio» como la «posición del anuncio» tienen que ver con la ubicación de un anuncio, no son lo mismo.
El «Ad Rank» determina la posición del anuncio tras la subasta. El anuncio ganador recibe el puesto n.º 1, el siguiente el n.º 2, y así sucesivamente, hasta el puesto n.º 25 (el número máximo de anuncios mostrados).
Por otro lado, la «posición del anuncio» () se refiere a la ubicación real del anuncio en la página, que suele numerarse desde el 1 (arriba) hacia abajo. En los resultados paginados, las posiciones se mantienen de forma secuencial en todas las páginas. Por ejemplo, si muestras 10 anuncios inmobiliarios por página y colocas anuncios en las posiciones 1 y 10 de cada página, al primer anuncio de la página 2 se le debería asignar la posición 11. Es importante incluir la posición del anuncio en todas las balizas de seguimiento para garantizar la precisión de las mediciones y los informes.
|
Definición de OpenAPI Ads
openapi: 3.0.1
info:
title: Ad Delivery API
version: v1
description: Retrieves ads.
contact:
name: 'Media Solutions'
email: 'MediaSolutionsAPI1@expedia.com'
url: 'https://test.developers.expediagroup.com/docs/'
tags:
- name: Ad Delivery
description: API to retrieve ads
servers:
- url: https://test.ean.com/v1
- url: https://api.ean.com/v1
paths:
/ads:
post:
tags:
- Ad Delivery
description: Returns relevant ads.
operationId: getAds
parameters:
- name: Accept
in: header
description: Specifies the response format that the client would like to receive back. This must be application/json
required: true
schema:
type: string
example: 'application/json'
- name: Authorization
in: header
description: EAN token, format is <pre>EAN APIKey=<APIKey>,Signature=<Encoded Signature>,timestamp=<timestamp></pre>
required: true
schema:
type: string
- name: Accept-Encoding
in: header
description: Specifies the response encoding that the client would like to receive back. This must be gzip.
required: true
schema:
type: string
example: 'gzip'
- name: User-Agent
in: header
description: The User-Agent header string from the customer's request, as captured by your integration.
required: true
schema:
type: string
example: 'Mozilla/5.0 (Linux; Android 13; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36'
- name: Customer-Ip
in: header
description: IP address of the customer, as captured by your integration.
Ensure your integration passes the customer's IP, not your own. Used for fraud recovery and other important analytics.
required: false
schema:
type: string
example: '192.168.123.132'
- name: Customer-Session-Id
in: header
description: Insert your own unique value for each user session, beginning with the first API call.
Continue to pass the same value for each subsequent API call during the user's session, using a new value for every new customer session.
required: false
schema:
type: string
example: '7f9a24ea-2145-4819-a7b7-2a4cbe1165ab'
- name: Customer-Id
in: header
description: An obfuscated unique identifier for each customer. This should not contain any personal information such as email, first or last name.
required: true
schema:
type: string
example: '7f9a24ea-2145-4819-a7b7-2a4cbe1165ab'
- name: Test
in: header
description: Ads calls have a test header that can be used to return set responses with the following keywords:<br>
* `standard`
* `service_unavailable`
* `unknown_internal_error`
schema:
type: string
enum:
- standard
- service_unavailable
- unknown_internal_error
- name: billing_terms
in: query
description: This parameter is to specify the terms of how a resulting booking should be billed. If this field is
needed, the value for this will be provided to you separately.
schema:
type: string
- name: partner_point_of_sale
in: query
description: This parameter is to specify what point of sale is being used to shop and book. If this field is needed,
the value for this will be provided to you separately.
schema:
type: string
- name: payment_terms
in: query
description: This parameter is to specify what terms should be used when being paid for a resulting booking. If this
field is needed, the value for this will be provided to you separately.
schema:
type: string
- name: platform_name
in: query
description: This parameter is to specify what platform is being used to shop and book. If this field is needed, the
value for this will be provided to you separately.
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AdsRequest'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/AdsResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
type: 'invalid_input'
message: 'An invalid request was sent in, please check the nested errors for details.'
errors:
- type: 'language.required'
message: 'A language is required. Supported languages are:
[ar-SA, cs-CZ, da-DK, de-DE, el-GR, en-US, es-ES, es-MX, fi-FI, fr-CA, fr-FR, hr-HR, hu-HU, id-ID,
is-IS, it-IT, ja-JP, lt-LT, ko-KR, ms-MY, nb-NO, nl-NL, pl-PL, pt-BR, pt-PT, ru-RU, sk-SK, sv-SE,
th-TH, tr-TR, uk-UA, vi-VN, zh-CN, zh-TW]'
fields:
- name: 'language'
type: 'request'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
type: 'request_unauthenticated'
message: 'Data required to authenticate your request is missing or inaccurate.
Ensure that your request follows the guidelines in our documentation.'
fields:
- name: 'apikey'
type: 'header'
value: 'jaj3982k239dka328e'
- name: 'signature'
type: 'header'
value: '129d75332614a5bdbe0c7eb540e95a65f9d85a5b53dabb38d19b37fad6312a2bd25c12ee5a82831d55112087e1b'
- name: 'timestamp'
type: 'header'
value: '198284729'
- name: 'servertimestamp'
type: 'server'
value: '198284729'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
type: 'request_unauthorized'
message: 'Your request could not be authorized.'
'426':
description: Upgrade Required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
type: 'upgrade_required'
message: 'This service requires the use of TLS.'
'429':
description: Too Many Requests
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
type: 'too_many_requests'
message: 'You have reached your capacity for this type of request.'
'500':
description: Unknown Internal Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
type: 'unknown_internal_error'
message: 'An internal server error has occurred.'
'503':
description: Service Unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
type: 'service_unavailable'
message: 'This service is currently unavailable.'
components:
schemas:
PageType:
type: string
enum:
- other
- search_results
- details
- confirmation
example: 'search_results'
description: The type of page the ads will be rendered on.
SortType:
type: string
enum:
- default
example: default
description: The sort type selected for the organic results.
ProductLine:
type: string
enum:
- car
- flight
- lodging
example: lodging
description: The different types of travel product lines a traveler can search for.
SalesChannel:
type: string
enum:
- website
- mobile_app
- mobile_web
example: 'mobile_app'
description: The sales channel for the request.
GuestCounts:
type: object
required:
- adult_count
properties:
adult_count:
type: integer
format: int32
example: 2
child_count:
type: integer
format: int32
example: 1
AdsRequest:
type: object
required:
- sales_channel
- language
- country_code
- page_type
- search_product_lines
- checkin
- checkout
- occupancies
- property_ids
properties:
country_code:
type: string
example: 'US'
pattern: '^[A-Z]{2}$'
description: "The country code of the traveler's point of sale, in ISO 3166-1 alpha-2 format.
This should represent the country where the shopping transaction is taking place.
For more information see: https://www.iso.org/obp/ui/#search/code/"
language:
type: string
example: 'en-US'
pattern: '^[a-z]{2}-[A-Z]{2}$'
description: 'Desired language for the response as a subset of BCP47 format that only uses hyphenated pairs of two-digit language and country codes.
Use only ISO 639-1 alpha-2 language codes and ISO 3166-1 alpha-2 country codes.
See https://www.w3.org/International/articles/language-tags/
Language Options: https://developers.expediagroup.com/docs/rapid/resources/reference/language-options'
sales_channel:
$ref: '#/components/schemas/SalesChannel'
page_type:
$ref: '#/components/schemas/PageType'
sort_type:
$ref: '#/components/schemas/SortType'
search_product_lines:
example: [ 'lodging', 'flight' ]
description: The product lines the traveler is searching for. lodging indicates hotel_standalone. lodging and
flight would indicate a lodging_package.
type: array
items:
$ref: '#/components/schemas/ProductLine'
checkin:
type: string
description: Check-in date, in ISO 8601 format (YYYY-MM-DD).
pattern: '^\d{4}-\d{2}-\d{2}$'
example: '2025-01-01'
checkout:
type: string
description: Check-out date, in ISO 8601 format (YYYY-MM-DD).
pattern: '^\d{4}-\d{2}-\d{2}$'
example: '2025-01-05'
occupancies:
type: array
items:
$ref: '#/components/schemas/GuestCounts'
description: Each array item represents guests of one room.
focused_property_id:
type: string
description: The property id the ranking of ads should be based on. Examples of a focused property are a
customer searching for a specific property and it being pinned to the top of a page or the property
recommendation carousel based on the currently or previously viewed property. The focused_property_id itself
will be excluded from the ranking.
example: '23433'
property_ids:
type: array
items:
type: string
example: [ '2717582', '16159546', '2025453' ]
description: The list of property ids eligible for returning sponsored listings. These are the potential
candidates that could be included in the auction. The maximum number of property_ids that can be sent in a
request is 700.
experiment_ids:
description: A list of experiment ids that can be used for testing different behavior. The ids can be associated
with different tests ran by the publisher and are completely arbitrary. The experiment ids will
be included reports back to the publisher.
type: array
items:
type: string
example: [ '324324.1', '2423423.3', '3242343.5' ]
additionalProperties: false
Image:
type: object
properties:
caption:
type: string
description: The image caption.
example: 'Hotel Lobby'
link:
type: object
additionalProperties:
$ref: '#/components/schemas/Link'
description: The url to retrieve the image.
example:
"70px":
method: GET
href: https://i.travelapi.com/hotels/1000000/20000/15300/15237/bef1b976_t.jpg
description: An individual image.
Creative:
type: object
properties:
image:
$ref: '#/components/schemas/Image'
description: The image to be rendered for the sponsored listing.
additionalProperties: false
Link:
type: object
properties:
method:
type: string
description: The request method used to access the link.
example: 'POST'
href:
type: string
description: The URL for the link. This can be absolute or relative. Placeholders will be need to be populated by the client.
example: 'https://advertising.expedia.com/sponsoredcontent/v1/View?position=[position]&data=AAAAAQAAAAEAAA'
expires:
type: string
description: If the link expires, this will be the UTC date the link will expire, in ISO 8601 format.
example: '2025-07-10 15:00:00.000'
description: An individual link.
Beacons:
type: object
required:
- view
- render
- click
properties:
view:
$ref: '#/components/schemas/Link'
render:
$ref: '#/components/schemas/Link'
click:
$ref: '#/components/schemas/Link'
SponsoredListing:
description: The sponsored listing which advertises a specific property.
type: object
required:
- rank
- property_id
- beacons
properties:
rank:
type: integer
pattern: int32
minimum: 0
example: 1
description: The sponsored listing should adhere to the rank and not be re-ranked. This field is 0-based.
property_id:
type: string
example: '13243534'
creative:
$ref: '#/components/schemas/Creative'
beacons:
$ref: '#/components/schemas/Beacons'
ad_transparency_url:
type: string
example: 'https://advertising.expedia.com/sponsoredcontent/dsa/id=123'
description: The url used to retrieve digital services act information regarding why the ad was selected.
additionalProperties: false
AdsResponse:
type: object
properties:
sponsored_listings:
type: array
items:
$ref: '#/components/schemas/SponsoredListing'
additionalProperties: false
Error:
type: object
properties:
type:
type: string
description: The error type.
message:
type: string
description: A human readable message giving details about this error.
fields:
type: array
description: Details about the specific fields that had an error.
items:
$ref: '#/components/schemas/Field'
errors:
type: array
description: An array of all the actual errors that occured.
items:
$ref: '#/components/schemas/ErrorIndividual'
description: The overall class of error that occured.
Field:
type: object
properties:
name:
type: string
description: The field that had an error.
type:
type: string
description: The type of the field that had an error.
value:
type: string
description: The value of the field that had an error.
description: An individual field that had an error.
ErrorIndividual:
type: object
properties:
type:
type: string
description: The error type.
message:
type: string
description: A human readable message giving details about this error.
fields:
type: array
description: Details about the specific fields that had an error.
items:
$ref: '#/components/schemas/Field'
description: An individual error.
ID de propiedad: Solo se reconocerán los ID de propiedad de Expedia al llamar a la API de anuncios patrocinados de alojamiento. Cualquier ID de grupo de non-Expedia puede que no muestre ningún inventario publicitario o que, por error, se asocie a una propiedad diferente e irrelevante de Expedia Group.
Límite de propiedades: Puedes incluir hasta 700 ID de propiedades en una sola solicitud.
Tarifas y disponibilidad de alojamientos: La API de anuncios patrocinados de alojamientos no asume ni comprueba la disponibilidad, ya que puedes elegir mostrar las tarifas de Expedia Group o las de otras fuentes en los anuncios patrocinados de los resultados de búsqueda. Por eso tienes que enviar una solicitud tanto a la API de anuncios patrocinados de alojamiento como a la API de disponibilidad de compras y combinar los resultados.
Procesamiento por lotes y almacenamiento en caché: La API de anuncios patrocinados de alojamiento no admite solicitudes por lotes, y Expedia Group desaconseja el almacenamiento en caché del inventario de anuncios patrocinados.
La subasta de anuncios patrocinados tiene que realizarse para cada búsqueda y no se puede reutilizar, así que envía una solicitud al punto final de «Anuncios patrocinados de alojamiento» cada vez que un cliente haga una búsqueda. Si cambian los criterios de búsqueda del cliente (por ejemplo, las fechas del viaje o el número de habitaciones), haz solicitudes adicionales para asegurarte de que la información sea up-to-date.
Aunque puedes almacenar en caché tus tarifas y disponibilidad para la búsqueda orgánica, las llamadas a la API de anuncios patrocinados de alojamiento deben realizarse en tiempo real. Las plataformas publicitarias suelen establecer presupuestos máximos diarios que se gastan en tiempo real. Si los datos del anuncio no se actualizan con frecuencia, para cuando se haga clic en él, puede que al anunciante ya no le quede presupuesto. A esto se le llama «sobregasto», y aunque se muestre un anuncio y un cliente haga clic en él, no se generarán ingresos.
Orden de los anuncios clasificados: Puedes elegir qué posiciones de tus resultados de búsqueda quieres reservar para anuncios patrocinados, pero no puedes hacer una « re-sort » ni aplicar un algoritmo de selección, como sí podrías hacer con las respuestas de la API de Shopping. Esto se debe a que el orden de los anuncios patrocinados que se muestran en la API refleja los resultados de la subasta en tiempo real, en la que los anunciantes pujan con ciertas cantidades cost-per-click para conseguir su posición.
Si no quieres que un alojamiento concreto aparezca en un anuncio patrocinado, puedes excluir el ID de ese alojamiento en tu solicitud a la API de anuncios patrocinados de alojamientos.
Cobertura publicitaria:. Los parámetros de búsqueda adicionales, como los filtros, limitan el número de inmuebles que pueden aparecer en una búsqueda concreta. Te recomendamos que incluyas el mayor número posible de inmuebles en tu solicitud. Aplicar cualquier filtro adicional más allá de los datos que introduce el viajero podría hacer que se perdieran oportunidades de ingresos publicitarios.
Imagen principal del alojamiento: No es obligatorio utilizar las imágenes principales de property-selected que se envían a través de la respuesta de la API, pero te recomendamos que lo hagas.
Duplicación de anuncios inmobiliarios en los anuncios patrocinados y en los resultados orgánicos: Es una práctica habitual en el sector que los anuncios inmobiliarios que aparecen en los anuncios patrocinados también salgan en un segundo anuncio orgánico en los resultados de búsqueda. Los anunciantes están dispuestos a hacer ofertas más altas a cambio de una mayor visibilidad en los resultados de búsqueda.
Por ejemplo, si reservas la posición 1 de los resultados de búsqueda para un anuncio patrocinado y Hotel A gana la subasta, aparecerá en la posición 1 como anuncio patrocinado. En tu selección de inventario orgánico y orden de clasificación, Hotel A aparece por segunda vez en los resultados de búsqueda, en la posición 7, más abajo en la página.
Es poco habitual que un anuncio patrocinado aparezca justo encima o debajo de su resultado orgánico correspondiente en los resultados de búsqueda; esto solo ocurre en la parte superior de los resultados en entre el 2 % y el 3 % de las búsquedas. Cuando eso ocurra, una opción es bajar el resultado orgánico unas cuantas posiciones, ajustando el desplazamiento a un nivel que mantenga una buena experiencia de usuario.
Ejemplo de un anuncio patrocinado en «sort»
Como los bloqueadores de anuncios a veces detectan y eliminan los anuncios patrocinados de los resultados de búsqueda, eliminar la duplicación orgánica significaría que los alojamientos de « high-quality » no aparecerían ante los viajeros.
Compatibilidad con las solicitudes de la API de compras: La API de anuncios patrocinados de alojamiento está diseñada para usarse junto con la API de compras rápidas de alojamiento. El orden de las solicitudes de la API no importa: las solicitudes a la API de anuncios patrocinados de alojamiento y a la API de disponibilidad de compras se pueden realizar en paralelo o de forma secuencial.
El último paso antes de poner en marcha tu implementación de la API de anuncios patrocinados de alojamiento es asegurarte de pasar de los puntos de conexión de pruebas a los de producción:
Cambia la API de entrega de anuncios de https://test.ean.com/v1/ads a https://api.ean.com/v1/ads.
Cambia el punto final de notificación de reservas (si lo usas) de https://test.ean.com/v1/ads/booking-notification a https://api.ean.com/v1/ads/booking-notification.