# Eventos de reconciliación

Consulta el histórico de eventos para reconciliar tus webhooks con la API.

> [!WARNING]
> El SDK `vexor` de npm (Stripe, MercadoPago, PayPal, Square, Talo) está **deprecado**: ya no se mantiene y no debe usarse. vexorpay es hoy una **API REST de links de pago en USD sobre Polar (Merchant of Record), sin SDK oficial**. Migración: <https://developers.vexorpay.com/docs/migracion-desde-el-sdk>

Fuente: <https://developers.whop.vexorpay.com/docs/api/events>

`GET /api/v1/events` — histórico de eventos de negocio para reconciliar lo que recibiste por webhook con la API.

## Cómo funciona

Cada evento tiene un **id determinístico** (`evt_...`) que es **exactamente el mismo** que se envía firmado en los webhooks salientes (header `vexorpay-Event-Id`). Por eso puedes:

1. Recibir un webhook `payment.completed` con `evt_abc`.
2. Si tienes dudas o se perdió el POST, consultar `GET /api/v1/events` y encontrar el mismo `evt_abc`.
3. Deduplicar: procesar cada `evt_` una sola vez.

Los eventos de ventas de Polar (`payment.completed`, `payment.refunded`, `payment.disputed`) y de retiros de Polar (`payout.paid`) se pueden reconstruir desde la API en orden cronológico descendente.

> Los eventos de suscripciones (`subscription.*`), `payment.failed` y `dispute.resolved` existen como webhook pero **no** se materializan en este endpoint (solo se derivan de las ventas y los retiros). Aceptar esos `type` es válido, pero la respuesta viene vacía: para esos casos básate en el webhook.

## Request

`GET /api/v1/events`

### Parámetros

| Parámetro | Descripción |
| --- | --- |
| `type` | Filtro: cualquiera de los 11 tipos de evento (ver [Webhooks](/docs/api/webhooks)). En la práctica solo devuelve datos para `payment.completed`, `payment.refunded`, `payment.disputed` o `payout.paid`. |
| `created[gte]` / `created[lte]` | Rango de fecha del evento (ISO 8601). |
| `limit` / `starting_after` / `ending_before` | Paginación por cursor por id de evento (default 10, máximo 100). |

### Ejemplo

**curl**

```bash
curl "https://api.vexorpay.com/api/v1/events?type=payment.completed&limit=5" \
  -H "Authorization: Bearer vxp_live_tu_clave"
```

**Node.js**

```js
const res = await fetch(
  'https://api.vexorpay.com/api/v1/events?type=payment.completed&limit=5',
  {
    headers: { Authorization: 'Bearer vxp_live_tu_clave' },
  },
)

const data = await res.json()
```

**PHP**

```php
<?php

$client = curl_init(
  'https://api.vexorpay.com/api/v1/events?type=payment.completed&limit=5',
);
curl_setopt_array($client, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer vxp_live_tu_clave'],
]);

$data = json_decode(curl_exec($client), true);
```

**Python**

```python

response = requests.get(
    'https://api.vexorpay.com/api/v1/events',
    params={'type': 'payment.completed', 'limit': '5'},
    headers={'Authorization': 'Bearer vxp_live_tu_clave'},
)
data = response.json()
```

**Go**

```go
req, _ := http.NewRequest("GET", "https://api.vexorpay.com/api/v1/events?type=payment.completed&limit=5", nil)
req.Header.Set("Authorization", "Bearer vxp_live_tu_clave")

res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
```

### Respuesta exitosa

`200 OK`

```json
{
  "data": [
    {
      "id": "evt_6c2314a4fb4a408c07c2",
      "type": "payment.completed",
      "created": "2026-01-02T12:05:00.000Z",
      "sandbox": false,
      "data": {
        "object": {
          "charge": {
            "id": "67f1c1e2c8a4b0d1f2e3a4b5",
            "provider": "polar",
            "reference": "ORD-1001",
            "metadata": null,
            "polarOrderId": "59f4a98b-7034-437d-92b7-f463758ba69f",
            "polarCheckoutId": "8150f7d1-6404-48c2-8797-842e71a500ad",
            "amountCents": 1900,
            "currency": "usd",
            "status": "paid",
            "sandbox": false,
            "refundedCents": 0,
            "paidAt": "2026-01-02T12:05:00.000Z"
          },
          "payment_link": {
            "id": "66f1c1e2c8a4b0d1f2e3a4b5",
            "slug": "a1b2c3d4e5",
            "title": "Ebook UX en 30 días",
            "reference": "CATALOGO-UX"
          }
        }
      }
    }
  ],
  "has_more": false,
  "total_count": 1,
  "url": "/v1/events?limit=5"
}
```

El objeto dentro de `data.object` tiene **la misma forma** que el payload del webhook (`charge` + `payment_link`, o `payout`), más el campo `sandbox` —presente tanto en el evento raíz como dentro de `charge`—. `charge.id` es el id de la venta en [`GET /api/v1/orders/{id}`](/docs/api/orders), `amountCents` es el total que pagó el comprador y `refundedCents` lo reembolsado. `charge.reference` es tu referencia de la venta y `payment_link.reference` la del link. En `payout.paid`, `payout` es el retiro de Polar (misma forma que en [Retiros](/docs/api/payouts)).

## Errores

| Error | HTTP | Causa |
| --- | --- | --- |
| `validation_error` | 400 | `type` no es uno de los tipos de evento válidos. |
