Skip to main content

API DeviceHub

note

Recuerda que estas llamadas API serán peticiones HTTP POST a un la dirección TCP/IP donde está instalado el DeviceHub. Normalmente esta dirección será:

POST http://localhost:17000

La configuración del DeviceHub deberá ser esta:

Woonivers API Key será proporcionado por el equipo de Sipay. Las URLs por entorno son:

EntornoObjetoURL
sandboxtravellerhttps://sandbox.woonivers.com/api/v1/traveller
sandboxderhttps://sandbox.woonivers.com/api/v1/traveller
livetravellerhttps://api.woonivers.com/api/v1/traveller
livederhttps://api.woonivers.com/api/v1/traveller

Esta integración parte de la premisa de que ya tiene integrada la pasarela de pagos de Sipay en su PoS. Puede ver la referencia en este enlace.

Existen llamadas especiales que ofrecen su funcionalidad a través del contenido del propio mensaje XML. Son conocidas como CallSpecificFunction. Tienen los mismos elemementos comunes que todas las llamadas: ClientIdValue, ... pero además todas las de este tipo tienen los siguientes parámetros comunes:

  • Function
  • Modifier
  • Parameter 1
  • Parameter 2
  • Parameter 3

A continuación incluimos un ejemplo genérico a modo de prototipo:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>FunctionCode</tem:Function>
<tem:Modifier>FunctionModifier</tem:Modifier>
<tem:Parameter1>Parameter1</tem:Parameter1>
<tem:Parameter2>Parameter1</tem:Parameter2>
<tem:Parameter3>Parameter3</tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>

Con la especificación técnica que encontrará en esta guía podrá abordar los siguientes casos de uso:

  • Caso 1: Usuario registrado en Woonivers al que se le detecta la tarjeta con el BIN elegible (a.k.a ACR, moneda distinta EUR) en el momento del cobro.
  • Caso 2: Usuario no registrado en Woonivers al que se le detecta la tarjeta con el BIN elegible (a.k.a ACR, moneda distintaEUR) en el momento del cobro.
  • Caso 3: Usuario registrado en Woonivers que solicita el tax free antes de pagar.
  • Caso 4: Usuario no registrado en Woonivers que solicita el tax free antes de pagar.
  • Caso 5: Usuario registrado en Woonivers que solicita el tax free después de pagar.
  • Caso 6: Usuario no registrado en Woonivers que solicita el tax free después de pagar.

💳ACR (Automatic Card Recognition)

Nuestro sistema Automatic Card Recognition (ACR) que tendrías implementado para el proceso de Tax Free está diseñado para detectar tarjetas que no son de la zona euro y facilitar la creación de documentos Tax Free de manera automática.

El ACR funciona de la siguiente manera:

  1. Detección Automática: Cuando un turista realiza una compra y paga con una tarjeta que tiene un BIN (Bank Identification Number) de fuera de la UE, el sistema ACR reconoce automáticamente la tarjeta.
  2. Generación de Factura Tax Free: Una vez detectada la tarjeta, el sistema genera automáticamente la factura Tax Free para la tienda, sin necesidad de intervención manual con la entrada vía API del resto de datos.
  3. Recopilación de Datos: El sistema recoge los datos de la compra del CRM de la caja, incluyendo el número de ticket, productos, PVP, IVA, etc., y de la tarjeta el número enmascarado para el posterior pago del importe del Tax Free.
  4. Devolución del IVA: La integración registra automáticamente el importe de devolución conforme a la tabla oficial de devolución del IVA.

Beneficios del Sistema ACR:

  • Conversión: Un gran porcentaje de viajeros no solicitan el tax free. Con este sistema podrá ofrecer proactivamente el servicio de Tax Free y mejorar la experiencia de sus clientes.
  • Eficiencia: Automatiza el proceso de detección y generación de facturas Tax Free, reduciendo la necesidad de intervención manual y acelerando el proceso.
  • Precisión: Minimiza errores al utilizar datos precisos y actualizados de las tarjetas y las compras.
  • Facilidad de Uso: Permite a los comercios realizar el cobro sin la presencia física del cliente, facilitando el proceso de pago y la generación de facturas Tax Free.

