La .NET CONF 2024 acaba de terminar. Descubre las NOVEDADES de .NET 9 junto a los CAMBIOS que trae C# 13.
Puedes ver el contenido de este vídeo junto con su curso en el modo vídeo (similar a Udemy) si pulsas aquí.

Webhooks en Stripe

Este postes el Segundo de un curso completo y gratuito sobre Stripe, el cual está disponible tanto esta misma web así como en YouTube.

Tanto el curso como el código del mismo estan disponibles de forma abierta y gratuita, si te gusta el contenido ya sabes que puedes apoyar a la web haciendote premium, o comprando mi libro.

En el vídeo de YouTube, el contenido de este post incia en el minuto 79:50.

 

 

La forma en la que Stripe nos notifica que un pago ha sido realizado con éxito es a través de webhooks.

 

1 - Qué es un Webhoook?

Un webhook no es más que una llamada HTTP que Stripe va a realizar desde su servidor al nuestro. En este caso es una llamada directa de un servidor al otro, no una redirección como en la confirmación del pago, y esto es importante porque Stripe no puede llamar directamente desde su servidor a tu máquina local. 

 

Para testear en local, lo que tenemos que hacer es utilizar la CLI de stripe;

 

 

2 - La CLI de Stripe

 

La CLI o command line interface de Stripe es una herramienta que nos permite realizar las acciones que normalmente realizaríamos en la api, pero no solo eso, también nos permite ejecutar eventos para testear los webhooks, y eso es lo que vamos a hacer aquí. 

 

Todo lo que voy a contar en este punto esta en la documentación oficial;

 

Asumiendo que estas en windows te tienes que bajar de github el fichero stripe.exe e incluir la ruta donde está dentro de la variable de entorno Path, en mi caso he puesto el ejecutable dentro de `C:\Program Files\Stripe`.

 

Y ahora lo que tenemos que hacer es loguearnos.

Si hacemos stripe login, va a hacer login en la cuenta normal, si lo que queremos es loguearnos en la cuenta de test, tenemos que mandar la api key de test con el comando

stripe login --api-key {sk_test_…..}

No hay forma que podamos comprobar algo así como una comando que te diga si estamos en test, pero lo que yo hago es comparar los balances, con el comando stripe balance retrieve te indica si estás en modo producción o no. 

 

stripe cli example

Una cosa a tener en cuenta de Stripe es que los precios son en la menor moneda posible dentro de tu moneda, por ejemplo en euros tenemos euros y céntimos, las cantidades que muestra stripe son en céntimos, por lo que ese 929 en verdad es 9.29€. 

 

 

3 - Escuchar webhooks de stripe

 

Una vez tenemos la CLI configurada ahora tenemos que conectarla a nuestra aplicación. 

 

Para nuestro caso en concreto vamos a utilizar el comando listen de la CLI, este comando escucha a eventos que pasan en Stripe (recuerda, esta conectada) y le tenemos que especificar que evento queremos escuchar, en nuestro caso es un checkout.session.completed y después le diremos a la CLI que mande ese evento a una URL en concreto, en nuestro caso, a la url en local que tenemos que crear, el comando es el siguiente:

stripe listen -e checkout.session.completed --forward-to https://localhost:7265/api/webhook --latest

 

Y es importante que lo creemos antes de ejecutar nuestro código pues el comando nos devuelve un código, este código es un secret, similar al de la API pero para el webhook, de esta forma nos aseguramos que es stripe quién está llamando a nuestra y no un actor malicioso.

Este código en producción lo tienes en la interfaz de stripe y es un código secreto que no debes compartir con nadie. En el entorno local da igual pues nadie puede acceder a él. 

 

Lo qu eel comando listen hace es permitir a la CLI que re-envie los eventos que sucedan desde el sistema de Stripe a la aplicación en local, para ello debemos crear el endpoint que hemos indicado en el forward. 

namespace StripeCourse.Controllers.Api;

[Route("api/[controller]")]
[ApiController]
public class WebhookController : ControllerBase
{


