1.2.2. Tutorial de la API para comerciantes#

1.2.2.1. Introducción#

1.2.2.1.1. Acerca de GNU Taler#

GNU Taler es un protocolo abierto para un sistema de pago electrónico con una implementación de referencia de software libre. GNU Taler ofrece un procesamiento de pagos seguro, rápido y sencillo utilizando técnicas criptográficas bien entendidas. GNU Taler permite a los clientes permanecer en el anonimato, al tiempo que garantiza que los comerciantes puedan ser responsabilizados por los gobiernos. Por lo tanto, GNU Taler es compatible con la regulación antiblanqueo de dinero (AML) y de conocimiento del cliente (KYC), así como con la regulación de protección de datos (como GDPR).

1.2.2.1.2. Acerca de este tutorial#

Este tutorial trata sobre cómo procesar pagos usando el backend GNU Taler para comerciantes. La audiencia para este tutorial son desarrolladores de comerciantes (como tiendas web) que están trabajando en la integración de GNU Taler con el Frontend de cara al cliente y el Backoffice de cara al personal.

En este capítulo se explican algunos conceptos básicos. En el segundo capítulo, aprenderá a realizar pagos básicos.

Esta versión del tutorial tiene ejemplos para Python3. Utiliza la librería requests para peticiones HTTP. También hay disponibles versiones para otros lenguajes/entornos.

Si quieres ver algunos ejemplos sencillos y en funcionamiento, echa un vistazo a estos:

1.2.2.1.3. Arquitectura general#

La pila de software Taler para un comerciante consta de los siguientes componentes principales:

  • Un frontend que interactúa con el navegador del cliente. La interfaz permite al cliente crear una cesta de la compra y realizar un pedido. Tras el pago, activa la lógica comercial correspondiente para satisfacer el pedido. Este componente no se incluye con Taler, sino que se supone que existe en el comerciante. Este tutorial describe cómo desarrollar un frontend Taler.

  • Un backend de pago específico de Taler que facilita al frontend el procesamiento de transacciones financieras con Taler. Para este tutorial, utilizará un backend sandbox público. Para el uso en producción, debe configurar su propio backend o pedir a otra persona que lo haga por usted.

La siguiente imagen ilustra las diversas interacciones de estos componentes clave:

../../_images/arch-api.png

El backend proporciona el soporte de protocolo criptográfico, almacena la información financiera específica de Taler y se comunica con el intercambio GNU Taler a través de Internet. El frontend accede al backend a través de una API RESTful. Como resultado, el frontend nunca tiene que comunicarse directamente con el intercambio, y tampoco trata con datos sensibles. En concreto, las claves de firma del comerciante y la información de la cuenta bancaria se encapsulan en el backend Taler.

Algunas funcionalidades del backend (la «interfaz pública») se exponen directamente al navegador del cliente. En la API HTTP, todos los puntos finales privados (para el Backoffice) llevan el prefijo /private/. Este tutorial se centra en los puntos finales /private/. La interfaz pública es utilizada directamente por el monedero y no es relevante para el comerciante (aparte de que la API debe estar expuesta).

1.2.2.1.4. Sandbox público y autenticación#

La forma en que el frontend se autentifica en el backend Taler depende de la configuración. Consulte el Manual del operador del backend Taler.

El backend de sandbox público https://backend.demo.taler.net/instances/sandbox/ utiliza una clave API en la cabecera Authorization. El valor de esta cabecera debe ser Bearer secret-token:sandbox para el backend sandbox público.

>>> import requests
>>> requests.get("https://backend.demo.taler.net/instances/sandbox/private/orders",
...              headers={"Authorization": "Bearer secret-token:sandbox"})
<Response [200]>

Si se devuelve un código de estado HTTP distinto de 200, algo ha ido mal. Debe averiguar cuál es el problema antes de continuar con este tutorial.

El backend sandbox https://backend.demo.taler.net/instances/sandbox/ utiliza KUDOS como moneda imaginaria. Las monedas denominadas en KUDOS pueden retirarse de https://bank.demo.taler.net/.

