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).

También puedes llamar a esta ruta con app-id / app-secret en vez de un token de cuenta. Ver Operar con credenciales de app.

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
typestringSíTipo de oferta: buy o sell
coinstring | numberSíTick de la moneda (ej: BANK_CUP) o ID numérico
amountnumberSíCantidad en QUSD (0.1 - 10,000)
receivenumberSíCantidad a recibir en la moneda seleccionada (0.1 - 100,000,000)
detailsarraySíDatos 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)
offer_kindstringNofixed (por defecto, se toma entera) o flexible (por rango, se toma por partes). Ver Ofertas por rango
order_minnumberSi offer_kind es flexibleMínimo por orden (> 0)
order_maxnumberSi offer_kind es flexibleMáximo por orden (≥ order_min, ≤ amount)
requirementsobjectNoRequisitos para quien aplique (ver abajo). Valen para ofertas fixed y flexible
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

Requisitos para quien aplique

Con requirements solo podrán aplicar las cuentas que los cumplan:

{ "requirements": { "min_completed": 25, "min_rating": 4.5 } }
ClaveValores permitidosQué exige
min_completed5, 10, 25, 50, 100Operaciones P2P completadas
min_rating4, 4.5Rating promedio (1–5)
min_account_days7, 30, 90, 180Antigüedad de la cuenta en días
min_trustscore50, 85TrustScore de la cuenta (0–100, lo asigna QvaPay)

Cualquier otro valor responde 400 con code: "INVALID_REQUIREMENTS". Omitir una clave (o mandarla en 0/null) es "sin ese requisito".

La respuesta devuelve requirements (o null).

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
403FLEXIBLE_NOT_ENABLED: tu cuenta no tiene KYC aprobado y no puede publicar ofertas por rango
409DUPLICATE_REQUEST: ya hay una creación en proceso con la misma idempotency_key
409FLEXIBLE_OFFER_EXISTS: ya tienes una oferta por rango viva del mismo lado (buy/sell) en esa moneda; cancélala o edítala antes de publicar otra
429Demasiadas solicitudes (límite: 1 cada 10 segundos; 100 ofertas al día (250 para cuentas VIP y GOLD), sin tope diario para cuentas de empresa)
500Error interno al crear la transacción