La llamada GetNextMessage en la respuesta final con el código 1000, deberemos buscar el valor del campo TaxFreeEnabled con valor a 1.

                ...
<ns1:ExtraInfo>
<ns1:TaxFreeEnabled>0</ns1:TaxFreeEnabled>
<ns1:Feature1>0</ns1:Feature1>
<ns1:Feature2>0</ns1:Feature2>
<ns1:Feature3>0</ns1:Feature3>
<ns1:Feature4>0</ns1:Feature4>
<ns1:AuthorizationCode></ns1:AuthorizationCode>
<ns1:FeatureInfo></ns1:FeatureInfo>
</ns1:ExtraInfo>
...

La llamada completa puede encontrarse en este enlace.

🧳Viajero

[POST /traveller] Creación de viajero

Petición

Parámetros:

Los datos de Header deben ser iguales que en todas las transacciones.

  • Function: 75
  • Modifier: 4
  • Parameter1: Valor de traveller
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosIdValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>75</tem:Function>
<tem:Modifier>4</tem:Modifier>
<tem:Parameter1>traveller</tem:Parameter1>
<tem:Parameter2></tem:Parameter2>
<tem:Parameter3></tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>

El valor de Parameter1 será un cadena de texto que contiene el JSON con los datos del viajero y codificada en base64.

Si tomamos el ejemplo del API:

{
"country": "ESP",
"locale": "en",
"email": "john@doe.com",
"first_name": "John",
"last_name": "Doe",
"phone": "123456789",
"phone_prefix": "34",
"birth_date": "1990-01-25",
"document_type": "PASSPORT_ID_TYPE",
"document_id": "123456789",
"document_country": "ESP",
"notes": "string",
"residence_country": "ESP",
"zip_code": "28001",
"city": "Madrid",
"address": "Calle de la Princesa, 1"
}

La codificación en base64 será:

ewogICJjb3VudHJ5IjogIkVTUCIsCiAgImxvY2FsZSI6ICJlbiIsCiAgImVtYWlsIjogImpvaG5AZG9lLmNvbSIsCiAgImZpcnN0X25hbWUiOiAiSm9obiIsCiAgImxhc3RfbmFtZSI6ICJEb2UiLAogICJwaG9uZSI6ICIxMjM0NTY3ODkiLAogICJwaG9uZV9wcmVmaXgiOiAiMzQiLAogICJiaXJ0aF9kYXRlIjogIjE5OTAtMDEtMjUiLAogICJkb2N1bWVudF90eXBlIjogIlBBU1NQT1JUX0lEX1RZUEUiLAogICJkb2N1bWVudF9pZCI6ICIxMjM0NTY3ODkiLAogICJkb2N1bWVudF9jb3VudHJ5IjogIkVTUCIsCiAgIm5vdGVzIjogInN0cmluZyIsCiAgInJlc2lkZW5jZV9jb3VudHJ5IjogIkVTUCIsCiAgInppcF9jb2RlIjogIjI4MDAxIiwKICAiY2l0eSI6ICJNYWRyaWQiLAogICJhZGRyZXNzIjogIkNhbGxlIGRlIGxhIFByaW5jZXNhLCAxIgp9

y por tanto la petición al DeviceHub será:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosIdValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>75</tem:Function>
<tem:Modifier>4</tem:Modifier>
<tem:Parameter1>ewogICJjb3VudHJ5IjogIkVTUCIsCiAgImxvY2FsZSI6ICJlbiIsCiAgImVtYWlsIjogImpvaG5AZG9lLmNvbSIsCiAgImZpcnN0X25hbWUiOiAiSm9obiIsCiAgImxhc3RfbmFtZSI6ICJEb2UiLAogICJwaG9uZSI6ICIxMjM0NTY3ODkiLAogICJwaG9uZV9wcmVmaXgiOiAiMzQiLAogICJiaXJ0aF9kYXRlIjogIjE5OTAtMDEtMjUiLAogICJkb2N1bWVudF90eXBlIjogIlBBU1NQT1JUX0lEX1RZUEUiLAogICJkb2N1bWVudF9pZCI6ICIxMjM0NTY3ODkiLAogICJkb2N1bWVudF9jb3VudHJ5IjogIkVTUCIsCiAgIm5vdGVzIjogInN0cmluZyIsCiAgInJlc2lkZW5jZV9jb3VudHJ5IjogIkVTUCIsCiAgInppcF9jb2RlIjogIjI4MDAxIiwKICAiY2l0eSI6ICJNYWRyaWQiLAogICJhZGRyZXNzIjogIkNhbGxlIGRlIGxhIFByaW5jZXNhLCAxIgp9</tem:Parameter1>
<tem:Parameter2></tem:Parameter2>
<tem:Parameter3></tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>
Respuesta