	[HttpPost]
	public async Task Post()
	{
	}
}

Así únicamente estamos creando el endpoint, pero debemos leer el propio mensaje. 

 

 

NOTA: Antes de continuar quiero hacer un parón aquí, vamos a escuchar al evento  checkout.session.completed, el cual se completa al hacer un pago en el checkout de stripe, si utilizas la API o incluso Stripe elements, este evento no se genera, por lo que hay que escuchar payment_intent.succeeded; Técnicamente puedes escuchar siempre este segundo, pero payment_intent.succeeded no contiene información del usuario que ha realizado la compra, mientras que checkout.session.completed si lo hace, lo cual puede ser muy importante si lo que estás vendiendo es un bien digital como podría ser un libro, además, Stripe recomienda escuchar a checkout.session.completed

 

[HttpPost]
public async Task<IActionResult> Post()
{
	var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
	try
	{
		Event? stripeEvent = EventUtility.ConstructEvent(json,
				Request.Headers["Stripe-Signature"], configuration["StripeWebhookSecret"]);  

		// Handle the event
		switch (stripeEvent.Type)
		{
			case Events.CheckoutSessionCompleted:
					HandleSessionCompleted(stripeEvent.Data.Object as Session);
				break;
			default:
				Console.WriteLine("Unhandled event type: {0}", stripeEvent.Type);
				break;
		}
		return Ok();
	}
	catch (StripeException e)
	{
		return BadRequest();
	}
}

public void HandleSessionCompleted(Session checkoutSession)
{
	Console.WriteLine("Session Completed Event");
	Console.WriteLine($"By user: {checkoutSession.CustomerDetails.Name} ({checkoutSession.CustomerDetails.Email})");

	var options = new SessionGetOptions();
	options.AddExpand("line_items");
	var service = new SessionService();
	Session sessionWithLineItems = service.Get(checkoutSession.Id, options);
	Console.WriteLine("Items:");
	foreach (var item in sessionWithLineItems.LineItems)
	{
		Console.WriteLine($"PriceId: {item.Price.Id} - Quantity: {item.Quantity}");
	}

	Console.WriteLine("In production this will lookup the id from the " +
		"stripePaymentID and send them by email, create an order, etc");
}

 

Aquí tenemos bastante que explicar, Stripe manda la información como post así que tenemos que leer el body para leer el contenido, el cual vamos a leer como string y convertirlo en un Evento de Stripe, para ello además validamos que el evento viene de stripe con el header “Stripe-Signature” y el secret que nos ha dado la CLI. 

 

Posteriormente como únicamente tenemos un solo endpoint para el webhook lo que hacemos es validar el tipo de evento y actuar conforme al mismo. 

 

En nuestro caso solo vamos a comparar si es un evento de “checkout.session.completed” y tenemos un handler, que si bien no va a mandar el libro por correo (pues no esta el sistema de correo configurado), vemos cómo accedemos a todos los datos que necesitamos.

 

 

Una vez tenemos todo corriendo, podemos ejecutar la aplicación y al realizar el pago veremos como la CLI es capaz de leer el evento y mandarlo a nuestra aplicación en local:

Ejemplo CLI stripe

Para finalizar este punto, Stripe permite reenviar un evento con stripe events resend evt_…. Lo cual puede ser muy útil si no tienes la CLI bien configurada o cualquier bug en el códgo, ya que puedes enviar el mismo evento tantas veces como quieras, lo que te permite debuguear sin tener que realizar todo el proceso.

Si eliminas la opción -e del comando listen, escucharás todos los eventos que sucedan en el sistema, y la CLI los mandará todos al código, aunque únicamente vayamos a reaccionar a uno de ellos. 

 

 

4 - Webhoooks en producción

 

Ya que aquí no estamos viendo el funcionamiento en producción es importante mencionar que para que se envíen los eventos tienes que especificarlo en stripe.

webhook production stripe

 

Y no solo eso, sino que además tienes que especificar qué eventos quieres escuchar para que te los envíen.

 


Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2024 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café