> ## 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 Webhook Endpoint

Lo primero que debes hacer para usar los webhooks de Fintoc es construir tu propio webhook endpoint. Construir un webhook endpoint 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 leer nuestra [guía](/es/docs/resources/webhooks-walkthrough/webhooks-good-practices) sobre buenas prácticas para implementar webhooks.

# Consideraciones clave

Por cada evento que ocurre en Fintoc, se enviará una solicitud HTTP POST con JSON a cada webhook endpoint registrado. A partir de esa solicitud, puedes parsear todo el detalle del evento usando el body JSON.

Tu webhook endpoint, 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 la idempotencia en los eventos recibidos.

## Devolver 2XX rápidamente

Para confirmar que un evento fue recibido exitosamente, tu aplicación debe responder con un código de estado HTTP 2XX. Cualquier respuesta con un código de estado distinto a ese será considerada un intento fallido.

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

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 disparada por la recepción de un webhook debe ejecutarse de forma asíncrona. De esta forma, evitamos notificarte múltiples veces sobre eventos que ya han sido recibidos, pero que no lograron responder con un código de estado 2XX debido a un *timeout* HTTP.

## Probar el webhook

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

* Creas un webhook endpoint
* Registras un webhook endpoint
* Realizas 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'));
```