Mediante la iteración del GetNextMessage y atendiendo a las reglas comentadas en esta sección deberemos obtener el valor de <ns1:ExpansionData><EXPANSION></EXPANSION></ns1:ExpansionData> en el código 1000.

[GET /traveller] Obtener datos del viajero

En este caso, teniendo un importe y un número de ticket, se lanza la transacción de devolución, solicitando la autorización financiera. El código de respuesta refleja si la petición ha sido entregada al servicio device hub. Para obtener el resultado de la transacción, es necesario utilizar la función GetNextMessage.

Petición

Parámetros:

Los datos de Header deben ser iguales que en todas las transacciones.

  • Function: 75
  • Modifier: 3
  • Parameter1: Valor de traveller_id
  • Parameter2: Valor de document_id
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosIdValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>75</tem:Function>
<tem:Modifier>3</tem:Modifier>
<tem:Parameter1>301</tem:Parameter1>
<tem:Parameter2></tem:Parameter2>
<tem:Parameter3></tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>
Respuesta

Mediante la iteración del GetNextMessage y atendiendo a las reglas comentadas en esta sección deberemos obtener el valor de <ns1:ExpansionData><EXPANSION></EXPANSION></ns1:ExpansionData> en el código 1000.

Contendar una cadena en base64 que se deberá decodificar para obtener el JSON con los datos del viajero. Ejemplo:

{
"request_id": "6bd80493-4917-4fdd-a304-58245d116037",
"id": "Xxxxasda80493-4917-4fdd-a304-5824123137",
"locale": "es-AR",
"email": "john.doe@example.com",
"first_name": "JOHN DOE",
"last_name": "MAURO",
"phone_prefix": 34,
"phone_number": "123123123",
"birth_date": "1978-07-19",
"document_type": "PASSPORT_ID_TYPE",
"document_id": "AXXXXABCD",
"document_country": "ARG",
"residence_country": "ARG",
"zip_code": "1842",
"city": "buenos aires",
"address": "sargento cabral"
}

[PUT /traveller] Actualizar información del viajero

Petición

Parámetros:

Los datos de Header deben ser iguales que en todas las transacciones.

  • Function: 75
  • Modifier: 5
  • Parameter1: Valor de traveller id
  • Parameter2: Valor de traveller
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosIdValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>75</tem:Function>
<tem:Modifier>5</tem:Modifier>
<tem:Parameter1>traveller_id</tem:Parameter1>
<tem:Parameter2>traveller</tem:Parameter2>
<tem:Parameter3></tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>

El valor de Parameter1 será el identificador del viajero interno en Woonivers. El valor de Parameter2 será un cadena de texto que contiene el JSON con los datos del viajero completos y codificada en base64.

Si tomamos el ejemplo del API:

{
"country": "ESP",
"locale": "en",
"email": "john@doe.com",
"first_name": "John",
"last_name": "Doe",
"phone": "123456789",
"phone_prefix": "34",
"birth_date": "1990-01-25",
"document_type": "PASSPORT_ID_TYPE",
"document_id": "123456789",
"document_country": "ESP",
"notes": "string",
"residence_country": "ESP",
"zip_code": "28001",
"city": "Madrid",
"address": "Calle de la Princesa, 1"
}

La codificación en base64 será:

