# Entregables

Contenido privado que ve sólo quien compró un link (una nota o un link), y la redirección después del pago.

> [!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, sin SDK oficial**. Migración: <https://developers.vexorpay.com/docs/migracion-desde-el-sdk>

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

Un `deliverable` es contenido que le das a quien te compra: instrucciones, un código de
acceso, el link a tu curso o a tu agenda. Se adjunta a uno o varios links de pago con `deliverable_ids` y lo ve
**sólo el comprador**: en la confirmación del pago y en su portal de compras (`/billing`, donde entra con su
email y un código). El mail del recibo le lleva a ese portal.

- **Pago único**: el comprador lo ve para siempre, salvo que le reembolses todo el
  pago o pierdas una disputa. Un reembolso parcial no lo quita.
- **Suscripción**: lo ve mientras la suscripción siga vigente (también en cada renovación); cuando termina, deja
  de verlo.
- Si editas un entregable o agregas uno a un link, lo ven también
  quienes ya compraron. Si lo eliminas, deja de verse en todas las compras.

Cada venta trae en `access` si el comprador tiene acceso y qué entregables ve ([Ventas](/docs/api/orders)).

## El objeto Deliverable

```json
{
  "id": "6a1f0c2e9b1d4e0012ab34cd",
  "type": "note",
  "name": "Cómo acceder al curso",
  "note": "Entrá a cursos.ejemplo.com con tu email y el código CURSO-2026.",
  "url": null,
  "sandbox": false,
  "createdAt": "2026-11-05T12:00:00.000Z",
  "updatedAt": "2026-11-05T12:00:00.000Z"
}
```

| Campo | Descripción |
| --- | --- |
| `type` | `note` (texto privado, hasta 5000 caracteres), `url` (un link https) o `license_key` (una clave única por compra; ver [Claves de licencia](/docs/api/license-keys)). |
| `name` | El título que ve el comprador (hasta 100 caracteres). |
| `note` | El texto, si es `note`. |
| `url` | El link, si es `url`. El comprador lo podría compartir: para algo sensible, usa una nota con instrucciones de acceso. |

## Crear un entregable

`POST /api/v1/deliverables` (idempotente con `Idempotency-Key`)

```bash
curl https://api.vexorpay.com/api/v1/deliverables \
  -X POST \
  -H "Authorization: Bearer vxp_live_tu_clave" \
  -H "Content-Type: application/json" \
  -d '{ "type": "note", "name": "Cómo acceder al curso", "note": "Entrá a cursos.ejemplo.com con el código CURSO-2026." }'
```

Responde `201` con el entregable.

## Adjuntarlo a un link y redirigir después del pago

Al crear o editar un link (`POST /api/v1/payment-links` o `PATCH /api/v1/payment-links/{id}`):

| Campo | Descripción |
| --- | --- |
| `deliverable_ids` | Ids de tus entregables (hasta 10). En el PATCH reemplaza la lista; `null` o `[]` los quita. |
| `success_url` | URL https a la que va el comprador después de pagar. Admite `{ORDER_ID}` (id de la venta) y `{REFERENCE}`. `null` la quita. |

```bash
curl https://api.vexorpay.com/api/v1/payment-links/LINK_ID \
  -X PATCH \
  -H "Authorization: Bearer vxp_live_tu_clave" \
  -H "Content-Type: application/json" \
  -d '{ "deliverable_ids": ["6a1f0c2e9b1d4e0012ab34cd"], "success_url": "https://tu-sitio.com/gracias?orden={ORDER_ID}" }'
```

vexorpay confirma el pago antes de redirigir: si el link tiene entregables, el comprador los ve primero y sigue
con un botón; si no, lo llevamos a tu URL en unos segundos. **No des por pagada una compra porque alguien llegó a
tu `success_url`** (cualquiera puede escribir esa URL): confírmala con el webhook
`payment.completed` o con `GET /api/v1/orders/{ORDER_ID}`.

## Listar, ver, editar y eliminar

| Endpoint | Qué hace |
| --- | --- |
| `GET /api/v1/deliverables` | Tus entregables (hasta 200, los más nuevos primero). |
| `GET /api/v1/deliverables/{id}` | Un entregable. |
| `PATCH /api/v1/deliverables/{id}` | Cambia `name`, `note` o `url` (el `type` no cambia). |
| `DELETE /api/v1/deliverables/{id}` | Lo quita de tus links y de todas las compras. Responde `{ "id": "…", "deleted": true }`. |

## Quitar o devolver el acceso

`POST /api/v1/orders/{id}/access` con `{ "status": "revoked" }` le quita al comprador el acceso a los entregables de esa
compra (y revoca sus claves de licencia); con `"granted"` se lo devuelve, salvo que haya otro motivo para no tenerlo
(reembolso total, disputa perdida, suscripción terminada). Responde la [venta](/docs/api/orders) con `access`.

## Webhooks

`access.granted` y `access.revoked` avisan cada cambio del acceso de una compra, con el objeto `Access` en `data.object`
(`id`, `orderId`, `subscriptionId`, `paymentLinkId`, `customerEmail`, `status`, `revokedReason`, `deliverableIds`,
`licenseKeyIds`). Ver [Webhooks](/docs/api/webhooks).

## Llevar al cliente a su portal

`POST /api/v1/customer-portal-links` con `{ "customer_email": "ana@ejemplo.com" }` devuelve un link de 1 hora a su portal
de compras, **limitado a lo que te compró a vos** (su contenido, sus claves y sus suscripciones). Sirve para un botón
«Mis compras» en tu web. Si ese email no te compró nada responde `404 customer_not_found`.

## Errores

| Código | HTTP | Cuándo |
| --- | --- | --- |
| `validation_error` | 400 | Falta `type` o `name`, la nota o la URL no son válidas, o `deliverable_ids` trae un id que no es tuyo. |
| `not_found` | 404 | No existe ese entregable (o ya lo eliminaste). |
| `access_not_found` | 404 | `POST /orders/{id}/access` sobre una venta que no dio acceso (no se cobró o no es de un link). |
| `idempotency_conflict` | 409 | La `Idempotency-Key` ya se usó con un body distinto. |
