> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fintoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Crea tu endpoint de Webhook

Lo primero que debes hacer para usar los webhooks de Fintoc es construir tu propio endpoint de webhook. Construir un endpoint de webhook es similar a construir cualquier endpoint para tu aplicación, pero creemos que es importante tener algunas consideraciones en mente antes de empezar a escribir código.

También te recomendamos que leas nuestra [guía](/es/v2023-11-15/docs/resources/webhooks-walkthrough/webhooks-good-practices) sobre buenas prácticas para implementar webhooks.

# Consideraciones clave

Para cada evento que ocurre en Fintoc, se enviará una solicitud HTTP (POST) en formato JSON a cada endpoint de webhook registrado. Desde esa solicitud puedes parsear el detalle completo del evento usando el body en JSON.

Tu endpoint de webhook, entonces, debe ser capaz de recibir solicitudes POST, manejar la información del evento y luego responder con cualquier código de respuesta HTTP que pertenezca a la [familia de códigos de éxito](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success) (2XX).

## Guardar el evento recibido

Cada evento enviado por Fintoc como webhook tiene un `id` único. Es importante **al menos** guardar el `id` correspondiente a cada evento en la base de datos de tu aplicación. De esta forma puedes asegurar idempotencia en los eventos recibidos.

## Responder 2XX rápidamente

Para confirmar que un evento se recibió correctamente, tu aplicación debe responder con un código de estado HTTP 2XX. Cualquier respuesta con un código de estado distinto será considerada un intento fallido.

Si Fintoc no recibe un código de estado 2XX, intentaremos notificar el evento nuevamente. Después de múltiples días e intentos fallidos, Fintoc dejará de enviar el evento a ese endpoint de webhook.

Es muy importante que respondas con un código de estado 2XX lo más rápido posible. Cualquier lógica compleja en tu aplicación que se gatille por la recepción de un webhook debería ejecutarse de forma asíncrona. De esta manera, evitamos notificarte múltiples veces sobre eventos que ya fueron recibidos, pero que no lograron responder con un código 2XX debido a un *timeout* HTTP.

## Probar el webhook

Debido a que las notificaciones al endpoint de webhook ocurren solo bajo circunstancias específicas, es posible que algunos bugs en la recepción de un webhook pasen desapercibidos hasta que sea demasiado tarde. Por eso siempre recomendamos que pruebes tus endpoints al:

* Crear un endpoint de webhook
* Registrar un endpoint de webhook
* Realizar cualquier cambio que pueda afectar la recepción del webhook

# Código de ejemplo

```python theme={null}
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 credentials 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)
```

```ruby theme={null}
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
```

```javascript theme={null}
// 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'));
```