1.2.2.1.5. Instancias comerciales#

Un único servidor Taler merchant backend puede ser utilizado por múltiples comerciantes que son entidades de negocio separadas. A cada una de estas entidades comerciales se le asigna una instancia de comerciante que se identifica mediante un id de instancia alfanumérico. Si se omite la instancia, se asume el id de instancia admin.

Las siguientes instancias comerciales están configuradas en https://backend.demo.taler.net/:

Nota

Se trata de comerciantes ficticios utilizados para nuestras demostradoras y no están afiliados ni aprobados oficialmente por los respectivos proyectos.

Todos los puntos finales de las instancias ofrecen la misma API. Por lo tanto, la instancia que se va a utilizar simplemente se incluye en la URL base del backend del comerciante.

1.2.2.2. Procesamiento de pagos comerciales#

1.2.2.2.1. Creación de una orden de pago#

Los pagos en Taler giran en torno a una orden, que es una descripción legible por máquina de la transacción comercial para la que se va a realizar el pago. Antes de aceptar un pago Taler como comerciante debe crear dicha orden.

Esto se hace enviando un objeto JSON al punto final de la API /private/orders. En el campo order deben aparecer al menos los siguientes campos:

  • importe: La cantidad a pagar, como una cadena en el formato CURRENCY:DECIMAL_VALUE, por ejemplo EUR:10 para 10 Euros o KUDOS:1.5 para 1.5 KUDOS.

  • resumen: Un resumen legible por humanos de lo que trata el pago. El resumen debe ser lo suficientemente corto como para caber en los títulos, aunque no se impone un límite estricto.

  • fulfillment_url: Una URL que se mostrará una vez completado el pago. En el caso de productos digitales, debe ser una página que muestre el producto adquirido. Cuando el pago se realiza correctamente, el monedero añade automáticamente el order_id como parámetro de consulta, así como el session_sig para los pagos vinculados a sesión (que se explican más adelante).

Los pedidos pueden tener muchos más campos, vea El Formato de Pedido de Taler. Al enviar un pedido por POST, también puede especificar detalles adicionales, como una anulación de la duración del reembolso e instrucciones para la gestión del inventario. Estos son raramente necesarios y no se tratan en este tutorial; por favor, consulte el Manual de referencia para más detalles.

Un fragmento mínimo de Python para crear un pedido tendría el siguiente aspecto:

>>> import requests
>>> body = dict(order=dict(amount="KUDOS:10",
...                        summary="Donation",
...                        fulfillment_url="https://example.com/thanks.html"),
...             create_token=False)
>>> response = requests.post("https://backend.demo.taler.net/instances/sandbox/private/orders",
...               json=body,
...               headers={"Authorization": "Bearer secret-token:sandbox"})
<Response [200]>

El backend completará algunos detalles que faltan en el pedido, como la dirección de la instancia comercial. Los detalles completos se denominan condiciones del contrato.

Nota

La solicitud anterior desactiva el uso de testigos de reclamación estableciendo la opción create_token en false. Si necesita tokens de reclamación, debe ajustar el código para construir el URI taler://pay/ que se indica a continuación para incluir el token de reclamación.

Después de enviar con éxito un POST a /private/orders, se devolverá un JSON con sólo un campo order_id con una cadena que representa el ID del pedido. Si también obtiene un token de reclamación, vuelva a comprobar que ha utilizado la solicitud tal y como se ha descrito anteriormente.

Junto con la instancia del comerciante, el identificador de pedido identifica de forma única el pedido dentro de un backend de comerciante. Usando el ID de pedido, puedes construir trivialmente el URI taler://pay/ respectivo que debe proporcionarse al monedero. Sea ejemplo.com el nombre de dominio donde los puntos finales públicos de la instancia son accesibles. El URI de pago de Taler es entonces simplemente taler://pay/example.com/$ORDER_ID/ donde $ORDER_ID debe ser reemplazado por el ID de la orden que fue devuelta.

