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

# Pruebas locales

> Como probar webhooks de SimplePay en desarrollo con tunnels HTTPS, raw body, firma HMAC, replays y casos Bookable de sandbox.

Para probar webhooks localmente, expone tu servidor con un tunnel HTTPS. En produccion SimplePay rechaza endpoints locales, privados o sin HTTPS.

## 1. Levanta tu handler

```bash terminal theme={"theme":{"light":"github-light","dark":"github-dark"}}
pnpm dev
# o
bun run dev
```

Ejemplo Express con raw body:

```ts server.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import express from "express";
import { verifySimplePayWebhook } from "./verify-simplepay-webhook";

const app = express();

app.post(
  "/webhooks/simplepay",
  express.raw({ type: "application/json" }),
  async (request, response) => {
    const rawBody = request.body.toString("utf8");

    verifySimplePayWebhook({
      rawBody,
      signatureHeader: request.header("SimplePay-Signature") ?? null,
      secret: process.env.SIMPLEPAY_WEBHOOK_SECRET!,
    });

    const event = JSON.parse(rawBody);
    await processSimplePayEvent(event);

    response.sendStatus(204);
  },
);

app.listen(3000);
```

## 2. Abre un tunnel HTTPS

Usa un tunnel HTTPS de desarrollo o tu herramienta equivalente:

```bash terminal theme={"theme":{"light":"github-light","dark":"github-dark"}}
dev-tunnel http 3000
```

Registra la URL publica:

```bash terminal theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -sS -X POST "https://api.simplepay.mx/v1/webhook_endpoints" \
  -H "Authorization: Bearer $SIMPLEPAY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: webhook_endpoint_dev_tunnel_v1" \
  -d '{
    "url": "https://dev-tunnel.example.com/webhooks/simplepay",
    "description": "Local development tunnel",
    "enabled_events": ["booking.confirmed", "booking.expired", "booking.cancelled"]
  }'
```

## 3. Crea un evento real

Para Hosted Checkout:

1. Crea una Checkout Session.
2. Completa el pago en sandbox.
3. Observa el POST al tunnel.

Para Bookable Payments:

1. Crea setup y booking checkout.
2. Completa o simula el resultado de pago.
3. Espera `booking.confirmed`, `booking.expired` o `booking.cancelled`.

## 4. Reintenta con replay

```bash terminal theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -sS -X POST "https://api.simplepay.mx/v1/events/spwevt_0123456789abcdef0123456789abcdef/replay" \
  -H "Authorization: Bearer $SIMPLEPAY_API_KEY"
```

## Casos que debes probar

<Steps>
  <Step title="Firma valida">
    Tu handler acepta payload firmado con timestamp reciente.
  </Step>

  <Step title="Firma invalida">
    Tu handler rechaza payload alterado o secret equivocado.
  </Step>

  <Step title="Timestamp viejo">
    Tu handler rechaza replay externo fuera de tolerancia.
  </Step>

  <Step title="Evento duplicado">
    Tu handler responde 2xx y no repite side effects.
  </Step>

  <Step title="Falla temporal">
    Tu handler puede fallar y luego procesar por replay sin romper consistencia.
  </Step>
</Steps>

## Simular firma en tests

```ts sign-test-payload.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import crypto from "node:crypto";

export function signTestPayload(payload: string, secret: string) {
  const timestamp = Math.floor(Date.now() / 1000);
  const signature = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${payload}`)
    .digest("hex");

  return `t=${timestamp},v1=${signature}`;
}
```

<Tip>
  Guarda fixtures de payloads reales de sandbox despues de remover datos
  sensibles. Son oro para tests de regresion.
</Tip>
