# Host-to-host (H2H): muestra el pago cripto en tu propia interfaz

> Muestra un pago de CryptoLike en tu pantalla: dirección, monto exacto, red, QR y plazo de la factura, elección de moneda por API y pedido confirmado por webhook.

Source: https://cryptolike.net/es/docs/h2h
Updated: 2026-10-18

Host-to-host (H2H) significa que tu servidor crea el pago con la API de CryptoLike y tu propia interfaz lo muestra: el pagador nunca abre una página de CryptoLike. Cada respuesta con la factura (invoice) trae lo que necesita la pantalla — la dirección, el monto exacto, la red, los datos del QR y el plazo de pago — y un webhook firmado le avisa a tu servidor cuando el pago está confirmado. Aquí verás cuándo elegir H2H, cómo es el flujo, qué debe mostrar la pantalla y qué hacer cuando el pagador envía de menos, de más o tarde.

## Cuándo elegir H2H, la página de pago o el widget

Las tres opciones muestran la misma factura, con los mismos estados y webhooks; cambia quién dibuja la pantalla de pago.

| Opción | Quién dibuja la pantalla | Elígela cuando | Qué construyes |
|---|---|---|---|
| Página de pago | CryptoLike, en `checkout_url` | Quieres el camino más corto: una redirección y un webhook | Una redirección desde tu backend |
| Widget de pago | CryptoLike, en un marco dentro de tu página | El cliente debe quedarse en tu flujo de compra, y la página de CryptoLike puede aparecer dentro | Tu origen en la lista permitida, un script y una regla de CSP |
| H2H | Tú | Una app para celular, un quiosco, un bot de mensajería o un flujo de compra que debe verse por completo como tu producto | La pantalla de pago con cada elemento de la lista de abajo |

