Programa tu Webhook

Lo primero que debes hacer para utilizar webhooks en Fintoc es construir tu propio webhook endpoint. Construir un webhook endpoint es similar a construir cualquier endpoint de tu aplicación, sin embargo, creemos importante tomar en cuenta ciertas consideraciones antes de programar el endpoint.

Te recomendamos leer también nuestra guía de buenas prácticas al momento de implementar webhooks.

Consideraciones claves

Por cada evento que ocurra en Fintoc, se envía una petición HTTPs (POST) en formato JSON a los webhook endpoints registrados. Todo el detalle del evento se puede obtener al parsear el JSON recibido.

Como mínimo, tu webhook endpoint debe ser capaz de recibir peticiones POST, para obtener la información de un evento, y confirmar la recepción respondiendo con cualquier código HTTP perteneciente a la familia de estados exitosos (2xx).

Guardar el evento recibido

Cada evento que envía Fintoc posee un id único. Es importante guardar, por lo menos, el id correspondiente a cada evento en la base de datos de tu aplicación. De esta manera puedes asegurar idempotencia en los eventos recibidos.

Retornar 2xx rápidamente

Para confirmar que se recibió un evento correctamente, tu aplicación debe responder con un estado HTTP 2xx. Ante cualquier respuesta fuera de este rango, se considerará que el evento no fue recepcionado de manera correcta.

Si Fintoc no recibe un estado 2xx, reintentará notificar el evento. Después de múltiples días y fallos en la recepción de un evento, Fintoc dejará de notificar sobre ese evento a tu webhook endpoint.

Es de gran importancia retornar el estado de recepción del webhook lo más pronto posible. Cualquier lógica compleja de tu aplicación motivada por la recepción del webhook, deberá ser realizada de forma asíncrona. De esta manera, evitamos seguir notificando sobre eventos ya recibidos, pero que fallaron en responder por causa de un timeout.

Probar el webhook

Como las notificaciones al webhook endpoint ocurren solo bajo circunstancias específicas, es posible encontrar fallas en la recepción de un webhook cuando ya es demasiado tarde. Por esto, recomendamos siempre testear tus endpoints al:

  • Crear un webhook endpoint.
  • Registrar un webhook endpoint.
  • Después de realizar cualquier cambio que pueda afectar el webhook.

Código de ejemplo

require 'json'

# Using Sinatra
post '/webhook' do
  payload = request.body.read
  event = nil

  begin
    event = JSON.parse(payload)
  rescue JSON::ParserError => e
    # Invalid payload
    status 400
    return
  end
  
  # idempotency using sinatra-activerecord
  seen_event = WebhookEvent.find_by(fintoc_event_id: event['id'])
  if seen_event
    status 200
    return
  end
  
  # save new event for idempotency
  new_event = WebhookEvent.create!(
    fintoc_event_id: event['id'],
    type: event['type'],
    data: event['data']
  )

  # Handle the event
  case event['type']
  when 'link.credentials_changed'
    link_id = event['data']['id']
    # Then define and call a method to handle the event.
  when 'link.refresh_intent.succeeded'
    link_id = event['data']['refreshed_object_id']
    # Then define and call a method to handle the link refreshed event.
  when 'account.refresh_intent.succeeded'
    account_id = event['data']['refreshed_object_id']
    # Then define and call a method to handle the account refreshed event.
  # ... handle other event types
  else
    # Unexpected event type
    puts "Unhandled event type: #{event.type}"
  end

  status 200
end
import json
import os

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    event = None
    payload = request.data
    try:
        event = json.loads(payload)
    except:
        return jsonify(success=False)
      
    # Add idempotency using the ORM being used by your app.

    # Handle the event
    if event and event['type'] == 'link.credentials_changed':
        link_id = event['data']['id']
        # Then define and call a method to handle the ceredentilas changed event.
    elif event and event['type'] == 'link.refresh_intent.succeeded':
        link_id = event['data']['refreshed_object_id']
        # Then define and call a method to handle the link refreshed event.
    elif event and event['type'] == 'account.refresh_intent.succeeded':
        account_id = event['data']['refreshed_object_id']
        # Then define and call a method to handle the account refreshed event.
    # ... handle other event types
    else:
        # Unexpected event type
        print('Unhandled event type {}'.format(event['type']))
    return jsonify(success=True)
// This example uses Express to receive webhooks
const app = require('express')();

// Use body-parser to retrieve the raw body as a buffer
const bodyParser = require('body-parser');

app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => {
  const event = request.body;
  
  // Add idempotency using the ORM being used by your app.

  // Handle the event
  switch (event.type) {
    case 'link.credentials_changed':
      const linkId = event.data.id;
      // Then define and call a method to handle the ceredentilas changed event.
      break;
    case 'link.refresh_intent.succeeded':
      const linkId = event.data.id;
      // Then define and call a method to handle the link refreshed event.
      break;
    case 'account.refresh_intent.succeeded':
      const accountId = event.data.id;
      // Then define and call a method to handle the account refreshed event.
      break;
    // ... handle other event types
    default:
      // Unexpected event type
      console.log(`Unhandled event type ${event.type}`);
  }

  // Return a response to acknowledge receipt of the event
  response.json({received: true});
});

app.listen(8000, () => console.log('Running on port 8000'));

What’s Next