QvaPay API
P2P

Crear Oferta P2P

Crear una nueva oferta de compra o venta P2P.

POST /p2p/create

Crea una nueva oferta P2P de compra o venta. Para ofertas de venta (sell), el monto se deduce automáticamente del saldo del usuario. El usuario debe tener KYC verificado.

Autenticación

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

Cuando se usa Credenciales de App, la oferta se crea en nombre del usuario propietario de la app. Dicho usuario debe cumplir todos los requisitos de P2P (p2p_enabled, KYC verificado, Telegram vinculado y teléfono verificado), y para ofertas de tipo sell el saldo se descuenta de su cuenta.

Request

Con Bearer Token:

curl -X POST "https://api.qvapay.com/p2p/create" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "buy",
    "coin": "BANK_CUP",
    "amount": 50,
    "receive": 12500,
    "details": [{ "name": "cuenta", "value": "1234567890" }],
    "only_vip": 0,
    "private": 0,
    "message": "Pago rápido",
    "webhook": "https://example.com/webhook"
  }'

Con Credenciales de App:

curl -X POST "https://api.qvapay.com/p2p/create" \
  -H "app-id: {tu-app-uuid}" \
  -H "app-secret: {tu-app-secret}" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "buy",
    "coin": "BANK_CUP",
    "amount": 50,
    "receive": 12500,
    "details": [{ "name": "cuenta", "value": "1234567890" }],
    "only_vip": 0,
    "private": 0,
    "message": "Pago rápido",
    "webhook": "https://example.com/webhook"
  }'

Parámetros (body JSON)

ParámetroTipoRequeridoDescripción
typestringTipo de oferta: buy o sell
coinstring | numberTick de la moneda (ej: BANK_CUP) o ID numérico
amountnumberCantidad en QUSD (0.1 - 100,000)
receivenumberCantidad a recibir en la moneda seleccionada (0.1 - 1,000,000)
detailsarrayDatos de pago según los campos de la moneda (ej: cuenta bancaria)
only_kycnumberNo1 para restringir a usuarios con KYC verificado
only_vipnumberNo1 para restringir a usuarios VIP
privatenumberNo1 para crear oferta privada (no se publica en Telegram)
messagestringNoMensaje público de la oferta (máx. 79 caracteres, URLs eliminadas)
webhookstringNoURL de webhook para notificaciones de estado
tagsarrayNoEtiquetas para la oferta (máx. 10 tags)
idempotency_keystringNoClave de idempotencia (8-64 caracteres, [A-Za-z0-9._-]) para reintentos seguros en conexiones inestables. Repetir la misma clave en 24h devuelve la oferta original con 200 y duplicate: true en vez de crear un duplicado

Response (201)

{
  "msg": "Oferta P2P creada correctamente",
  "p2p": {
    "uuid": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "type": "buy",
    "coin": "BANK_CUP",
    "amount": 50.00,
    "receive": 12500.00,
    "only_kyc": 0,
    "private": 0,
    "only_vip": 0,
    "status": "open",
    "details": { "cuenta": "1234567890" },
    "message": "Pago rápido",
    "webhook": "https://example.com/webhook",
    "created_at": "2024-06-20T14:30:00.000Z",
    "updated_at": "2024-06-20T14:30:00.000Z"
  }
}

Webhook

Si se proporciona un webhook, se enviará un POST con el siguiente payload cuando la oferta sea creada:

{
  "operation": "created",
  "p2p": { ... }
}

Idempotencia

Si se envía idempotency_key y una oferta ya fue creada con esa misma clave, la respuesta es 200 con la oferta original y el campo adicional "duplicate": true (no se crea una segunda oferta ni se debita saldo de nuevo). Si la creación original aún está en proceso, se responde 409 con "code": "DUPLICATE_REQUEST" — reintenta unos segundos después.

Errores

CódigoDescripción
400Datos inválidos, moneda no encontrada, KYC requerido, saldo insuficiente, o límite de ofertas pendientes alcanzado
401Token de autenticación inválido o ausente
409DUPLICATE_REQUEST: ya hay una creación en proceso con la misma idempotency_key
429Demasiadas solicitudes (límite: 1 cada 5 segundos, 100 diarias)
500Error interno al crear la transacción