/** * Payments API * Functions for managing payment configuration (API keys and Connect) */ import apiClient from './client'; // ============================================================================ // Types // ============================================================================ export type PaymentMode = 'direct_api' | 'connect' | 'none'; export type KeyStatus = 'active' | 'invalid' | 'deprecated'; export type AccountStatus = 'pending' | 'onboarding' | 'active' | 'restricted' | 'rejected'; export interface ApiKeysInfo { id: number; status: KeyStatus; secret_key_masked: string; publishable_key_masked: string; last_validated_at: string | null; stripe_account_id: string; stripe_account_name: string; validation_error: string; created_at: string; updated_at: string; } export interface ConnectAccountInfo { id: number; business: number; business_name: string; business_subdomain: string; stripe_account_id: string; account_type: 'standard' | 'express' | 'custom'; status: AccountStatus; charges_enabled: boolean; payouts_enabled: boolean; details_submitted: boolean; onboarding_complete: boolean; onboarding_link: string | null; onboarding_link_expires_at: string | null; is_onboarding_link_valid: boolean; created_at: string; updated_at: string; } export interface PaymentConfig { payment_mode: PaymentMode; tier: string; can_accept_payments: boolean; api_keys: ApiKeysInfo | null; connect_account: ConnectAccountInfo | null; } export interface ApiKeysValidationResult { valid: boolean; account_id?: string; account_name?: string; environment?: string; error?: string; } export interface ApiKeysCurrentResponse { configured: boolean; id?: number; status?: KeyStatus; secret_key_masked?: string; publishable_key_masked?: string; last_validated_at?: string | null; stripe_account_id?: string; stripe_account_name?: string; validation_error?: string; message?: string; } export interface ConnectOnboardingResponse { account_type: 'standard' | 'custom'; url: string; stripe_account_id?: string; } export interface AccountSessionResponse { client_secret: string; stripe_account_id: string; publishable_key: string; } // ============================================================================ // Unified Configuration // ============================================================================ /** * Get unified payment configuration status. * Returns the complete payment setup for the business. */ export const getPaymentConfig = () => apiClient.get('/payments/config/status/'); // ============================================================================ // API Keys (Free Tier) // ============================================================================ /** * Get current API key configuration (masked keys). */ export const getApiKeys = () => apiClient.get('/payments/api-keys/'); /** * Save API keys. * Validates and stores the provided Stripe API keys. */ export const saveApiKeys = (secretKey: string, publishableKey: string) => apiClient.post('/payments/api-keys/', { secret_key: secretKey, publishable_key: publishableKey, }); /** * Validate API keys without saving. * Tests the keys against Stripe API. */ export const validateApiKeys = (secretKey: string, publishableKey: string) => apiClient.post('/payments/api-keys/validate/', { secret_key: secretKey, publishable_key: publishableKey, }); /** * Re-validate stored API keys. * Tests stored keys and updates their status. */ export const revalidateApiKeys = () => apiClient.post('/payments/api-keys/revalidate/'); /** * Delete stored API keys. */ export const deleteApiKeys = () => apiClient.delete<{ success: boolean; message: string }>('/payments/api-keys/delete/'); // ============================================================================ // Stripe Connect (Paid Tiers) // ============================================================================ /** * Get current Connect account status. */ export const getConnectStatus = () => apiClient.get('/payments/connect/status/'); /** * Initiate Connect account onboarding. * Returns a URL to redirect the user for Stripe onboarding. */ export const initiateConnectOnboarding = (refreshUrl: string, returnUrl: string) => apiClient.post('/payments/connect/onboard/', { refresh_url: refreshUrl, return_url: returnUrl, }); /** * Refresh Connect onboarding link. * For custom Connect accounts that need a new onboarding link. */ export const refreshConnectOnboardingLink = (refreshUrl: string, returnUrl: string) => apiClient.post<{ url: string }>('/payments/connect/refresh-link/', { refresh_url: refreshUrl, return_url: returnUrl, }); /** * Create an Account Session for embedded Connect onboarding. * Returns a client_secret for initializing Stripe's embedded Connect components. */ export const createAccountSession = () => apiClient.post('/payments/connect/account-session/'); /** * Refresh Connect account status from Stripe. * Syncs the local account record with the current state in Stripe. */ export const refreshConnectStatus = () => apiClient.post('/payments/connect/refresh-status/'); // ============================================================================ // Transaction Analytics // ============================================================================ export interface Transaction { id: number; business: number; business_name: string; stripe_payment_intent_id: string; stripe_charge_id: string; transaction_type: 'payment' | 'refund' | 'application_fee'; status: 'pending' | 'succeeded' | 'failed' | 'refunded' | 'partially_refunded'; amount: number; amount_display: string; application_fee_amount: number; fee_display: string; net_amount: number; currency: string; customer_email: string; customer_name: string; created_at: string; updated_at: string; stripe_data?: Record; } export interface TransactionListResponse { results: Transaction[]; count: number; page: number; page_size: number; total_pages: number; } export interface TransactionSummary { total_transactions: number; total_volume: number; total_volume_display: string; total_fees: number; total_fees_display: string; net_revenue: number; net_revenue_display: string; successful_transactions: number; failed_transactions: number; refunded_transactions: number; average_transaction: number; average_transaction_display: string; } export interface TransactionFilters { start_date?: string; end_date?: string; status?: 'all' | 'succeeded' | 'pending' | 'failed' | 'refunded'; transaction_type?: 'all' | 'payment' | 'refund' | 'application_fee'; page?: number; page_size?: number; } export interface StripeCharge { id: string; amount: number; amount_display: string; amount_refunded: number; currency: string; status: string; paid: boolean; refunded: boolean; description: string | null; receipt_email: string | null; receipt_url: string | null; created: number; payment_method_details: Record | null; billing_details: Record | null; } export interface ChargesResponse { charges: StripeCharge[]; has_more: boolean; } export interface StripePayout { id: string; amount: number; amount_display: string; currency: string; status: string; arrival_date: number | null; created: number; description: string | null; destination: string | null; failure_message: string | null; method: string; type: string; } export interface PayoutsResponse { payouts: StripePayout[]; has_more: boolean; } export interface BalanceItem { amount: number; currency: string; amount_display: string; } export interface BalanceResponse { available: BalanceItem[]; pending: BalanceItem[]; available_total: number; pending_total: number; } export interface ExportRequest { format: 'csv' | 'xlsx' | 'pdf' | 'quickbooks'; start_date?: string; end_date?: string; include_details?: boolean; } /** * Get list of transactions with optional filtering. */ export const getTransactions = (filters?: TransactionFilters) => { const params = new URLSearchParams(); if (filters?.start_date) params.append('start_date', filters.start_date); if (filters?.end_date) params.append('end_date', filters.end_date); if (filters?.status && filters.status !== 'all') params.append('status', filters.status); if (filters?.transaction_type && filters.transaction_type !== 'all') { params.append('transaction_type', filters.transaction_type); } if (filters?.page) params.append('page', String(filters.page)); if (filters?.page_size) params.append('page_size', String(filters.page_size)); const queryString = params.toString(); return apiClient.get( `/payments/transactions/${queryString ? `?${queryString}` : ''}` ); }; /** * Get a single transaction by ID. */ export const getTransaction = (id: number) => apiClient.get(`/payments/transactions/${id}/`); /** * Get transaction summary/analytics. */ export const getTransactionSummary = (filters?: Pick) => { const params = new URLSearchParams(); if (filters?.start_date) params.append('start_date', filters.start_date); if (filters?.end_date) params.append('end_date', filters.end_date); const queryString = params.toString(); return apiClient.get( `/payments/transactions/summary/${queryString ? `?${queryString}` : ''}` ); }; /** * Get charges from Stripe API. */ export const getStripeCharges = (limit: number = 20) => apiClient.get(`/payments/transactions/charges/?limit=${limit}`); /** * Get payouts from Stripe API. */ export const getStripePayouts = (limit: number = 20) => apiClient.get(`/payments/transactions/payouts/?limit=${limit}`); /** * Get current balance from Stripe API. */ export const getStripeBalance = () => apiClient.get('/payments/transactions/balance/'); /** * Export transaction data. * Returns the file data directly for download. */ export const exportTransactions = (request: ExportRequest) => apiClient.post('/payments/transactions/export/', request, { responseType: 'blob', }); // ============================================================================ // Transaction Details & Refunds // ============================================================================ export interface RefundInfo { id: string; amount: number; amount_display: string; status: string; reason: string | null; created: number; } export interface PaymentMethodInfo { type: string; brand?: string; last4?: string; exp_month?: number; exp_year?: number; funding?: string; bank_name?: string; } export interface TransactionDetail extends Transaction { refunds: RefundInfo[]; refundable_amount: number; total_refunded: number; can_refund: boolean; payment_method_info: PaymentMethodInfo | null; description: string; } export interface RefundRequest { amount?: number; reason?: 'duplicate' | 'fraudulent' | 'requested_by_customer'; metadata?: Record; } export interface RefundResponse { success: boolean; refund_id: string; amount: number; amount_display: string; status: string; reason: string | null; transaction_status: string; } /** * Get detailed transaction information including refund data. */ export const getTransactionDetail = (id: number) => apiClient.get(`/payments/transactions/${id}/`); /** * Issue a refund for a transaction. * @param transactionId - The ID of the transaction to refund * @param request - Optional refund request with amount and reason */ export const refundTransaction = (transactionId: number, request?: RefundRequest) => apiClient.post(`/payments/transactions/${transactionId}/refund/`, request || {});