Saltar al contenido principal

Payout por lotes: la otra PayoutPolicy real

Todos los capítulos hasta aquí corren bajo PayoutPolicy.Immediate — el valor por defecto de Ishtaran, y el que usa todo ejemplo funcional de este sitio: executeSettlement() paga a Bob y a la comisión de Mercatto en el mismo momento, construyendo un SigningRequest real contra la propia wallet de ejecución de Mercatto (vea Settlement y Split). Existe un segundo modo real y público — Manual — en el que executeSettlement() nunca construye ningún SigningRequest. Registra un asiento real y balanceado en el Ledger (Reserved(pagador)Payable(beneficiario)) y completa de inmediato. El dinero solo se mueve realmente después, cuando Mercatto crea explícitamente un PayoutBatch.

Cuándo usar cada una

  • Immediate — el caso común, y el valor por defecto correcto. Un beneficiario recibe su pago en el momento en que su Settlement se ejecuta. Use este a menos que tenga una razón específica para acumular.
  • Manual — útil cuando quiere agrupar muchos Settlements pequeños en transmisiones on-chain más grandes y menos frecuentes (menor costo de red total), o cuando su propia cadencia de pago deliberadamente no es "en el instante en que ocurre un Settlement" (p. ej., un pago semanal a vendedores). El saldo Payable de un beneficiario (payout.getPayableSummary().accrued) puede crecer a lo largo de muchos Settlements antes de que algo se pague realmente.

Threshold y Scheduled también existen en el modelo de dominio (un disparo automático cuando un saldo cruza un umbral, o según una programación cron) pero todavía no tienen ninguna ruta pública para dispararse — este capítulo, y esta plataforma, solo crean un PayoutBatch con trigger = Manual.

Dos pasos de bootstrap que este capítulo necesita, ninguno necesario en ningún otro lugar de este tutorial

La propia PayoutPolicy es una decisión del Platform Owner, no algo que la API Key propia de Mercatto o una sesión de Member puedan configurar — POST /v1/admin/organizations/{organizationId}/payout-policy, autenticada con una Platform Owner API Key. Ningún SDK oficial expone esta ruta a propósito: no es una capacidad de Data Plane que el backend de un integrador llamaría en tiempo de ejecución, de la misma forma que ningún SDK expone la configuración de la Pricing Policy global de la plataforma. Real, encontrado en la misma sesión de este capítulo: antes de que esta ruta existiera, ConfigurePayoutPolicyCommand no tenía ninguna vía HTTP, pública ni administrativa — toda la superficie de payout por lotes de abajo era inalcanzable por cualquier actor real.

ExecutionSource es la wallet/dirección que paga por la propia transmisión del lote — un concepto genuinamente distinto del ExecutionDestination de un beneficiario (donde ellos reciben los fondos) y de la propia wallet de ejecución de Mercatto usada en el Settlement. Regístrela una vez por (Organization, Environment, AssetNetwork) antes del primer PayoutBatch real, la misma categoría de bootstrap que NetworkCostPayerAccount (vea Self-Custody).

Paso a paso

// 1. El Platform Owner cambia la PayoutPolicy a Manual para esta Organization/AssetNetwork.
await fetch(`${baseUrl}/v1/admin/organizations/${organizationId}/payout-policy`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Platform-Owner-Key': platformOwnerApiKey },
body: JSON.stringify({ assetNetworkId, mode: 3 /* Manual */ }),
});

// 2. Un NetworkExecutionQuote puede previsualizarse de forma aislada, en cualquier momento -- lectura pura.
const preview = await mercatto.networkExecution.quote(
environmentId, assetNetworkId,
[{ destinationAddress, amount: '1', kind: NetworkOperationKind.TRANSFER, reference: 'preview' }],
NetworkCostPayer.INTEGRATOR,
);

// 3. El Settlement acumula -- sin SigningRequest, completa de forma síncrona.
const executed = await mercatto.settlements.executeSettlement(transactionId);
const settlement = await mercatto.settlements.get(executed.settlementId);
// settlement.status.name === 'COMPLETED'; settlement.signingRequestId === null

const bobSummary = await mercatto.payout.getPayableSummary(bobAccountId, assetNetworkId);
// bobSummary.accrued > 0; bobSummary.paid === '0' -- nada se ha movido todavía

// 4. Registrar el ExecutionSource que financiará la transmisión del lote.
await mercatto.executionSources.register(organizationId, environmentId, assetNetworkId, walletId, derivationReference, address);

// 5. Crear el lote -- trigger Manual, beneficiarios explícitos con Payable real acumulado.
const created = await mercatto.payout.createBatch(organizationId, environmentId, assetNetworkId, [bobAccountId, mercattoRevenueAccountId]);
// created.payoutBatchId es null solo cuando ninguno de los titulares dados tenía Payable positivo -- un no-op legítimo.

// 6. Firmar cada leg con el signer de la propia wallet del ExecutionSource (nunca la de un
// beneficiario, nunca la wallet de Settlement de Mercatto), enviar, simular confirmación
// (Sandbox), esperar Completed -- exactamente el mismo protocolo de firma self-custody de
// Settlement/Withdrawal (vea Self-Custody).

En cuanto el lote llega a Completed, payout.getPayableSummary() refleja lo que cambió: accrued vuelve a 0 para cada beneficiario del lote, y paid crece exactamente por lo que se le debía — la misma semántica de Delivered que un payout de Settlement Immediate, solo que en otro cronograma.

Ejecútelo usted mismo

La versión completa y ejecutable — mismas llamadas, mismo orden, HTTP real, nunca simulado — es examples/marketplace-mercatto/scenarios/payout-batch-manual.ts en el repositorio de la plataforma (SDK de TypeScript). Necesita una cosa que ningún otro escenario del catálogo necesita: una Platform Owner API Key real (MERCATTO_PLATFORM_OWNER_API_KEY) para ejecutar el paso 1 de arriba — vea el propio README.md del catálogo de escenarios para la configuración exacta.