La página de pago y el widget ya muestran la advertencia de red, el plazo, el estado en vivo y los textos para un pago insuficiente o vencido en inglés, ruso y español. Con H2H todo eso queda a tu cargo, así que empieza por la página de pago o el widget, salvo que tu interfaz tenga que ser del todo tuya. El widget se describe en la [guía del widget de pago](https://cryptolike.net/docs/widget).

## Cómo es el flujo

1. **Tu servidor crea la factura** — `POST /v1/invoices`, firmada con tu clave API y con el encabezado `Idempotency-Key`. Envía `coin_id` para fijar la moneda ahora; omítelo para que el pagador la elija en tu interfaz.
2. **Si la factura no tiene moneda, el pagador la elige.** Tu servidor lee `GET /v1/invoices/{id}/coin-options`, tu interfaz muestra las monedas y tu servidor fija la elección con `POST /v1/invoices/{id}/coin`.
3. **Tu interfaz muestra el pago** a partir de la respuesta con la factura: red, dirección, `payer_amount`, QR, cuenta regresiva hasta `ttl_expires_at` y estado.
4. **Tu servidor sigue el estado** con los webhooks `invoice.*` y, para el contador de confirmaciones, con `GET /v1/invoices/{id}`, no más de una vez cada pocos segundos. Tu página le pregunta a tu servidor, nunca a la API de CryptoLike.
5. **Tu servidor confirma el pedido** solo con un webhook `invoice.paid` verificado; después tu interfaz muestra la confirmación.

El secreto de la API se queda en tu servidor. El navegador o la app reciben solo lo que tu servidor decide mostrar y nunca firman solicitudes. La firma se explica en [autenticación](https://cryptolike.net/docs/auth).

## Crea la factura

La solicitud de abajo fija la moneda desde el inicio (USDT en TRON). Sin `coin_id`, la respuesta trae los campos de la moneda, `address` y el bloque de pago en `null` hasta la elección.

```http
POST /v1/invoices HTTP/1.1
Host: api.cryptolike.net
Content-Type: application/json
Idempotency-Key: order-10042
X-API-Key: <key_id>
X-Timestamp: <unix seconds>
X-Signature: <HMAC-SHA256 of the request>

{"amount": "49.90", "currency": "USD", "coin_id": "6f1c2a3e-8d4b-4c5a-9e7f-0a1b2c3d4e5f", "order_id": "10042", "description": "Order #10042 — annual plan", "ttl_seconds": 1800, "fee_paid_by": "merchant"}
```

La respuesta es la factura (valores de ejemplo de la referencia de la API):

```json
{
  "id": "4e2bc88c-cb79-4afc-b864-c1ba8e9d50c9",
  "status": "new",
  "currency": "USD",
  "amount": "49.90",
  "coin_id": "6f1c2a3e-8d4b-4c5a-9e7f-0a1b2c3d4e5f",
  "ticker": "USDT",
  "network": "tron",
  "address": "TXYZopYRdj2D9XRtbG411XZZ3kM5VW9t7g",
  "amount_crypto": "49.90",
  "payer_amount": "49.90",
  "paid_amount": "0",
  "remaining_amount": "49.90",
  "overpaid_amount": "0",
  "amount_fiat": "49.90",
  "fiat_currency": "USD",
  "rate_locked": "1.0004",
  "rate_locked_at": "2026-09-16T12:00:00Z",
  "late_payment": false,
  "fee_paid_by": "merchant",
  "order_id": "10042",
  "description": "Order #10042 — annual plan",
  "return_url": null,
  "webhook_url": null,
  "metadata": null,
  "allowed_coin_ids": null,
  "checkout_url": "https://cryptolike.net/pay/4e2bc88c-cb79-4afc-b864-c1ba8e9d50c9",
  "ttl_expires_at": "2026-09-16T12:30:00Z",
  "expired_at": null,
  "created_at": "2026-09-16T12:00:00Z",
  "updated_at": "2026-09-16T12:00:00Z",
  "payment_uri": "tron:TXYZopYRdj2D9XRtbG411XZZ3kM5VW9t7g?amount=49.9&token=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "qr_payload": "TXYZopYRdj2D9XRtbG411XZZ3kM5VW9t7g",
  "confirmations": null,
  "required_confirmations": 20
}
```

Los campos que usa tu pantalla:

- `payer_amount` y `ticker` — exactamente lo que el pagador debe enviar. Con `fee_paid_by: payer` la comisión de la plataforma ya está incluida, así que `payer_amount` es mayor que `amount_crypto`; muestra `payer_amount`, nunca `amount` ni `amount_crypto`. Las comisiones están en la página de [precios](https://cryptolike.net/es/pricing).
- `network` — `btc`, `ltc`, `eth` o `tron`. Un mismo ticker puede estar en dos redes (USDT en TRON y en Ethereum), y la red decide a dónde envía el pagador.
- `address` — la dirección de depósito de esta factura.
- `payment_uri` — un enlace que abre la billetera con la dirección y el monto que falta pagar: BIP-21 en Bitcoin y Litecoin, EIP-681 en Ethereum y un enlace `tron:` en TRON.
- `qr_payload` — lo que va en el código QR: solo la dirección en todas las redes, sin el monto. Muchos pagadores envían desde un exchange, y el formulario de retiro de un exchange acepta solo una dirección. Si quieres un «QR con monto» para billeteras, ofrécelo como interruptor en Bitcoin y Litecoin y codifica ahí `payment_uri`.
- `ttl_expires_at` — el plazo de pago. Lo define `ttl_seconds`, de 60 segundos a 30 días; sin él se aplica la configuración de tu cuenta (30 minutos por defecto). Para un precio en USD u otra moneda fiat, el tipo de cambio de `rate_locked` queda fijo hasta ese momento.
- `confirmations` y `required_confirmations` — el contador de confirmaciones; `confirmations` es `null` mientras no llega nada.

Guarda cada monto como la cadena que devuelve la API: no lo redondees ni lo conviertas a un número de punto flotante.

## Deja que el pagador elija la moneda en tu interfaz

Para una factura creada sin `coin_id`, la lista de monedas y la elección pasan por dos llamadas: la misma lista y la misma operación que en la página de pago.

```http
GET /v1/invoices/4e2bc88c-cb79-4afc-b864-c1ba8e9d50c9/coin-options
```

```json
{
  "coin_options": [
    { "coin_id": "6f1c2a3e-8d4b-4c5a-9e7f-0a1b2c3d4e5f", "ticker": "USDT", "name": "Tether USD", "network": "tron", "network_name": "TRON",
      "decimals": 6, "confirmations": 20, "estimated_amount": "49.90", "rate_as_of": "2026-09-16T12:00:03Z",
      "estimate_reason": null, "estimate_message": null },
    { "coin_id": "a01d6e2b-3c4f-4a5b-8c7d-9e0f1a2b3c4d", "ticker": "BTC", "name": "Bitcoin", "network": "btc", "network_name": "Bitcoin",
      "decimals": 8, "confirmations": 2, "estimated_amount": null, "rate_as_of": null,
      "estimate_reason": "rate_stale",
      "estimate_message": { "key": "checkout.estimate.rate_stale", "default": "The exchange rate is updating. Choose this currency to see the exact amount." } }
  ]
}
```

- Muestra `network_name` junto a cada ticker y `estimated_amount` con el signo `≈`: es una estimación. Cuando es `null`, muestra en su lugar el texto de `estimate_message`; la moneda se puede elegir igual.
- La lista incluye solo las monedas que ofreces para facturas y que corresponden a la moneda de la factura, reducidas a `allowed_coin_ids` cuando la factura los tiene; las monedas en mantenimiento quedan fuera.
- Si la moneda ya está elegida, la llamada responde `409` con `details.coin_id`, y la factura ya tiene la dirección.

Fija la elección desde tu servidor, con un `Idempotency-Key`:

```http
POST /v1/invoices/4e2bc88c-cb79-4afc-b864-c1ba8e9d50c9/coin HTTP/1.1
Content-Type: application/json
Idempotency-Key: order-10042-coin

{"coin_id": "6f1c2a3e-8d4b-4c5a-9e7f-0a1b2c3d4e5f"}
```

La respuesta es la factura con `address`, `payer_amount`, `payment_uri`, `qr_payload` y `ttl_expires_at`, con la misma forma que arriba. La elección vuelve a calcular el monto y fija el tipo de cambio, así que muestra el `payer_amount` de esta respuesta y no la estimación. Rechazos: `400` con `details.field: coin_id` para una moneda fuera de las opciones; `409` cuando ya hay una moneda elegida (aunque sea la misma) o la factura ya no está en `new`; `503` cuando el tipo de cambio o una dirección nueva no están disponibles en ese momento: espera unos segundos y envía la misma solicitud. Una repetición con el mismo `Idempotency-Key` devuelve la primera respuesta. La moneda se elige una sola vez; si el pagador también tiene abierta la página de pago, esta cambia al pago de inmediato.

## Qué debe mostrar tu pantalla de pago

Estos elementos están en la página de pago de CryptoLike; tu pantalla necesita cada uno.

| Elemento | Campo | Por qué |
|---|---|---|
| La red con su nombre y, para un token, el estándar (TRON, TRC20) | `network`, `ticker` | El mismo ticker y el mismo formato de dirección existen en varias redes |
| Advertencia de red equivocada junto a la dirección | `ticker`, `network` | «Envía a esta dirección solo USDT en la red TRON. Los fondos enviados por otra red no se pueden recuperar.» |
| La dirección, con botón para copiar | `address` | El pagador la pega en su billetera; los fondos enviados a una dirección mal escrita no se pueden recuperar |
| El monto exacto, con botón para copiar | `payer_amount`, `ticker` | Una transferencia menor al monto se vuelve un pago insuficiente |
| El código QR, con el monto escrito al lado | `qr_payload` | El QR lleva solo la dirección en todas las redes |
| Un enlace «Abrir en la billetera» | `payment_uri` | Un toque en un teléfono que tiene billetera instalada |
| El tiempo restante | `ttl_expires_at` | Después la factura vence, y una transferencia posterior es un pago tardío |
| El estado, con las confirmaciones mientras espera | `status`, `confirmations`, `required_confirmations` | «Pago detectado, 3 de 20 confirmaciones» le indica al pagador que no envíe dos veces |
| La pantalla de resultado | `status`, `paid_amount`, `remaining_amount` | Pagado, pago insuficiente con el monto restante, vencido o cancelado, cada uno con el siguiente paso |

Lleva la cuenta regresiva con el reloj de tu servidor, no con el del dispositivo del pagador. Cuando llegue a cero, oculta la dirección y el QR y ofrece crear un pago nuevo. Los estados son `new`, `pending`, `paid`, `underpaid`, `expired` y `cancelled`; el artículo sobre [confirmaciones](https://cryptolike.net/es/glossary/confirmations) explica por qué una transferencia espera antes de contar.

## Pago insuficiente, pago excedente y pago tardío

- **Pago insuficiente.** Una transferencia confirmada menor a `payer_amount` pasa la factura a `underpaid` y envía `invoice.underpaid`; una diferencia dentro de la tolerancia de pago insuficiente de tu cuenta igual cuenta como `paid`. La factura sigue abierta para completar el pago en la misma dirección hasta `ttl_expires_at`: muestra `remaining_amount` y el `payment_uri` actualizado, que ahora pide el resto. Después del plazo el pago insuficiente es definitivo; pídele al pagador que te contacte. Más en [pago insuficiente](https://cryptolike.net/es/glossary/underpaid-payment).
- **Pago excedente.** El estado es `paid` con `overpaid_amount` mayor que cero; lo trae `invoice.paid`, que vuelve a llegar cuando otra transferencia lo aumenta. Todo el monto se acredita a tu saldo; arregla la diferencia con el cliente.
- **Pago tardío.** Una transferencia confirmada después de que la factura se cerró (`expired`, `cancelled` o un `underpaid` definitivo) igual se acredita a tu saldo: la factura recibe `late_payment: true`, te llega `invoice.late_payment` y el estado no cambia. Pasa también cuando una transferencia ya se detectó pero aún no se confirmó al vencer el plazo: la factura vence y la transferencia llega como pago tardío. Decide si entregas el pedido o devuelves el dinero. Más en [pago vencido](https://cryptolike.net/es/glossary/expired-payment).
- **Reverso.** Si una reorganización de la red elimina una transferencia confirmada, recibes `invoice.reverted` con los montos recalculados. Detén la entrega hasta que llegue un nuevo `invoice.paid`.

## Confirma el pedido solo con el webhook

Entrega un pedido cuando tu servidor recibe `invoice.paid` con una [firma de webhook](https://cryptolike.net/es/glossary/webhook-signature) válida, no cuando el pagador presiona «Ya pagué» ni por un estado que vio tu página. La entrega es al menos una vez: guarda `event_id`, responde `2xx` en menos de 10 segundos y omite las repeticiones. Los webhooks son los mismos para H2H, la página de pago y el widget, y no traen `payment_uri`, `qr_payload` ni el contador de confirmaciones; cuando los necesites, lee `GET /v1/invoices/{id}`. Los tipos de evento, los reintentos y un vector de prueba están en la [referencia de webhooks](https://cryptolike.net/docs/webhooks).

Antes del lanzamiento, haz en una red de prueba un pago por cada caso: pagado, pago insuficiente y luego completado, vencido y una transferencia tardía. Cómo conseguir una clave de prueba y monedas de prueba: [pagos cripto de prueba](https://cryptolike.net/es/guides/test-crypto-payments).

## Preguntas frecuentes

### ¿Necesito el widget para H2H?

No. Con H2H tu interfaz dibuja la pantalla con los campos de la factura, y en el navegador del pagador no se carga nada de CryptoLike. El widget es la otra opción: la página de pago de CryptoLike dentro de un marco en tu flujo de compra.

### ¿Puedo enviar igual al pagador a la página de pago?

Sí. Cada factura tiene `checkout_url`, y la página de pago muestra la misma factura. Una moneda elegida por API cambia de inmediato una página abierta al pago, así que puedes ofrecer la página como alternativa, por ejemplo a un pagador que tiene la billetera en otro dispositivo.

### ¿H2H cambia los webhooks?

No. Los eventos, la firma y los reintentos son los mismos que con la página de pago. El bloque de pago de la factura — `payment_uri`, `qr_payload`, `confirmations` y `required_confirmations` — no viene en el cuerpo del webhook; lee la factura con `GET /v1/invoices/{id}`.

### ¿Qué monto envía el pagador cuando él paga la comisión?

`payer_amount`. Con `fee_paid_by: payer` ya incluye la comisión de la plataforma, y `amount_crypto` es lo que recibes tú. Muestra `payer_amount` y guárdalo como la cadena que devuelve la API.