ewogICJjb3VudHJ5IjogIkVTUCIsCiAgImxvY2FsZSI6ICJlbiIsCiAgImVtYWlsIjogImpvaG5AZG9lLmNvbSIsCiAgImZpcnN0X25hbWUiOiAiSm9obiIsCiAgImxhc3RfbmFtZSI6ICJEb2UiLAogICJwaG9uZSI6ICIxMjM0NTY3ODkiLAogICJwaG9uZV9wcmVmaXgiOiAiMzQiLAogICJiaXJ0aF9kYXRlIjogIjE5OTAtMDEtMjUiLAogICJkb2N1bWVudF90eXBlIjogIlBBU1NQT1JUX0lEX1RZUEUiLAogICJkb2N1bWVudF9pZCI6ICIxMjM0NTY3ODkiLAogICJkb2N1bWVudF9jb3VudHJ5IjogIkVTUCIsCiAgIm5vdGVzIjogInN0cmluZyIsCiAgInJlc2lkZW5jZV9jb3VudHJ5IjogIkVTUCIsCiAgInppcF9jb2RlIjogIjI4MDAxIiwKICAiY2l0eSI6ICJNYWRyaWQiLAogICJhZGRyZXNzIjogIkNhbGxlIGRlIGxhIFByaW5jZXNhLCAxIgp9

y por tanto la petición al DeviceHub será:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosIdValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>75</tem:Function>
<tem:Modifier>5</tem:Modifier>
<tem:Parameter1>ABC-123-ID</tem:Parameter1>
<tem:Parameter2>ewogICJjb3VudHJ5IjogIkVTUCIsCiAgImxvY2FsZSI6ICJlbiIsCiAgImVtYWlsIjogImpvaG5AZG9lLmNvbSIsCiAgImZpcnN0X25hbWUiOiAiSm9obiIsCiAgImxhc3RfbmFtZSI6ICJEb2UiLAogICJwaG9uZSI6ICIxMjM0NTY3ODkiLAogICJwaG9uZV9wcmVmaXgiOiAiMzQiLAogICJiaXJ0aF9kYXRlIjogIjE5OTAtMDEtMjUiLAogICJkb2N1bWVudF90eXBlIjogIlBBU1NQT1JUX0lEX1RZUEUiLAogICJkb2N1bWVudF9pZCI6ICIxMjM0NTY3ODkiLAogICJkb2N1bWVudF9jb3VudHJ5IjogIkVTUCIsCiAgIm5vdGVzIjogInN0cmluZyIsCiAgInJlc2lkZW5jZV9jb3VudHJ5IjogIkVTUCIsCiAgInppcF9jb2RlIjogIjI4MDAxIiwKICAiY2l0eSI6ICJNYWRyaWQiLAogICJhZGRyZXNzIjogIkNhbGxlIGRlIGxhIFByaW5jZXNhLCAxIgp9</tem:Parameter2>
<tem:Parameter3></tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>
Respuesta

Mediante la iteración del GetNextMessage y atendiendo a las reglas comentadas en esta sección deberemos obtener el valor de <ns1:ExpansionData><EXPANSION></EXPANSION></ns1:ExpansionData> en el código 1000.


🧾DER

[POST /der] Creación de DER

Petición

Parámetros:

Los datos de Header deben ser iguales que en todas las transacciones.

  • Function: 75
  • Modifier: 1
  • Parameter1: Valor del DER
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosIdValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>75</tem:Function>
<tem:Modifier>1</tem:Modifier>
<tem:Parameter1>der</tem:Parameter1>
<tem:Parameter2></tem:Parameter2>
<tem:Parameter3></tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>

El valor de Parameter1 será un cadena de texto que contiene el JSON con los datos del viajero y codificada en base64.

Si tomamos el ejemplo del API:

