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

Construye un webhook endpoint para recibir y procesar eventos de Fintoc. Un webhook endpoint funciona como cualquier otro endpoint de tu aplicación, con consideraciones adicionales de entrega y reintentos.

Revisa las [Buenas prácticas con webhooks](/es/guides/resources/webhooks-walkthrough/webhooks-good-practices) antes de implementar tu endpoint.

## Consideraciones clave

Cuando ocurre un evento, Fintoc envía una solicitud `POST` con un body JSON a cada webhook endpoint registrado. Analiza el body JSON para acceder al detalle del evento.

Tu webhook endpoint debe procesar la solicitud `POST` y devolver un código de estado dentro del rango `2xx`.

### Guarda el evento recibido

Cada evento de webhook enviado por Fintoc tiene un `id` único. Guarda el `id` de cada evento en la base de datos de tu aplicación. Usa el `id` guardado para detectar entregas duplicadas y procesar cada evento una sola vez.

### Devuelve un código de estado `2xx` antes del timeout

Para confirmar la recepción de un evento, responde con un código de estado HTTP `2xx`. Fintoc trata cualquier otro código de estado como un intento fallido.

Responde con un código de estado `2xx` antes de que expire el timeout de entrega de Fintoc. Ejecuta de forma asíncrona la lógica que no necesita completarse antes de la confirmación, para que el handler responda antes del timeout.

### Maneja los reintentos y las entregas fallidas

Fintoc trata una entrega como un **intento fallido** si tu endpoint responde con cualquier código de estado fuera del rango `2xx` o si la solicitud excede el timeout.

Cuando una entrega falla, Fintoc la reintenta automáticamente usando **backoff exponencial**, comenzando 3 segundos después del intento fallido. Fintoc realiza **hasta 17 reintentos** por cada evento.

Si todos los intentos fallan, Fintoc deja de reintentar ese evento. Se aplican las siguientes limitaciones:

* Fintoc **no** deshabilita el webhook endpoint automáticamente ni te notifica cuando deja de reintentar un evento.
* Fintoc **no** ofrece reenvío manual ni un mecanismo de dead-letter para reenviar un evento fallido.

Fintoc puede entregar el **mismo evento más de una vez**, por lo que tu endpoint debe ser idempotente. Para manejar eventos duplicados, revisa [Evita la duplicación de eventos](/es/guides/resources/webhooks-walkthrough/webhooks-good-practices#evita-la-duplicación-de-eventos).

### Prueba el webhook

Fintoc envía eventos de webhook solo cuando ocurre la acción subyacente. Por eso, un bug en el handler puede pasar desapercibido hasta que el endpoint recibe tráfico de producción. Prueba tu endpoint cuando lo crees, lo registres o cambies la forma en que recibe eventos.

Para conocer el procedimiento de prueba paso a paso, incluyendo cómo exponer tu endpoint local y enviar un evento de prueba, revisa [Prueba tu webhook endpoint](/es/guides/resources/webhooks-walkthrough/webhooks-testing).

## Código de ejemplo

**Manejador de webhooks (Python)**

```python theme={null}
import json

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    payload = request.data
    try:
        event = json.loads(payload)
    except (json.JSONDecodeError, UnicodeDecodeError):
        return jsonify(received=False), 400

    if not isinstance(event, dict) or 'type' not in event:
        return jsonify(received=False), 400

    # Add idempotency with your app's ORM.

    # Handle the event
    if event['type'] == 'link.credentials_changed':
        link_id = event['data']['id']
        # Then define and call a method to handle the credentials changed event.
    elif 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['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(received=True)
```

**Manejador de webhooks (Node.js)**

```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) => {
  let event;
  try {
    event = JSON.parse(request.body);
  } catch {
    return response.status(400).json({ received: false });
  }

  if (!event || typeof event !== 'object' || typeof event.type !== 'string') {
    return response.status(400).json({ received: false });
  }

  // Add idempotency with your app's ORM.

  // Handle the event
  switch (event.type) {
    case 'link.credentials_changed': {
      const linkId = event.data.id;
      // Define and call a method to handle the credentials changed event.
      break;
    }
    case 'link.refresh_intent.succeeded': {
      const linkId = event.data.refreshed_object_id;
      // Define and call a method to handle the link refreshed event.
      break;
    }
    case 'account.refresh_intent.succeeded': {
      const accountId = event.data.refreshed_object_id;
      // 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'));
```