Puede poner el URI taler:// como destino de un enlace para abrir el monedero Taler a través del esquema taler://, o ponerlo en un código QR. Sin embargo, para una tienda web, lo más sencillo es redirigir el navegador a https://example.com/orders/$ORDER_ID. Esa página activará el monedero Taler. Aquí el backend genera la lógica correcta para activar el monedero, soportando los distintos tipos de monederos Taler existentes. En lugar de construir la URL anterior a mano, también es posible obtenerla comprobando el estado del pago como se describe en la siguiente sección.

Al construir manualmente esta URL, asegúrese de proporcionar el token de reclamación (a menos que se haya deshabilitado) y si el backend se ejecuta sin TLS, utilice taler+http:// (tenga en cuenta que esto último sólo es compatible con los monederos que se ejecutan en modo de depuración).

Nota

Una forma trivial de obtener la payment_redirect_url correcta es comprobar el estado del pago (ver más abajo). Así que si todavía no está seguro de cómo construirlo, puede simplemente pedir al backend que lo haga por usted. Sin embargo, en producción probablemente deberías construirlo manualmente y evitar la petición extra al backend.

1.2.2.2.2. Comprobación del estado del pago y requerimiento de pago#

Dado el ID del pedido, se puede comprobar el estado de un pago con el punto final /private/orders/$ORDER_ID. Si el cliente aún no ha completado el pago, /private/orders/$ORDER_ID proporcionará al frontend una URL (con el nombre payment_redirect_url) que activará el monedero del cliente para ejecutar el pago. Esta es básicamente la URL https://example.com/orders/$ORDER_ID de la que hablamos antes.

>>> import requests
>>> r = requests.get("https://backend.demo.taler.net/instances/sandbox/private/orders/" + order_id,
...                  headers={"Authorization": "Bearer secret-token:sandbox"})
>>> print(r.json())

Si el campo order_status en la respuesta es paid, no obtendrá una payment_redirect_url y en su lugar información sobre el estado del pago, incluyendo:

  • contract_terms: Las condiciones contractuales completas del pedido.

  • refunded: true si se ha concedido un reembolso (posiblemente parcial) por esta compra.

  • importe_devuelto: Importe reembolsado

Una vez que el frontend ha confirmado que el pago se ha realizado correctamente, normalmente necesita activar la lógica empresarial para que el comerciante cumpla las obligaciones del contrato.

Nota

No es necesario seguir consultando para notar cambios en el estado de la transacción del pedido. Los puntos finales admiten sondeos largos, simplemente especifique un parámetro de consulta timeout_ms con el tiempo máximo que desea esperar a que el estado del pedido cambie a paid.

1.2.2.3. Devoluciones#

Un reembolso en GNU Taler es una forma de «deshacer» un pago. Debe ser autorizado por el comerciante. Los reembolsos pueden ser por cualquier fracción de la cantidad original pagada, pero no pueden exceder el pago original. Los reembolsos están limitados en el tiempo y sólo pueden producirse mientras la bolsa mantiene los fondos de un pago concreto en custodia. El tiempo durante el cual un reembolso es posible puede ser controlado mediante el establecimiento de la refund_deadline en una orden. El valor predeterminado para este plazo de reembolso se especifica en la configuración del backend del comerciante.

El frontend puede indicar al backend del vendedor que autorice un reembolso mediante POST al endpoint /private/orders/$ORDER_ID/refund.

El objeto JSON de solicitud de reembolso sólo tiene dos campos:

  • reembolso: Importe a devolver. Si se autorizó un reembolso anterior para el mismo pedido, el nuevo importe debe ser superior, de lo contrario la operación no tiene efecto. El valor indica el importe total a reembolsar, no un incremento del reembolso.

  • reason: Justificación legible por humanos para el reembolso. El motivo solo lo utiliza el back office y no se muestra al cliente.

Si la solicitud tiene éxito (indicado por el código de estado HTTP 200), la respuesta incluye una taler_refund_uri. El frontend debe redirigir el navegador del cliente a esa URL para permitir que el monedero procese el reembolso.

Este fragmento de código ilustra la realización de un reembolso:

>>> import requests
>>> refund_req = dict(refund="KUDOS:10",
...                   reason="Customer did not like the product")
>>> requests.post("https://backend.demo.taler.net/instances/sandbox/private/orders/"
...               + order_id + "/refund", json=refund_req,
...               headers={"Authorization": "Bearer secret-token:sandbox"})
<Response [200]>

Nota

Tras conceder un reembolso, el punto final público https://example.com/orders/$ORDER_ID cambiará su interacción con el monedero y pasará de solicitar el pago a ofrecer un reembolso. Por lo tanto, las interfaces pueden volver a redirigir a los navegadores a este punto final. Sin embargo, para hacerlo, debe añadirse un campo h_contract (?h_contract=$H_CONTRACT), ya que el punto final público lo requiere para autenticar al cliente. El valor requerido $H_CONTRACT se devuelve en la respuesta de reembolso bajo el campo h_contract.

1.2.2.4. Detección de recompras y URL de cumplimiento#

Un posible problema para los comerciantes que venden acceso a artículos digitales es que un cliente puede haber pagado por un artículo en un dispositivo, pero luego querer leerlo en otro distinto, posiblemente uno que ni siquiera tenga instalado un monedero Taler.

Naturalmente, en ese momento se le pedirá al cliente que vuelva a pagar por el artículo. Si el cliente abre entonces el enlace taler:// en el monedero que pagó anteriormente por el artículo (por ejemplo, escaneando el código QR en el escritorio con la aplicación Android), el monedero reclamará el contrato, detectará que la URL de cumplimiento es idéntica a una por la que ya ha realizado un pago en el pasado, e iniciará la redirección de recompra: En este caso, el monedero se pondrá en contacto con el comerciante y repetirá el pago anterior, salvo que esta vez utilizará el ID de sesión (actual) del navegador (aprende el ID de sesión del código QR).

El backend del comerciante actualiza entonces el ID de sesión del pedido existente al ID de sesión actual del navegador. Cuando se comprueba el estado de pago del «nuevo» pedido impagado (o ya en long-polling), el backend detecta que para el ID de sesión y la URL de cumplimiento del navegador hay un contrato pagado existente. Entonces le dice al navegador que redirija inmediatamente a la URL de cumplimiento donde está disponible el artículo ya pagado.

Para garantizar que este mecanismo funciona según lo previsto, los comerciantes deben asegurarse de no utilizar la misma URL de cumplimiento para diferentes productos o para productos físicos en los que se espera que los clientes compren el artículo repetidamente. Del mismo modo, es crucial que los comerciantes utilicen sistemáticamente la misma URL de cumplimiento para el mismo producto digital cuando se desee detectar recompras.

Tenga en cuenta que cambiar el ID de sesión a un dispositivo diferente requiere la participación del monedero que realizó el pago, lo que limita razonablemente la posibilidad de compartir ampliamente las compras digitales. La detección de recompra también se realiza únicamente para URL de cumplimiento HTTP(S). En concreto, esto significa que los URIs de cumplimiento como taler://fulfillment-success/$MESSAGE no se consideran que identifiquen un recurso por el que se pueda pagar y, por tanto, no tienen que ser únicos.

1.2.2.5. Temas avanzados#

1.2.2.5.1. Pagos vinculados a sesión#

A veces no basta con comprobar si se ha pagado un pedido. Por ejemplo, cuando se vende acceso a medios en línea, el editor puede querer que cada cliente pague exactamente por el mismo producto. Taler apoya este modelo permitiendo que el mechant compruebe si el «recibo de pago» está disponible en el dispositivo actual del usuario. Esto evita que los usuarios compartan fácilmente el acceso a los medios transmitiendo un enlace a la página de cumplimiento. Por supuesto, los usuarios sofisticados también podrían compartir los recibos de pago, pero esto no es tan fácil como compartir un enlace, y en este caso es más probable que simplemente compartan los medios directamente.

Para utilizar esta función, el comerciante debe asignar primero al navegador actual del usuario un session_id efímero, normalmente a través de una cookie de sesión. Al ejecutar o reproducir un pago, el monedero recibirá una firma adicional (session_sig). Esta firma certifica que el monedero mostró un recibo de pago para el pedido correspondiente en la sesión actual.

