Skip to content

API: Implement Payouts Service & Controller (Wire Up Schema) #116

@0xdevcollins

Description

@0xdevcollins

Severity: HIGH — Payouts Module is Schema-Only, No Business Logic

Problem

The Payout Prisma model exists and is well-defined, but the payouts NestJS module has no service or controller implementation. The API endpoints POST /v1/payouts and POST /v1/payouts/bulk documented in the Product Docs are non-functional.

Implementation Required

1. Payouts Service

```typescript
@Injectable()
export class PayoutsService {
async createSingle(merchantId: string, dto: CreatePayoutDto): Promise
async createBulk(merchantId: string, dto: BulkPayoutDto): Promise
async findAll(merchantId: string, filters: PayoutFiltersDto): Promise<PaginatedResult>
async findOne(merchantId: string, payoutId: string): Promise
async cancel(merchantId: string, payoutId: string): Promise
async retry(merchantId: string, payoutId: string): Promise
async processPayout(payoutId: string): Promise // called by BullMQ worker
}
```

2. Payout execution via Stellar

For STELLAR and CRYPTO_WALLET destination types:
```typescript
async processPayout(payoutId: string) {
const payout = await this.prisma.payout.findUnique({ where: { id: payoutId } });

// Convert merchant balance → payout currency via path payment
const txHash = await this.stellar.pathPaymentSend({
source: process.env.RELAY_STELLAR_ADDRESS,
destination: payout.destination.stellarAddress,
sendAsset: 'USDC',
sendAmount: payout.amount,
destAsset: payout.currency,
});

await this.prisma.payout.update({
where: { id: payoutId },
data: { status: 'COMPLETED', stellarTxHash: txHash, completedAt: new Date() },
});

await this.webhooksService.fire(payout.merchantId, 'payout.completed', payout);
await this.eventsService.emitPayoutStatus(payout.merchantId, payoutId, 'COMPLETED');
}
```

3. BullMQ worker for async processing

```typescript
@processor('payouts')
export class PayoutsProcessor {
@process('process-payout')
async processPayout(job: Job<{ payoutId: string }>) {
await this.payoutsService.processPayout(job.data.payoutId);
}
}
```

4. Bulk CSV parsing

Use csv-parser or papaparse to handle bulk uploads.
Row-level validation: return errors per row without failing the entire batch.

Acceptance Criteria

  • POST /v1/payouts creates and queues a single payout
  • POST /v1/payouts/bulk accepts CSV, validates rows, queues valid ones
  • GET /v1/payouts and GET /v1/payouts/:id return correct data
  • Payout processed via BullMQ worker asynchronously
  • Stellar path payment executes for STELLAR destination type
  • Webhook fired on payout.completed and payout.failed
  • WebSocket emits payout status updates

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions