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

# Ligas de pago

> URLs de pago compartibles, de un solo uso o reutilizables, sin necesidad de conocer al deudor.

Una **liga de pago** (`PaymentLink`) es una **URL pública de pago** que puedes compartir sin conocer al deudor de antemano. Cuando alguien paga, TapiPay genera internamente una [deuda](/es/recursos/deudas) por ese pago.

**Cuándo usarla:** cobros sin padrón de deudores (donaciones, ventas sueltas, links de checkout por WhatsApp o email), donde conoces al pagador en el momento del pago, no antes. Si ya conoces al deudor, una [deuda](/es/recursos/deudas) suele ser mejor.

## Dos modos de uso

<CardGroup cols={2}>
  <Card title="Un solo uso" icon="ticket">
    `singleUse: true` (default). Genera una deuda con el primer pago y se desactiva. Ideal para una factura o venta puntual.
  </Card>

  <Card title="Reutilizable" icon="infinity">
    `singleUse: false`. Se crea sin deudor y acepta múltiples pagos mientras siga activa. Modo donaciones o pasarela de pagos.
  </Card>
</CardGroup>

## Crear una liga

Lo mínimo es el monto y una descripción visible en la página de pago.

```bash theme={null}
curl --request POST \
  --url 'https://tapipay-facade.dev.tapila.cloud/payment-links' \
  --header 'x-api-key: TU_API_KEY' \
  --header 'x-authorization-token: TU_TOKEN_TAPI' \
  --header 'Content-Type: application/json' \
  --data '{
    "externalPaymentLinkId": "LINK-DONACION-01",
    "amount": 500.00,
    "currency": "MXN",
    "description": "Donación campaña 2026",
    "expiresAt": "2026-12-31T23:59:59Z",
    "singleUse": false
  }'
```

### Campos principales

<ResponseField name="amount" type="number" required>
  Monto en **pesos**, con hasta 2 decimales (mínimo `0.01`).
</ResponseField>

<ResponseField name="description" type="string" required>
  Descripción visible en la página de pago.
</ResponseField>

<ResponseField name="externalPaymentLinkId" type="string">
  Llave natural de la liga. Opcional, pero si la envías debe ser única por organización (un duplicado devuelve `409 RESOURCE_CONFLICT`).
</ResponseField>

<ResponseField name="singleUse" type="boolean" default="true">
  `true` se desactiva tras el primer pago; `false` acepta múltiples pagos.
</ResponseField>

<ResponseField name="identifierValue" type="string">
  Identificador propio para la URL (opcional). Se sanea a un formato seguro para URL (minúsculas, alfanuméricos y guiones, máximo 64 caracteres). Si tras sanear queda vacío, devuelve `400 INVALID_REQUEST`.
</ResponseField>

<ResponseField name="expiresAt" type="string" required>
  Fecha y hora de expiración (ISO 8601). Debe ser futura. Es obligatoria.
</ResponseField>

<ResponseField name="successUrl" type="string">
  URL de redirección al completar el pago. Si no la envías, se usa la página de Tapi.
</ResponseField>

También acepta `currency`, `productName` y `metadata`.

## El `identifierValue` y la URL de pago

El `paymentUrl` siempre viene en la respuesta. Cómo se arma el `identifierValue` depende de si la liga tiene un deudor conocido:

<Tabs>
  <Tab title="Sin deudor conocido">
    Es el caso típico de una liga. El `identifierValue` **se expone** en la respuesta y es el segmento final de la `paymentUrl`, así que puedes correlacionarlo sin parsear la URL.

    * Si enviaste `identifierValue`, se usa tu valor saneado.
    * Si no, TapiPay genera uno **sintético** con el formato `{3letras}-{aleatorio}` (las 3 letras salen del nombre de tu organización; por ejemplo, "Acme Corp" produce `acm-x3kM9pQr`).

    ```json theme={null}
    {
      "data": {
        "paymentLinkId": "plk_7nS9uV3d",
        "status": "ACTIVE",
        "amount": 4500.00,
        "currency": "MXN",
        "description": "Factura única #777",
        "singleUse": true,
        "identifierValue": "acm-x3kM9pQr",
        "paymentUrl": "https://app.tapipay.la/s/acme-corp/portal/acm-x3kM9pQr/",
        "createdAt": "2026-06-03T19:20:00Z"
      },
      "requestId": "req_a1b2c3d4"
    }
    ```
  </Tab>

  <Tab title="Con deudor conocido">
    Si creas la liga con `externalClientId` o `contactData`, el identificador interno es el del deudor y **se omite** de la respuesta para no exponer datos personales (PII-safe). El `paymentUrl` puede venir resuelto o `null` si no puede generarse de forma segura.
  </Tab>
</Tabs>

## Ciclo de vida

```mermaid theme={null}
stateDiagram-v2
    [*] --> ACTIVE
    ACTIVE --> PAID: pago (si singleUse)
    ACTIVE --> EXPIRED: vence expiresAt
    ACTIVE --> CANCELLED: cancelación
    PAID --> [*]
    EXPIRED --> [*]
    CANCELLED --> [*]
```

| Estado      | Significado                                                   |
| ----------- | ------------------------------------------------------------- |
| `ACTIVE`    | Disponible para recibir pagos.                                |
| `PAID`      | Pagada. Aplica a ligas `singleUse: true` tras el primer pago. |
| `EXPIRED`   | Superó `expiresAt`. Ya no acepta pagos.                       |
| `CANCELLED` | Cancelada manualmente. Estado final.                          |

<Note>
  Una liga reutilizable (`singleUse: false`) permanece `ACTIVE` y acumula pagos. Cada pago genera una deuda interna; los consultas con `GET /payment-links/{id}/payments`.
</Note>

## Actualizar sin invalidar la URL

`PATCH /payment-links/{id}` permite cambiar `description`, `expiresAt` y `metadata` **sin cambiar el `paymentUrl`**: la liga sigue accesible desde la misma URL. El `amount`, la `currency` y `singleUse` **no** son modificables (intentarlo devuelve `400 INVALID_REQUEST`).

## Endpoints

| Método  | Ruta                           | Descripción                                        |
| ------- | ------------------------------ | -------------------------------------------------- |
| `POST`  | `/payment-links`               | Crear una liga.                                    |
| `GET`   | `/payment-links/{id}`          | Consultar una liga.                                |
| `GET`   | `/payment-links`               | Listar ligas.                                      |
| `PATCH` | `/payment-links/{id}`          | Actualizar `description`, `expiresAt`, `metadata`. |
| `POST`  | `/payment-links/{id}/cancel`   | Cancelar.                                          |
| `GET`   | `/payment-links/{id}/payments` | Listar los pagos recibidos.                        |

<Card title="Pruébalo en el API Reference" icon="play" href="/api-reference">
  Explora cada endpoint con su playground interactivo.
</Card>