Los pagos vinculados a una sesión se activan pasando el parámetro session_id al punto final /check-payment. El monedero redirigirá entonces a la página de cumplimiento, pero incluirá un parámetro adicional session_sig. El frontend puede consultar /check-payment tanto con el session_id como con el session_sig para verificar que la firma es correcta.

El último identificador de sesión que se utilizó con éxito para demostrar que el recibo de pago está en el monedero del usuario también está disponible como last_session_id en la respuesta a /check-payment.

1.2.2.5.2. Identificación del producto#

En algunas situaciones, el usuario puede haber pagado algún bien digital, pero el frontend no conoce el ID exacto del pedido y, por tanto, no puede ordenar al monedero que revele el recibo de pago existente. Esto es habitual en tiendas sencillas sin un sistema de inicio de sesión. En este caso, se le pediría al usuario que pagara de nuevo, aunque ya hubiera comprado el producto.

Para permitir que el monedero encuentre en su lugar el recibo de pago existente, la tienda debe utilizar una URL de cumplimiento única para cada producto. Entonces, el frontend debe proporcionar un parámetro adicional resource_url a /check-payment. Debe identificar esta URL de cumplimiento única para el producto. El monedero comprobará entonces si ha pagado antes por un contrato con la misma resource_url, y si es así reproducirá el pago anterior.

1.2.2.5.3. Formato de la orden Taler#

Una orden Taler puede especificar muchos detalles sobre el pago. Esta sección describe en profundidad cada uno de los campos.

Los importes financieros se especifican siempre como una cadena con el formato "MONEDA:VALOR_DECIMAL".

importe

Especifica el importe total que el cliente debe pagar al comerciante.

max_fee

Este es el importe total máximo de comisiones de depósito que el comerciante está dispuesto a pagar. Si las comisiones de depósito de las monedas superan este importe, el cliente debe incluirlo en el total del pago. La comisión se especifica utilizando el mismo formato utilizado para amount.

max_wire_fee

Comisión máxima por transferencia aceptada por el comerciante (la cuota del cliente se dividirá por el factor wire_fee_amortization, y se reducirá aún más si las comisiones de depósito son inferiores a max_fee). Por defecto, si falta es cero.

amortizacion de comisiones

¿A lo largo de cuántas transacciones de clientes espera el comerciante amortizar los gastos de transferencia de media? Si la comisión por transferencia del intercambio es superior a max_wire_fee, la diferencia se divide por este número para calcular la contribución esperada del cliente a la comisión por transferencia. La contribución del cliente puede reducirse aún más por la diferencia entre max_fee y la suma de las comisiones de depósito reales. Opcional, el valor por defecto si falta es 1. Los valores cero y negativos no son válidos y también se interpretan como 1.

pay_url

Qué URL acepta pagos. Esta es la URL donde la cartera POST monedas.

fulfillment_url

A qué URL debe dirigirse el monedero para obtener el cumplimiento, por ejemplo el HTML o PDF de un artículo comprado, o un sistema de seguimiento de pedidos de envíos, o una simple página Web legible por humanos que indique el estado del contrato.

orden_id

Identificador alfanumérico, libremente definible por el comerciante. Utilizado por el comerciante para identificar la transacción de forma única.

resumen

Resumen breve y legible del contrato. Para utilizar cuando se muestra el contrato en una sola línea, por ejemplo en el historial de transacciones del cliente.

marca de tiempo

Hora a la que se generó la oferta.

pay_deadline

Fecha límite en la que el comerciante desea que la bolsa transfiera definitivamente el dinero adeudado de este contrato. Una vez que expire este plazo, la bolsa agregará todos los depósitos cuyos contratos hayan superado la «fecha límite de devolución» y ejecutará un pago por transferencia grande para ellos. Los importes se redondearán a la unidad de transferencia; si el importe total sigue siendo inferior a la unidad de transferencia, no se desembolsará.

plazo_de_devolución

