import { initContract } from '@ts-rest/core'; import { z } from 'zod'; import { walletSchema, tokenTransactionSchema, tokenBundleSchema, purchaseTokensSchema, verifyTokenPaymentSchema, } from '../schemas/shopkeeper-wallet.schemas'; import { errorResponseSchema, paginationQuerySchema, paginationResponseSchema, } from '../schemas/common.schemas'; const c = initContract(); export const shopkeeperWalletContract = c.router({ getWallet: { method: 'GET', path: '/shopkeeper/wallet', responses: { 200: z.object({ wallet: walletSchema, recentTransactions: z.array(tokenTransactionSchema).max(10), }), 401: errorResponseSchema, }, summary: 'Get wallet balance and recent activity', }, purchaseTokens: { method: 'POST', path: '/shopkeeper/wallet/purchase', body: purchaseTokensSchema, responses: { 200: z.object({ wallet: walletSchema, transaction: tokenTransactionSchema.optional(), paymentUrl: z.string().optional(), referenceId: z.string().optional(), }), 400: errorResponseSchema, 401: errorResponseSchema, 402: errorResponseSchema, }, summary: 'Purchase a token bundle (initiates Paystack payment; wallet credited on success)', }, listBundles: { method: 'GET', path: '/shopkeeper/wallet/bundles', responses: { 200: z.object({ bundles: z.array(tokenBundleSchema) }), }, summary: 'List available token bundles', }, listTransactions: { method: 'GET', path: '/shopkeeper/wallet/transactions', query: z .object({ type: z.string().optional(), feature: z.string().optional(), from: z.coerce.date().optional(), to: z.coerce.date().optional(), }) .merge(paginationQuerySchema), responses: { 200: z.object({ transactions: z.array(tokenTransactionSchema), pagination: paginationResponseSchema, }), 401: errorResponseSchema, }, summary: 'List token transaction history', }, verifyTokenPayment: { method: 'POST', path: '/shopkeeper/wallet/verify-payment', body: verifyTokenPaymentSchema, responses: { 200: z.object({ verified: z.boolean(), wallet: walletSchema.optional(), transaction: tokenTransactionSchema.optional(), }), 400: errorResponseSchema, 401: errorResponseSchema, }, summary: 'Verify Paystack payment for token purchase', }, tokenPaymentWebhook: { method: 'POST', path: '/shopkeeper/wallet/webhook/flutterwave', body: z.object({ event: z.string(), data: z.record(z.unknown()) }), responses: { 200: z.object({ received: z.boolean() }), 400: errorResponseSchema, }, summary: 'Legacy webhook endpoint (not used)', }, tokenPaymentWebhookPaystack: { method: 'POST', path: '/shopkeeper/wallet/webhook/paystack', body: z.object({ event: z.string().optional(), data: z.object({ reference: z.string().optional(), status: z.string().optional() }).passthrough().optional(), }), responses: { 200: z.object({ received: z.boolean() }), 400: errorResponseSchema, }, summary: 'Paystack payment webhook for token purchases (verify x-paystack-signature with raw body)', }, });