# Crear link de pago único

Crea un link de pago único en dólares con la API de vexorpay.

> [!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.staging.vexorpay.com/docs/api/create-payment-link>

El link es reutilizable: puedes compartirlo con varios clientes y, si quieres un cobro único por pedido, usar el [checkout por compra](/docs/api/checkout).

Para cobrar de forma periódica (suscripciones/planes), usa la [creación de link recurrente](/docs/api/create-recurring-payment-link).

## Antes de empezar

El link cobra en **tu cuenta de cobro**: necesitas activarla desde el
dashboard (si no, la API responde `409 payment_account_not_ready`). Los links se pueden crear
con la verificación de identidad pendiente; para retirar el dinero hace falta completarla.

- El precio se fija en USD (mínimo USD 4). En el checkout, el comprador puede pagar en su
  moneda local o en USD.
- Cada venta paga la comisión de vexorpay, desde 2,7 % + USD 1 con el procesamiento incluido
  (ver [Cómo funcionan los cobros](/docs/como-funcionan-los-cobros)).
- Con una clave de prueba (`vxp_test_...`) contra `api.sandbox.vexorpay.com` el link se crea en
  sandbox y se paga con tarjetas de prueba.

Los links se editan con [`PATCH`](/docs/api/payment-links#actualizar-un-link), se
archivan con [`DELETE`](/docs/api/payment-links#eliminar-un-link) y se cobran con
[`checkout`](/docs/api/checkout), con las reglas que se explican en cada página.

## Request

`POST /api/v1/payment-links`

### Headers

| Header | Valor |
| --- | --- |
| `Authorization` | `Bearer vxp_live_tu_clave` |
| `Content-Type` | `application/json` |
| `Idempotency-Key` | opcional — para repetir sin duplicar |
| `Vexor-Account` | opcional — id del usuario conectado, para crear el link en su nombre ([cuentas conectadas](/docs/api/connected-accounts)) |

### Body

| Campo | Tipo | Requerido | Descripción |
| --- | --- | --- | --- |
| `amount` | number | **sí** | Monto en dólares. Mínimo USD 4. |
| `title` | string | **sí** | Título del producto: lo ve el comprador en el checkout y en el recibo. |
| `description` | string | no | Descripción del cobro. |
| `image_file_id` | string | no | Foto del producto. Debe ser un archivo tuyo (subido desde el dashboard). Se muestra en la página del link (`url`) y en el checkout. |
| `reference` | string | no | Referencia tuya (n° de orden, SKU…). Se incluye en las ventas y los webhooks para reconciliar. |
| `metadata` | object | no | Pares clave/valor libres que viajan con el link. |
| `type` | string | no | `one_time` (default). Ver [link recurrente](/docs/api/create-recurring-payment-link). |

### Ejemplo

**curl**

```bash
curl https://api.vexorpay.com/api/v1/payment-links \
  -X POST \
  -H "Authorization: Bearer vxp_live_tu_clave" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 19,
    "title": "Ebook UX en 30 días",
    "reference": "CATALOGO-UX",
    "metadata": { "categoria": "ebook" }
  }'
```

**Node.js**

```js
const res = await fetch('https://api.vexorpay.com/api/v1/payment-links', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer vxp_live_tu_clave',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 19,
    title: 'Ebook UX en 30 días',
    reference: 'CATALOGO-UX',
    metadata: { categoria: 'ebook' },
  }),
})

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

**PHP**

```php
<?php

$client = curl_init('https://api.vexorpay.com/api/v1/payment-links');
curl_setopt_array($client, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer vxp_live_tu_clave',
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'amount' => 19,
    'title' => 'Ebook UX en 30 días',
    'reference' => 'CATALOGO-UX',
    'metadata' => ['categoria' => 'ebook'],
  ]),
]);

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

**Python**

```python

response = requests.post(
    'https://api.vexorpay.com/api/v1/payment-links',
    headers={
        'Authorization': 'Bearer vxp_live_tu_clave',
        'Content-Type': 'application/json',
    },
    json={
        'amount': 19,
        'title': 'Ebook UX en 30 días',
        'reference': 'CATALOGO-UX',
        'metadata': {'categoria': 'ebook'},
    },
)
data = response.json()
```

**Go**

```go
body, _ := json.Marshal(map[string]any{
    "amount":    19,
    "title":     "Ebook UX en 30 días",
    "reference": "CATALOGO-UX",
    "metadata":  map[string]any{"categoria": "ebook"},
})

req, _ := http.NewRequest("POST", "https://api.vexorpay.com/api/v1/payment-links", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer vxp_live_tu_clave")
req.Header.Set("Content-Type", "application/json")

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

### Respuesta exitosa

`201 Created`

```json
{
  "id": "66f1c1e2c8a4b0d1f2e3a4b5",
  "amountCents": 1900,
  "currency": "usd",
  "title": "Ebook UX en 30 días",
  "description": null,
  "image": null,
  "reference": "CATALOGO-UX",
  "metadata": { "categoria": "ebook" },
  "status": "active",
  "slug": "a1b2c3d4e5",
  "sandbox": false,
  "url": "https://www.vexorpay.com/p/a1b2c3d4e5",
  "checkoutUrl": "https://…",
  "type": "one_time",
  "createdAt": "2026-01-02T12:00:00.000Z",
  "updatedAt": "2026-01-02T12:00:00.000Z"
}
```

`url` es la página pública del link: compártela (cada visita genera una referencia única para esa compra). `checkoutUrl` es el checkout alojado del link, sin referencia propia. Para una sesión de checkout por compra (con `reference`, email precargado o un plan puntual) usa [`POST /v1/payment-links/{id}/checkout`](/docs/api/checkout).

## Errores

| Error | HTTP | Causa |
| --- | --- | --- |
| `unauthorized` | 401 | Falta el header `Authorization`. |
| `invalid_key` | 401 | La API key es inválida o fue revocada. |
| `livemode_mismatch` | 403 | La clave no corresponde al host (clave de prueba contra producción o al revés). |
| `invalid_amount` | 400 | El monto es menor a USD 4 o no es un número válido. |
| `validation_error` | 400 | Falta el `title` (o está vacío). |
| `payment_account_not_ready` | 409 | Tu cuenta de cobro no está activada (o fue rechazada): actívala desde el dashboard. |
| `idempotency_conflict` | 409 | La `Idempotency-Key` ya se usó con un body distinto. |
| `rate_limited` | 429 | Superaste el límite de 100 requests por minuto. |
| `payment_link_failed` | 502 | El procesador de pagos rechazó la creación del link. No quedó nada publicado: reintenta. |
