QvaPay API
P2P

Listar Ofertas P2P

Obtener el listado paginado de ofertas P2P disponibles con filtros avanzados.

GET /p2p

Retorna el listado de ofertas P2P disponibles, con soporte para filtros por tipo, moneda, monto, ratio, estado y paginación.

Autenticación

Bearer Token (Authorization: Bearer <token>) o Credenciales de App (app-id + app-secret en headers).

Cuando se usa Credenciales de App, la consulta se realiza en nombre del usuario propietario de la app. Dicho usuario debe cumplir los requisitos de acceso a P2P (p2p_enabled, KYC verificado, Telegram vinculado y teléfono verificado).

Request

Con Bearer Token:

curl -X GET "https://api.qvapay.com/p2p?take=20&page=1&type=buy&coin=BANK_CUP" \
  -H "Authorization: Bearer <token>"

Con Credenciales de App:

curl -X GET "https://api.qvapay.com/p2p?take=20&page=1&type=buy&coin=BANK_CUP" \
  -H "app-id: {tu-app-uuid}" \
  -H "app-secret: {tu-app-secret}"

Parámetros (query string)

ParámetroTipoRequeridoDescripción
pagenumberNoPágina a consultar (por defecto 1)
takenumberNoResultados por página (por defecto 20, máximo 100)
typestringNoFiltrar por tipo: buy o sell (alias: offer_type)
coinstringNoFiltrar por tick de la moneda (ej: BANK_CUP)
orderBystringNoCampo de ordenamiento: updated_at (por defecto), created_at, amount, receive, ratio, best_rate, rating, trades
orderTypestringNoOrden: asc o desc (por defecto desc; alias: order). Con orderBy=best_rate, desc es "mejor tasa primero"
mybooleanNotrue o 1 muestra solo las ofertas del usuario autenticado (como dueño o como peer)
peerstringNoFiltrar por usuario: acepta UUID o username (con o sin @)
sortByStatusbooleanNoSolo con my=true: agrupa por estado (revisión → procesando → pagado → abierta → completada). Por defecto true
minnumberNoMonto mínimo (alias: min_price)
maxnumberNoMonto máximo (alias: max_price)
ratio_minnumberNoRatio mínimo (receive / amount) (alias: min_ratio)
ratio_maxnumberNoRatio máximo (receive / amount) (alias: max_ratio)
only_vipbooleanNotrue o 1 muestra solo ofertas marcadas como exclusivas para usuarios VIP
searchstringNoBúsqueda general (detalles, mensaje, uuid, montos). Solo funciona junto a my=true
statusstringNoFiltrar por estado: open, revision, processing, paid, completed, cancelled. Solo aplica junto a my=true (el listado público siempre es open)

Los ordenamientos ratio (tasa receive / amount), best_rate, rating (valoración promedio del ofertante) y trades (operaciones P2P completadas del ofertante) son rankings globales sobre el listado público; en my=true caen a updated_at (salvo ratio, que sí se aplica sobre tus ofertas).

ratio vs best_rate

ratio es la tasa cruda receive / amount (moneda por USD) y no es lo mismo que "mejor tasa": su dirección se invierte según el lado del mercado, porque el ratio se mide siempre desde la oferta, no desde quien la toma.

Tipo de ofertaQuien la toma…El ratio es…Mejor para quien la toma
sellcompra QUSD pagando la monedalo que paga por dólarratio más bajo
buyvende QUSD y recibe la monedalo que recibe por dólarratio más alto

Por eso orderBy=ratio&orderType=desc sobre un listado type=sell devuelve las ofertas más caras primero. Usa orderBy=best_rate, que normaliza el signo según el tipo: orderType=desc es siempre "mejor primero" y asc "peor primero", en ambos lados.

best_rate requiere type y coin (responde 400 si faltan): sin tipo el signo no está definido, y los ratios de monedas distintas no son comparables entre sí (1000 CUP/USD vs 1.2 MLC/USD ordenaría por moneda, no por tasa). Tampoco aplica con my=true, donde la perspectiva es la del dueño de la oferta.

# Mejores ofertas para comprar CUP por transferencia bancaria
curl -X GET "https://api.qvapay.com/p2p?type=sell&coin=BANK_CUP&orderBy=best_rate&orderType=desc" \
  -H "Authorization: Bearer {token}"

Response

Paginación estilo Laravel. amount, receive y los demás campos decimales se serializan como strings.

{
  "current_page": 1,
  "data": [
    {
      "uuid": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "type": "buy",
      "coin": "BANK_CUP",
      "amount": "50",
      "receive": "12500",
      "payment_type_id": 1,
      "message": "Pago rápido",
      "private": false,
      "only_vip": false,
      "status": "open",
      "created_at": "2024-06-20T14:30:00.000Z",
      "updated_at": "2024-06-20T14:30:00.000Z",
      "offer_kind": "fixed",
      "available_amount": "50",
      "reserved_amount": "0",
      "order_min": null,
      "order_max": null,
      "User": {
        "uuid": "550e8400-e29b-41d4-a716-446655440000",
        "username": "johndoe",
        "name": "John",
        "image": "https://example.com/avatar.png",
        "kyc": true,
        "vip": false,
        "golden_check": false,
        "phone_verified": true,
        "telegram_verified": true,
        "rating_avg": 4.85,
        "rating_count": 12,
        "_count": {
          "P2P": 34,
          "P2P_Peer": 18
        }
      },
      "Coin": {
        "name": "Transferencia CUP",
        "tick": "BANK_CUP",
        "logo": "https://example.com/cup.png",
        "price": "1"
      }
    }
  ],
  "per_page": 20,
  "total": 143
}

Notas:

  • _count.P2P y _count.P2P_Peer son las operaciones P2P completadas del usuario como dueño y como peer, respectivamente.
  • En ofertas con peer asignado (visible con my=true) se incluye un objeto Peer con la misma estructura que User.
  • Con my=true sin status explícito, la respuesta incluye "sorted_by_status": true y las ofertas llegan agrupadas por estado.

Errores

CódigoDescripción
400Parámetro inválido (page, take, orderBy, orderType, type, status o filtros numéricos), orderBy=best_rate sin type/coin, o el usuario no cumple los requisitos de acceso a P2P
401Token de autenticación inválido o ausente
429Demasiadas solicitudes (límite: 30 cada 60 segundos por usuario)