Fecha límite hasta la que el comerciante está dispuesto (y es capaz) de realizar reembolsos por el contrato utilizando Taler. Tenga en cuenta que la bolsa Taler retendrá el pago en custodia al menos hasta esta fecha límite. Hasta este momento, el comerciante podrá firmar un mensaje para activar un reembolso al cliente. Pasado este plazo, ya no será posible reembolsar al cliente. Debe ser inferior a pay_deadline.

productos

Matriz de productos que se están vendiendo al cliente. Cada entrada contiene una tupla con los siguientes valores:

descripción

Descripción del producto.

cantidad

Cantidad de los artículos que se van a enviar. Puede especificar una unidad (por ejemplo, 1 kg) o solo la cantidad.

precio

Precio por cantidad de unidades de este producto enviadas a la ubicación_de_entrega dada. Tenga en cuenta que normalmente la suma de todos los precios debe sumar el importe total del contrato, pero puede ser diferente debido a descuentos o porque los precios individuales no están disponibles.

producto_id

ID único del producto en el catálogo del vendedor. Por lo general, puede elegirse libremente, ya que sólo tiene significado para el comerciante, pero debe ser un número en el rango [0,2^{51}).

impuestos

Mapa de los impuestos aplicables que debe pagar el comerciante. La etiqueta es el nombre del impuesto, es decir, IVA, impuesto sobre las ventas o impuesto sobre la renta, y el valor es el importe del impuesto aplicable. Obsérvese que se permiten etiquetas arbitrarias, siempre que se utilicen para identificar el régimen fiscal aplicable. El regulador puede especificar los detalles. Esto se utiliza para declarar al cliente qué impuestos pretende pagar el comerciante, y puede ser utilizado por el cliente como recibo. También es probable que la información sea utilizada por las auditorías fiscales del comerciante.

fecha_entrega

Hora a la que debe entregarse el producto en el lugar_de_entrega.

lugar_entrega

Esto debería dar una etiqueta en el mapa locations, especificando dónde debe entregarse el artículo.

Los valores pueden omitirse si no son aplicables. Por ejemplo, si una compra es sobre un paquete de productos que no tienen precios individuales o IDs de producto, el product_id o el price pueden no estar especificados en el contrato. Del mismo modo, para los productos virtuales entregados directamente a través del URI de cumplimiento, no existe delivery_location.

comerciante
dirección

Esto debería dar una etiqueta en el mapa locations, especificando dónde se encuentra el comerciante.

nombre

Debe indicar un nombre legible para el comerciante.

jurisdicción

Esto debería dar una etiqueta en el mapa locations, especificando la jurisdicción bajo la cual este contrato debe ser arbitrado.

lugares

Mapa asociativo de las ubicaciones utilizadas en el contrato. Las etiquetas de los lugares en este mapa pueden elegirse libremente y utilizarse siempre que se requiera un lugar en otras partes del contrato. De este modo, si se requiere la misma ubicación muchas veces (como la dirección comercial del cliente o del comerciante), sólo es necesario enumerarla (y transmitirla) una vez, y se puede hacer referencia a ella a través de la etiqueta. Una lista no exhaustiva de atributos de ubicación es la siguiente:

nombre

Nombre del destinatario de la entrega, ya sea una empresa o una persona.

país

Nombre del país de entrega, tal como figura en un paquete postal, por ejemplo «Francia».

estado

Nombre del estado para la entrega, tal como figura en un paquete postal, por ejemplo «NY».

región

Nombre de la región de entrega, tal como figura en un paquete postal.

provincias

Nombre de la provincia de entrega, tal como figura en un paquete postal.

ciudad

Nombre de la ciudad de entrega, tal como figura en un paquete postal.

código postal

Código postal de entrega, como el que figura en un paquete postal.

calle

Nombre de la calle de entrega, tal como figura en un paquete postal.

número_calle

Número de la calle (número de la casa) de entrega, tal como figura en un paquete postal.

Nota

Las ubicaciones no están obligadas a especificar todos estos campos, y también se les permite tener campos adicionales. Los renderizadores de contratos deben renderizar al menos los campos enumerados anteriormente, y deben renderizar los campos que no entiendan como una lista clave-valor.