{
"country": "ESP",
"locale": "en",
"order": "order_id",
"order_datetime": "2025-03-25",
"currency": "eur",
"traveller_id": "woonivers_traveller_id",
"products": [
{
"amount": 1,
"description": "Producto 1",
"classification": "ALI",
"tax_rate": 7.5,
"tax_base": 4000,
"tax_amount": 400,
"total_tax": 4400,
"serial_number": "Serial number",
"metadata": {
"key_sample1": "value_sample1",
"key_sample2": "value_sample2"
}
}
],
"metadata": {
"key_sample1": "value_sample1",
"key_sample2": "value_sample2"
}
}

La codificación en base64 será:

ewogICJjb3VudHJ5IjogIkVTUCIsCiAgImxvY2FsZSI6ICJlbiIsCiAgImVtYWlsIjogImpvaG5AZG9lLmNvbSIsCiAgImZpcnN0X25hbWUiOiAiSm9obiIsCiAgImxhc3RfbmFtZSI6ICJEb2UiLAogICJwaG9uZSI6ICIxMjM0NTY3ODkiLAogICJwaG9uZV9wcmVmaXgiOiAiMzQiLAogICJiaXJ0aF9kYXRlIjogIjE5OTAtMDEtMjUiLAogICJkb2N1bWVudF90eXBlIjogIlBBU1NQT1JUX0lEX1RZUEUiLAogICJkb2N1bWVudF9pZCI6ICIxMjM0NTY3ODkiLAogICJkb2N1bWVudF9jb3VudHJ5IjogIkVTUCIsCiAgIm5vdGVzIjogInN0cmluZyIsCiAgInJlc2lkZW5jZV9jb3VudHJ5IjogIkVTUCIsCiAgInppcF9jb2RlIjogIjI4MDAxIiwKICAiY2l0eSI6ICJNYWRyaWQiLAogICJhZGRyZXNzIjogIkNhbGxlIGRlIGxhIFByaW5jZXNhLCAxIgp9

y por tanto la petición al DeviceHub será:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:CallSpecificFunctionRequest>
<tem:Header>
<tem:ClientId>ClientIdValue</tem:ClientId>
<tem:StoreId>StoreIdValue</tem:StoreId>
<tem:PosId>PosIdValue</tem:PosId>
<tem:Lang>Idioma</tem:Lang>
<tem:ExtraData1></tem:ExtraData1>
</tem:Header>
<tem:Function>75</tem:Function>
<tem:Modifier>4</tem:Modifier>
<tem:Parameter1>ewogICJjb3VudHJ5IjogIkVTUCIsCiAgImxvY2FsZSI6ICJlbiIsCiAgImVtYWlsIjogImpvaG5AZG9lLmNvbSIsCiAgImZpcnN0X25hbWUiOiAiSm9obiIsCiAgImxhc3RfbmFtZSI6ICJEb2UiLAogICJwaG9uZSI6ICIxMjM0NTY3ODkiLAogICJwaG9uZV9wcmVmaXgiOiAiMzQiLAogICJiaXJ0aF9kYXRlIjogIjE5OTAtMDEtMjUiLAogICJkb2N1bWVudF90eXBlIjogIlBBU1NQT1JUX0lEX1RZUEUiLAogICJkb2N1bWVudF9pZCI6ICIxMjM0NTY3ODkiLAogICJkb2N1bWVudF9jb3VudHJ5IjogIkVTUCIsCiAgIm5vdGVzIjogInN0cmluZyIsCiAgInJlc2lkZW5jZV9jb3VudHJ5IjogIkVTUCIsCiAgInppcF9jb2RlIjogIjI4MDAxIiwKICAiY2l0eSI6ICJNYWRyaWQiLAogICJhZGRyZXNzIjogIkNhbGxlIGRlIGxhIFByaW5jZXNhLCAxIgp9</tem:Parameter1>
<tem:Parameter2></tem:Parameter2>
<tem:Parameter3></tem:Parameter3>
</tem:CallSpecificFunctionRequest>
</soap:Body>
</soap:Envelope>
Respuesta

Mediante la iteración del GetNextMessage y atendiendo a las reglas comentadas en esta sección deberemos obtener el valor de <ns1:ExpansionData><EXPANSION></EXPANSION></ns1:ExpansionData> en el código 1000.

[GET /der] Búsqueda de DER

[DELETE /der] Cancelación de DER