QvaPay API
User

Recargar saldo (TopUp Cripto)

Generar una billetera cripto para recibir un depósito en tu cuenta de QvaPay. Funciona tanto para usuarios recargando su propio saldo como para apps/merchants que integren depósitos.

POST /api/topup

Crea una transacción de depósito y genera una billetera cripto (BTC, USDT, ETH, etc.) en la red elegida. Cuando se envíen fondos a esa billetera, el proveedor cripto notificará a QvaPay, QvaPay acreditará el saldo en USD a la cuenta y, si se proporcionó webhook_url, disparará un webhook saliente (ver TopUp Webhook).

Autenticación

Acepta dos modos:

  • Bearer token de usuario (Authorization: Bearer <token>) — caso típico de un usuario recargando su propio saldo. El TOPUP queda asociado a app_id = 0 y los webhooks (si se configura webhook_url) se enviarán sin firma.
  • Credenciales de App (app-id + app-secret en headers) — pensado para integraciones merchant que quieran recibir webhooks firmados con HMAC.

Rate limit

5 requests por minuto por usuario (ArcJet, token bucket). Usuarios vip quedan exentos.

Request

{
  "amount": 100,
  "pay_method": "BTC",
  "webhook_url": "https://mitienda.com/webhook/topup"
}

Parámetros

ParámetroTipoRequeridoDescripción
amountnumberSiMonto en USD a recibir (mayor al min_in de la moneda, máximo 100,000)
pay_methodstringSiTick de la moneda (ej: BTC, USDT, ETH, TRX, SOL, LTC, DOGE, BTCLN...)
webhook_urlstringNoURL pública (HTTPS recomendado) donde QvaPay enviará la notificación al acreditarse el pago. Máx. 191 caracteres.
fee_modestringNoSolo depósitos con tarjeta (CARD). on_top (default): el fee se suma al cobro y se acredita el amount completo. included: se cobra exactamente el amount y se acredita el amount menos el fee.
refund_addressstringNoSolo monedas que se convierten al recibirse (ver Monedas convertidas): dirección propia en la moneda enviada a la que se devuelven los fondos si el envío no se puede convertir. Sin ella, una devolución se tramita por soporte.
complianceobjectNo*Atestación de propósito del fondeo. *Obligatoria en todo depósito de una cuenta US person, por cualquier método y canal; y para el navegador web en depósitos por transferencia bancaria (BANK). En los demás casos es opcional (recomendada). Ver Atestación en depósitos bancarios

Response

{
  "result": "OK",
  "data": {
    "wallet": "1A1z7agoat8Hs3zNx2EN1234567890",
    "memo": null,
    "coin": "BTC",
    "value": 0.0025,
    "price": 43000,
    "transaction_id": "1234567",
    "transaction_uuid": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "transaction_url": "https://pay.qvapay.com/?token=N2M5ZTY2NzktNz...",
    "payment_id": "abc123",
    "redirect_url": null
  }
}

Campos de respuesta

CampoTipoDescripción
walletstringDirección de la billetera donde se debe enviar los fondos
memostring | nullMemo o tag (cuando aplica, ej. Stellar/TON/Cosmos). Si viene, es obligatorio incluirlo en el envío
coinstringTick de la moneda
valuenumberCantidad de cripto que se debe enviar para acreditar el amount solicitado en USD
pricenumberPrecio de la moneda en USD al momento de la cotización
transaction_idstringID numérico interno de la transacción (BigInt como string)
transaction_uuidstringUUID único de la transacción — guárdalo para reconciliar contra el webhook
transaction_urlstringURL de pago corta de QvaPay (opcional para redirigir al usuario)
payment_idstringID interno del proveedor cripto
redirect_urlstring | nullURL de redirección si el proveedor lo provee (PayPal, etc.)

Cómo se recibe cada moneda

QvaPay elige el camino según pay_method; la forma de la respuesta es siempre la misma:

  • Dirección de depósito propia (BTC, LTC, TRX, USDT, USDC, ETH, SOL, TON, BNB, MATIC, ARB y otras): wallet es una dirección de un solo uso para este depósito.
  • Lightning (BTCLN): wallet es una factura Lightning (bolt11) por exactamente value BTC; caduca en 1 hora. Se acredita el amount en cuanto se paga.
  • Monedas convertidas al recibirse (DOGE, ZEC, ATOM, BCH, AVAX en C-Chain, ADA, VET, XTZ, DASH, ALGO, SUI, XRP, LINK, SHIB y CAKE en BSC, DAI en Ethereum, TRUMP en Solana, HMSTR y NOT en TON, USDCALGO, RVN): ver la sección siguiente.

Monedas convertidas al recibirse

Estas monedas se convierten automáticamente a USD al llegar, a la tasa de mercado del momento (tasa flotante):

  • value es una estimación de cuánto enviar para que se acrediten amount USD. Se acredita lo que realmente resulte de la conversión, menos el fee de la moneda: si se envía de más se acredita el excedente (con el recargo de sobrepago) y si se envía de menos se acredita lo recibido (is_partial: true en el webhook).
  • La acreditación tarda lo que tarde la conversión (normalmente 5–30 minutos tras las confirmaciones de la red de origen). El webhook llega igual que en el resto de depósitos.
  • Si memo viene informado (p. ej. ATOM, USDCALGO, o el destination tag de XRP), el envío debe llevarlo.
  • Cada moneda tiene un mínimo por debajo del cual la conversión no sale (o cuesta demasiado: algunas redes tienen un coste fijo por envío). La respuesta lo indica con 400 BELOW_MIN y min_usd, que puede cambiar con el mercado.

