Guía para desarrolladores
Referencia de API
Explorar documentación

Liquidar pagos de marketplace (comisión + payout)

Cobra al comprador en la cuenta comercio del tenant, retiene una comisión de plataforma en tu app y luego paga destinos Pago Móvil de vendedores verificados con payouts simples o en batch.

Qué es este flujo

Usa este patrón cuando un vendedor registra un destino Pago Móvil en VES, un comprador paga con su propio Pago Móvil (monto de subasta o pedido) y tu tenant debe conservar una comisión antes de pagar al vendedor — opcionalmente repartiendo el crédito entre más de un comerciante verificado.

Pasos de punta a punta

  1. Registra y verifica al vendedor

    POST /v1/merchants con bankCode + teléfono del vendedor (y tu id de vendedor como externalRef) y luego verifica el método con microdepósitos. Detalles: Comerciantes y payouts (/es/merchants-payouts).

  2. Resuelve el comerciante antes del payout

    Al liquidar, busca al vendedor bajo tu tenant con GET /v1/merchants?externalRef={tuIdDeVendedor} — la misma auth que el resto (`x-api-key`). Prefiere esto a guardar solo el merchantId del gateway. Ver /es/merchants-payouts#lookup-by-ref.

  3. Cobra al comprador

    Cobra a la cuenta comercio del tenant con C2P (recomendado: POST /v1/payments/c2p/request y luego POST /v1/payments/c2p) o débito inmediato (POST /v1/payments/debit/otp y luego POST /v1/payments/debit). Envía un externalRef de pago estable para tu pedido/subasta.

  4. Espera payment.completed

    Suscríbete a payment.completed / payment.failed. Si la respuesta es incierta, recupera con GET /v1/payments/by-ref/:externalRef antes de cumplir o pagar.

  5. Calcula comisión y neto en VES

    En tu app: comisión = cobrado × tasa (o fijo), neto = cobrado − comisión. No hay campo de platform-fee en la API: retienes la comisión pagando al vendedor menos de lo cobrado.

  6. Paga al vendedor (o reparte)

    POST /v1/payouts con el merchantId del vendedor, el monto neto exacto y el paymentId del cobro completado — o POST /v1/payouts/batch con paymentId y un ítem por destino. Cada ítem necesita su propio externalRef idempotente. Se permiten varios payouts parciales hasta que el neto restante sea 0.

Reglas de comisión y split

ReglaDetalle
Dueño de la comisiónPrefiere applicationFeeVes / applicationFeePercent en el cobro (la plataforma retiene; el neto va a pending del vendedor). Retener pagando menos sigue válido sin merchantId.
Ledger del vendedorGET /v1/merchants/:id/balance devuelve pendingVes + availableVes. POST /v1/merchants/:id/transfers mueve float del tenant → pending del vendedor. Payouts con fromMerchantBalance debitan available del vendedor.
Balance de plataformaGET /v1/balance devuelve platformAvailableVes, sellerObligationsVes, sellerPendingVes, sellerAvailableVes.
Montos de payoutStrings VES con exactamente dos decimales (p. ej. "1523.40"). El gateway nunca convierte FX en payouts.
Vínculo paymentIdOpcional en POST /v1/payouts y POST /v1/payouts/batch. Vincula piernas al cobro para ops y el tope de neto restante.
Neto restanteremaining = vesAmount − feeVes − suma(payouts PENDING|COMPLETED de ese paymentId). Los FAILED liberan remaining. Exceder → 422 payment_split_exceeded.
Multi-parcialVarios payouts/batches pueden usar el mismo paymentId hasta remaining = 0. El mismo externalRef sigue siendo replay idempotente.
Split en batchPOST /v1/payouts/batch paga a varios comerciantes verificados en una solicitud. El resultado es por ítem — no es todo o nada. El paymentId del batch aplica a cada ítem.
Float de comercioLos payouts clásicos debitan la cuenta comercio del tenant. Los payouts de saldo del vendedor debitan available (el tenant ya reservó vía SELLER_TRANSFER).
IdempotenciaexternalRef en pagos es solo correlación. En comerciantes y payouts es la clave de idempotencia; paymentId entra en el hash del request de payout.

Ejemplos mínimos

Cuando el vendedor esté verificado y el cobro al comprador haya completado, liquida el neto (o un split multiparte) con la API de payouts.

Alta del vendedorbash
curl --request POST "${API_URL}/v1/merchants" \
  --header "content-type: application/json" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --data '{
    "externalRef": "seller_laganga_7f3a",
    "name": "Maria Perez",
    "identification": "V12345678",
    "contactEmail": "maria@mail.com",
    "contactPhone": "04141234567",
    "bankCode": "0134",
    "phone": "04145555555"
  }'
Cobro al comprador (C2P)bash
curl --request POST "${API_URL}/v1/payments/c2p" \
  --header "content-type: application/json" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --data '{
    "intentId": "00000000-0000-4000-8000-000000000000",
    "usdAmount": 12.50,
    "debtorId": "V87654321",
    "debtorCellPhone": "584121234567",
    "debtorBankCode": 102,
    "token": "123456",
    "externalRef": "bid_1042"
  }'
Payout netobash
curl --request POST "${API_URL}/v1/payouts" \
  --header "content-type: application/json" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --data '{
    "merchantId": "00000000-0000-4000-8000-000000000000",
    "paymentId": "00000000-0000-4000-8000-000000000010",
    "monto": "1371.06",
    "concepto": "Bid 1042 neto",
    "externalRef": "po_bid_1042_seller"
  }'
Split en batchbash
curl --request POST "${API_URL}/v1/payouts/batch" \
  --header "content-type: application/json" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --data '{
    "externalRef": "settle_bid_1042",
    "paymentId": "00000000-0000-4000-8000-000000000010",
    "items": [
      {
        "merchantId": "00000000-0000-4000-8000-000000000000",
        "monto": "1200.00",
        "concepto": "Neto vendedor",
        "externalRef": "po_bid_1042_seller"
      },
      {
        "merchantId": "00000000-0000-4000-8000-000000000002",
        "monto": "171.06",
        "concepto": "Parte socio",
        "externalRef": "po_bid_1042_partner"
      }
    ]
  }'

Webhooks y recuperación

  • Usa paymentId en los payouts para vincular la liquidación al cobro; usa externalRef del pago para tu id de pedido y externalRef del payout / ítem de batch para reintentos seguros.
  • Suscríbete a payment.completed / payment.failed antes de cumplir la subasta o el pedido.
  • Suscríbete a payout.completed / payout.failed después de disparar la liquidación.
  • Verificación de comerciantes y reglas de payout: /es/merchants-payouts. Firma y entrega: /es/webhooks.