Atestación de cuentas US person

Una cuenta US person (se declaró persona estadounidense, verificó con un documento emitido en EE. UU. o sus territorios, o tiene SSN/ITIN en su ficha) tiene que enviar el objeto compliance en todo depósito, sea cripto, bancario o de cualquier otro método, y desde cualquier canal (web, apps móviles, apps de comercio y clientes API). Si falta o no es válido, la respuesta es 400 con code: "US_PERSON_ATTESTATION_REQUIRED". Vigente desde el 29 sep 2026. El formato y los códigos (P-1…P-4) son los mismos de la sección siguiente.

Atestación en depósitos bancarios

Un depósito por transferencia bancaria (pay_method: "BANK") entra en la cuenta bancaria estadounidense de QvaPay, por lo que el cliente declara el propósito del fondeo con el mismo objeto compliance que usan los retiros:

{
  "amount": 500,
  "pay_method": "BANK",
  "compliance": {
    "purposeCode": "P-1",
    "attestations": {
      "notProhibitedOfficial": true,
      "notProhibitedPartyMember": true,
      "notRestrictedList": true,
      "lawfulPurpose": true
    }
  }
}

Códigos válidos en este ámbito: P-1 (remesa familiar), P-2 (pago al sector privado), P-3 (donativo), P-4 (recarga / telecomunicaciones). Las cuatro casillas de attestations deben ser true.

La exigencia se despliega por canal: el navegador web recibe 400 si falta; las apps móviles (x-qvapay-client-platform: ios|android), las apps de comercio (app-id) y los clientes API con Bearer propio pueden omitirla hoy (se registra la ausencia) y deberían enviarla desde ya. Los depósitos cripto no la requieren, salvo que la cuenta sea US person (ver arriba).

Errores

CódigoDescripción
400Datos inválidos: amount fuera de rango, pay_method no soportado, webhook_url no válida
400Depósito BANK desde el navegador sin el objeto compliance
400US_PERSON_ATTESTATION_REQUIRED: depósito de una cuenta US person sin compliance válido, en cualquier canal
400BELOW_MIN: monto por debajo del mínimo de conversión de la moneda en este momento (min_usd trae el mínimo)
403KYC_REQUIRED: la cuenta no tiene verificación de identidad aprobada (kyc_url indica dónde completarla)
403COMPANY_ACCOUNT_REQUIRED: depósito BANK desde una cuenta no elegible (ver nota)
401Credenciales de app o bearer token ausentes/inválidos
429Rate limit excedido (más de 5 requests por minuto)
429CARD_DAILY_LIMIT: tope diario de depósitos con tarjeta de la cuenta (ver nota)
400DEPOSIT_MONTHLY_LIMIT: la cuenta deposita por el nivel «SSN verificado» y este CARD/PAYPAL supera su tope de 30 días (cap, used, remaining, window_days, resets_at; ver nota)
429RATE_LIMITED: en el nivel «SSN verificado», un depósito CARD/PAYPAL cada 5 segundos
500Error interno al crear la transacción o billetera
503DEPOSIT_UNAVAILABLE: la conversión de esa moneda no está disponible en este momento; reintentar en unos minutos

Notas importantes

  • BANK solo para cuentas elegibles: los depósitos por transferencia bancaria están disponibles para cuentas VIP, cuentas con TrustScore de 85 o más, y cuentas empresa (cuenta de tipo empresa o titular de una empresa registrada y aprobada en Ajustes) — la misma regla que PAYPAL. Cualquier otra cuenta recibe 403 con code: "COMPANY_ACCOUNT_REQUIRED" (el código se mantiene por compatibilidad); el wizard de depósito no muestra el método a esas cuentas.
  • CARD (depósito con tarjeta): misma elegibilidad que PAYPAL y, además, la petición debe venir desde fuera de Cuba. Monto entre min_in y max_in de la moneda. El tope diario cuenta intentos (cada depósito creado, se pague o no): 3 por día en cuentas personales, que depositan a su propio saldo. Una cuenta empresa puede cobrar a sus clientes con tarjeta por este método (crea el depósito con webhook_url y envía al cliente a transaction_url; el webhook de TopUp llega al acreditarse), por lo que tiene un tope diario propio y mucho mayor. Al superarlo, 429 con code: "CARD_DAILY_LIMIT". El contracargo de una tarjeta de cliente se descuenta del saldo de la cuenta que cobró.
  • Nivel «SSN verificado» (solo apps móviles): una persona de EE. UU. GOLD que verificó su SSN (ver Verificación del SSN) puede depositar con CARD y PAYPAL sin ser VIP, TrustScore ≥ 85 ni empresa, con un tope combinado de $500 sobre lo cobrado en los últimos 30 días (ventana rodante). Solo desde x-qvapay-client-platform: ios|android. Antes de ofrecer el método, consulta GET /user/deposit-eligibility, que devuelve el nivel (full sin tope, ssn con tope) y el cupo restante.
  • Cap al monto solicitado: si se envía cripto que excede el amount solicitado, QvaPay solo acredita el amount y el excedente queda en cuenta interna. Pide el monto exacto que indica value en la respuesta.
  • Subpago: si se envía menos del solicitado, se acredita lo que valga en USD después del fee. El webhook indicará is_partial: true (ver TopUp Webhook).
  • Idempotencia del webhook: el mismo transaction_uuid puede llegar 1–3 veces al webhook (política de reintentos). Tu endpoint debe ser idempotente.