paybridge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ /**
3
+ * SoftyComp payment provider
4
+ * South African bill presentment and debit order platform
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.SoftyCompProvider = void 0;
11
+ const crypto_1 = __importDefault(require("crypto"));
12
+ const base_1 = require("./base");
13
+ class SoftyCompProvider extends base_1.PaymentProvider {
14
+ constructor(config) {
15
+ super();
16
+ this.name = 'softycomp';
17
+ this.supportedCurrencies = ['ZAR'];
18
+ // Token cache
19
+ this.token = null;
20
+ this.tokenExpiry = 0;
21
+ this.apiKey = config.apiKey;
22
+ this.secretKey = config.secretKey;
23
+ this.sandbox = config.sandbox;
24
+ this.webhookSecret = config.webhookSecret;
25
+ // Base URL mapping
26
+ if (this.sandbox) {
27
+ this.baseUrl = 'https://sandbox.softycomp.co.za/SoftyCompBureauAPI';
28
+ }
29
+ else {
30
+ this.baseUrl = 'https://api.softycomp.co.za/SoftyCompBureauAPI';
31
+ }
32
+ }
33
+ // ==================== Authentication ====================
34
+ async authenticate() {
35
+ // Return cached token if still valid (with 60s buffer)
36
+ if (this.token && Date.now() < this.tokenExpiry - 60000) {
37
+ return this.token;
38
+ }
39
+ const response = await fetch(`${this.baseUrl}/api/auth/generatetoken`, {
40
+ method: 'POST',
41
+ headers: { 'Content-Type': 'application/json' },
42
+ body: JSON.stringify({
43
+ apiKey: this.apiKey,
44
+ apiSecret: this.secretKey,
45
+ }),
46
+ });
47
+ if (!response.ok) {
48
+ const errorText = await response.text();
49
+ throw new Error(`SoftyComp authentication failed: ${response.status} - ${errorText}`);
50
+ }
51
+ const data = (await response.json());
52
+ this.token = data.token;
53
+ this.tokenExpiry = new Date(data.expiration).getTime();
54
+ return this.token;
55
+ }
56
+ async apiRequest(method, path, data) {
57
+ const token = await this.authenticate();
58
+ const url = `${this.baseUrl}${path}`;
59
+ const response = await fetch(url, {
60
+ method,
61
+ headers: {
62
+ Authorization: `Bearer ${token}`,
63
+ 'Content-Type': 'application/json',
64
+ },
65
+ body: data ? JSON.stringify(data) : undefined,
66
+ });
67
+ if (!response.ok) {
68
+ const errorText = await response.text();
69
+ throw new Error(`SoftyComp API error (${method} ${path}): ${response.status} - ${errorText}`);
70
+ }
71
+ const contentType = response.headers.get('content-type');
72
+ if (contentType && contentType.includes('application/json')) {
73
+ return (await response.json());
74
+ }
75
+ return (await response.text());
76
+ }
77
+ // ==================== Payment Methods ====================
78
+ async createPayment(params) {
79
+ this.validateCurrency(params.currency);
80
+ // Build the bill item (once-off payment)
81
+ const item = {
82
+ Description: params.description || 'Payment',
83
+ Amount: parseFloat(params.amount.toFixed(2)),
84
+ FrequencyTypeID: 1, // Once-off
85
+ DisplayCompanyName: 'Your Company',
86
+ DisplayCompanyContactNo: '',
87
+ DisplayCompanyEmailAddress: params.customer.email,
88
+ };
89
+ // Build the bill request
90
+ const billData = {
91
+ Name: params.customer.name,
92
+ ModeTypeID: 4, // Plugin mode (returns payment URL)
93
+ Emailaddress: params.customer.email,
94
+ Cellno: params.customer.phone || '',
95
+ UserReference: params.reference,
96
+ Items: [item],
97
+ ScheduledDateTime: null,
98
+ CallbackUrl: params.urls.webhook,
99
+ SuccessURL: params.urls.success,
100
+ FailURL: params.urls.cancel,
101
+ NotifyURL: params.urls.webhook,
102
+ CancelURL: params.urls.cancel,
103
+ };
104
+ const result = await this.apiRequest('POST', '/api/paygatecontroller/requestbillpresentment', billData);
105
+ if (!result.success) {
106
+ throw new Error(`Failed to create payment: ${result.message}`);
107
+ }
108
+ return {
109
+ id: result.reference,
110
+ checkoutUrl: result.paymentURL,
111
+ status: 'pending',
112
+ amount: params.amount,
113
+ currency: params.currency,
114
+ reference: params.reference,
115
+ provider: 'softycomp',
116
+ createdAt: new Date().toISOString(),
117
+ expiresAt: new Date(Date.now() + 30 * 60 * 1000).toISOString(),
118
+ raw: result,
119
+ };
120
+ }
121
+ async createSubscription(params) {
122
+ this.validateCurrency(params.currency);
123
+ // Map interval to SoftyComp frequency: 2=monthly, 7=yearly
124
+ let frequencyTypeID;
125
+ if (params.interval === 'monthly') {
126
+ frequencyTypeID = 2;
127
+ }
128
+ else if (params.interval === 'yearly') {
129
+ frequencyTypeID = 7;
130
+ }
131
+ else {
132
+ throw new Error(`SoftyComp does not support ${params.interval} subscriptions. Use monthly or yearly.`);
133
+ }
134
+ // Parse and validate start date
135
+ let startDate;
136
+ if (params.startDate) {
137
+ this.validateFutureDate(params.startDate, 'startDate');
138
+ startDate = new Date(params.startDate);
139
+ }
140
+ else {
141
+ // Default to tomorrow
142
+ startDate = new Date();
143
+ startDate.setDate(startDate.getDate() + 1);
144
+ }
145
+ // Build the bill item (recurring)
146
+ const item = {
147
+ Description: params.description || 'Subscription',
148
+ Amount: parseFloat(params.amount.toFixed(2)),
149
+ FrequencyTypeID: frequencyTypeID,
150
+ DisplayCompanyName: 'Your Company',
151
+ DisplayCompanyContactNo: '',
152
+ DisplayCompanyEmailAddress: params.customer.email,
153
+ CommencementDate: startDate.toISOString().split('T')[0],
154
+ RecurringDay: params.billingDay || startDate.getDate(),
155
+ RecurringMonth: params.interval === 'yearly' ? startDate.getMonth() + 1 : null,
156
+ DayOfWeek: null,
157
+ ExpiryDate: null,
158
+ InitialAmount: null,
159
+ ToCollectAmount: null,
160
+ };
161
+ // Build the bill request
162
+ const billData = {
163
+ Name: params.customer.name,
164
+ ModeTypeID: 4,
165
+ Emailaddress: params.customer.email,
166
+ Cellno: params.customer.phone || '',
167
+ UserReference: params.reference,
168
+ Items: [item],
169
+ ScheduledDateTime: null,
170
+ CallbackUrl: params.urls.webhook,
171
+ SuccessURL: params.urls.success,
172
+ FailURL: params.urls.cancel,
173
+ NotifyURL: params.urls.webhook,
174
+ CancelURL: params.urls.cancel,
175
+ };
176
+ const result = await this.apiRequest('POST', '/api/paygatecontroller/requestbillpresentment', billData);
177
+ if (!result.success) {
178
+ throw new Error(`Failed to create subscription: ${result.message}`);
179
+ }
180
+ return {
181
+ id: result.reference,
182
+ checkoutUrl: result.paymentURL,
183
+ status: 'pending',
184
+ amount: params.amount,
185
+ currency: params.currency,
186
+ interval: params.interval,
187
+ reference: params.reference,
188
+ provider: 'softycomp',
189
+ startsAt: startDate.toISOString(),
190
+ createdAt: new Date().toISOString(),
191
+ raw: result,
192
+ };
193
+ }
194
+ async getPayment(id) {
195
+ const result = await this.apiRequest('GET', `/api/paygatecontroller/listBillPresentmentDetails/${id}/${id}`);
196
+ // Map status: 1=pending, 2=completed, 3=failed, 4/5=cancelled
197
+ const statusTypeID = result?.statusTypeID || result?.status || 1;
198
+ const status = this.mapBillStatus(statusTypeID);
199
+ return {
200
+ id: result?.reference || id,
201
+ checkoutUrl: '', // Not available from status endpoint
202
+ status,
203
+ amount: parseFloat(result?.amount || '0'),
204
+ currency: 'ZAR',
205
+ reference: result?.userReference || id,
206
+ provider: 'softycomp',
207
+ createdAt: result?.createdDate || new Date().toISOString(),
208
+ raw: result,
209
+ };
210
+ }
211
+ async refund(params) {
212
+ const refundData = {
213
+ Reference: params.paymentId,
214
+ UserReference: params.paymentId,
215
+ };
216
+ if (params.amount !== undefined) {
217
+ refundData.Amount = parseFloat(params.amount.toFixed(2));
218
+ }
219
+ const result = await this.apiRequest('POST', '/api/paygatecontroller/requestCreditTransaction', refundData);
220
+ return {
221
+ id: result?.reference || `refund_${params.paymentId}_${Date.now()}`,
222
+ status: result?.success ? 'completed' : 'pending',
223
+ amount: params.amount || 0,
224
+ currency: 'ZAR',
225
+ paymentId: params.paymentId,
226
+ createdAt: new Date().toISOString(),
227
+ raw: result,
228
+ };
229
+ }
230
+ // ==================== Webhooks ====================
231
+ parseWebhook(body, _headers) {
232
+ const event = typeof body === 'string' ? JSON.parse(body) : body;
233
+ // activityTypeID mapping: 1=Pending, 2=Successful, 3=Failed, 4=Cancelled
234
+ let eventType = 'payment.pending';
235
+ let status = 'pending';
236
+ switch (event.activityTypeID) {
237
+ case 2:
238
+ eventType = 'payment.completed';
239
+ status = 'completed';
240
+ break;
241
+ case 3:
242
+ eventType = 'payment.failed';
243
+ status = 'failed';
244
+ break;
245
+ case 4:
246
+ eventType = 'payment.cancelled';
247
+ status = 'cancelled';
248
+ break;
249
+ default:
250
+ eventType = 'payment.pending';
251
+ status = 'pending';
252
+ }
253
+ return {
254
+ type: eventType,
255
+ payment: {
256
+ id: event.reference,
257
+ checkoutUrl: '',
258
+ status,
259
+ amount: event.amount,
260
+ currency: 'ZAR',
261
+ reference: event.userReference,
262
+ provider: 'softycomp',
263
+ createdAt: event.transactionDate,
264
+ },
265
+ raw: event,
266
+ };
267
+ }
268
+ verifyWebhook(body, headers) {
269
+ const signature = headers?.signature || headers?.['x-signature'];
270
+ if (!signature || !this.webhookSecret) {
271
+ // No signature validation configured
272
+ return true;
273
+ }
274
+ const expectedSignature = crypto_1.default
275
+ .createHmac('sha256', this.webhookSecret)
276
+ .update(body)
277
+ .digest('hex');
278
+ return signature === expectedSignature || signature === `sha256=${expectedSignature}`;
279
+ }
280
+ // ==================== Helpers ====================
281
+ mapBillStatus(statusTypeID) {
282
+ switch (Number(statusTypeID)) {
283
+ case 1: return 'pending'; // New
284
+ case 2: return 'completed'; // Paid
285
+ case 3: return 'failed'; // Failed
286
+ case 4: return 'cancelled'; // Expired
287
+ case 5: return 'cancelled'; // Cancelled
288
+ default: return 'pending';
289
+ }
290
+ }
291
+ }
292
+ exports.SoftyCompProvider = SoftyCompProvider;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Yoco payment provider
3
+ * South African online payment gateway
4
+ * @see https://developer.yoco.com
5
+ */
6
+ import { PaymentProvider } from './base';
7
+ import { CreatePaymentParams, PaymentResult, CreateSubscriptionParams, SubscriptionResult, RefundParams, RefundResult, WebhookEvent } from '../types';
8
+ interface YocoConfig {
9
+ apiKey: string;
10
+ sandbox: boolean;
11
+ webhookSecret?: string;
12
+ }
13
+ export declare class YocoProvider extends PaymentProvider {
14
+ readonly name = "yoco";
15
+ readonly supportedCurrencies: string[];
16
+ private apiKey;
17
+ private sandbox;
18
+ private baseUrl;
19
+ private webhookSecret?;
20
+ constructor(config: YocoConfig);
21
+ createPayment(params: CreatePaymentParams): Promise<PaymentResult>;
22
+ createSubscription(params: CreateSubscriptionParams): Promise<SubscriptionResult>;
23
+ getPayment(id: string): Promise<PaymentResult>;
24
+ refund(params: RefundParams): Promise<RefundResult>;
25
+ parseWebhook(body: any, _headers?: any): WebhookEvent;
26
+ verifyWebhook(body: string | Buffer, headers?: any): boolean;
27
+ private mapYocoStatus;
28
+ private mapYocoEventType;
29
+ }
30
+ export {};
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * Yoco payment provider
4
+ * South African online payment gateway
5
+ * @see https://developer.yoco.com
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.YocoProvider = void 0;
12
+ const crypto_1 = __importDefault(require("crypto"));
13
+ const base_1 = require("./base");
14
+ const currency_1 = require("../utils/currency");
15
+ class YocoProvider extends base_1.PaymentProvider {
16
+ constructor(config) {
17
+ super();
18
+ this.name = 'yoco';
19
+ this.supportedCurrencies = ['ZAR'];
20
+ this.apiKey = config.apiKey;
21
+ this.sandbox = config.sandbox;
22
+ this.webhookSecret = config.webhookSecret;
23
+ // Yoco uses same API for sandbox and production, differentiated by API keys
24
+ this.baseUrl = 'https://payments.yoco.com/api/v1';
25
+ }
26
+ // ==================== Payment Methods ====================
27
+ async createPayment(params) {
28
+ this.validateCurrency(params.currency);
29
+ // TODO: Implement Yoco checkout creation
30
+ // POST /v1/checkouts
31
+ // Amount must be in CENTS (minor unit)
32
+ // Auth: Bearer {secret_key}
33
+ // Body: {
34
+ // amount: 29900, // cents
35
+ // currency: "ZAR",
36
+ // cancelUrl: "...",
37
+ // successUrl: "...",
38
+ // failureUrl: "...",
39
+ // metadata: { ... }
40
+ // }
41
+ const amountInCents = (0, currency_1.toMinorUnit)(params.amount, params.currency);
42
+ const requestBody = {
43
+ amount: amountInCents,
44
+ currency: params.currency,
45
+ cancelUrl: params.urls.cancel,
46
+ successUrl: params.urls.success,
47
+ failureUrl: params.urls.cancel,
48
+ metadata: {
49
+ reference: params.reference,
50
+ description: params.description,
51
+ customerName: params.customer.name,
52
+ customerEmail: params.customer.email,
53
+ ...params.metadata,
54
+ },
55
+ };
56
+ // TODO: Make actual API request
57
+ console.warn('[PayBridge:Yoco] createPayment not yet implemented:', requestBody);
58
+ throw new Error('Yoco provider not yet fully implemented. Coming soon!');
59
+ }
60
+ async createSubscription(params) {
61
+ this.validateCurrency(params.currency);
62
+ // TODO: Implement Yoco subscription creation
63
+ // Yoco may not support subscriptions directly - need to check their API
64
+ // May need to implement via recurring charges or use Yoco recurring billing
65
+ console.warn('[PayBridge:Yoco] createSubscription not yet implemented');
66
+ throw new Error('Yoco subscriptions not yet implemented. Coming soon!');
67
+ }
68
+ async getPayment(id) {
69
+ // TODO: Implement Yoco payment status check
70
+ // GET /v1/checkouts/{id}
71
+ // Auth: Bearer {secret_key}
72
+ console.warn('[PayBridge:Yoco] getPayment not yet implemented:', id);
73
+ throw new Error('Yoco getPayment not yet implemented. Coming soon!');
74
+ }
75
+ async refund(params) {
76
+ // TODO: Implement Yoco refund
77
+ // POST /v1/refunds
78
+ // Amount in CENTS
79
+ // Auth: Bearer {secret_key}
80
+ // Body: {
81
+ // paymentId: "...",
82
+ // amount: 29900 // cents, optional for partial refund
83
+ // }
84
+ const amountInCents = params.amount ? (0, currency_1.toMinorUnit)(params.amount, 'ZAR') : undefined;
85
+ console.warn('[PayBridge:Yoco] refund not yet implemented:', { ...params, amountInCents });
86
+ throw new Error('Yoco refunds not yet implemented. Coming soon!');
87
+ }
88
+ // ==================== Webhooks ====================
89
+ parseWebhook(body, _headers) {
90
+ const event = typeof body === 'string' ? JSON.parse(body) : body;
91
+ // TODO: Map Yoco webhook structure to PayBridge WebhookEvent
92
+ // Yoco webhook payload structure:
93
+ // {
94
+ // type: "payment.succeeded" | "payment.failed" | "payment.refunded",
95
+ // payload: {
96
+ // id: "...",
97
+ // amount: 29900, // cents
98
+ // currency: "ZAR",
99
+ // status: "succeeded" | "failed" | "refunded",
100
+ // metadata: { ... }
101
+ // }
102
+ // }
103
+ const yocoStatus = event.payload?.status || event.status;
104
+ const status = this.mapYocoStatus(yocoStatus);
105
+ const eventType = this.mapYocoEventType(event.type);
106
+ return {
107
+ type: eventType,
108
+ payment: {
109
+ id: event.payload?.id || event.id,
110
+ checkoutUrl: '',
111
+ status,
112
+ amount: (0, currency_1.toMajorUnit)(event.payload?.amount || 0, 'ZAR'),
113
+ currency: 'ZAR',
114
+ reference: event.payload?.metadata?.reference || '',
115
+ provider: 'yoco',
116
+ createdAt: event.payload?.createdDate || new Date().toISOString(),
117
+ },
118
+ raw: event,
119
+ };
120
+ }
121
+ verifyWebhook(body, headers) {
122
+ const signature = headers?.['x-yoco-signature'] || headers?.signature;
123
+ if (!signature || !this.webhookSecret) {
124
+ // No signature validation configured
125
+ return true;
126
+ }
127
+ // TODO: Implement Yoco signature validation
128
+ // Yoco uses HMAC-SHA256 with X-Yoco-Signature header
129
+ const expectedSignature = crypto_1.default
130
+ .createHmac('sha256', this.webhookSecret)
131
+ .update(body)
132
+ .digest('hex');
133
+ return signature === expectedSignature;
134
+ }
135
+ // ==================== Helpers ====================
136
+ mapYocoStatus(yocoStatus) {
137
+ const statusMap = {
138
+ succeeded: 'completed',
139
+ successful: 'completed',
140
+ failed: 'failed',
141
+ cancelled: 'cancelled',
142
+ refunded: 'refunded',
143
+ pending: 'pending',
144
+ };
145
+ return statusMap[yocoStatus?.toLowerCase()] || 'pending';
146
+ }
147
+ mapYocoEventType(yocoType) {
148
+ const typeMap = {
149
+ 'payment.succeeded': 'payment.completed',
150
+ 'payment.successful': 'payment.completed',
151
+ 'payment.failed': 'payment.failed',
152
+ 'payment.cancelled': 'payment.cancelled',
153
+ 'payment.refunded': 'refund.completed',
154
+ };
155
+ return typeMap[yocoType] || 'payment.pending';
156
+ }
157
+ }
158
+ exports.YocoProvider = YocoProvider;
@@ -0,0 +1,167 @@
1
+ /**
2
+ * PayBridge — Unified payment SDK types
3
+ */
4
+ export type Provider = 'softycomp' | 'yoco' | 'ozow' | 'payfast' | 'paystack' | 'stripe' | 'peach';
5
+ export type PaymentStatus = 'pending' | 'completed' | 'failed' | 'cancelled' | 'refunded';
6
+ export type SubscriptionInterval = 'weekly' | 'monthly' | 'yearly';
7
+ export type Currency = 'ZAR' | 'USD' | 'EUR' | 'GBP' | 'NGN';
8
+ export type WebhookEventType = 'payment.pending' | 'payment.completed' | 'payment.failed' | 'payment.cancelled' | 'subscription.created' | 'subscription.cancelled' | 'refund.completed';
9
+ export interface PayBridgeConfig {
10
+ /** Payment provider to use */
11
+ provider: Provider;
12
+ /** Provider-specific credentials */
13
+ credentials: {
14
+ /** API key or merchant ID */
15
+ apiKey?: string;
16
+ /** Secret key or merchant key */
17
+ secretKey?: string;
18
+ /** Additional provider-specific credentials */
19
+ [key: string]: any;
20
+ };
21
+ /** Use sandbox/test environment */
22
+ sandbox?: boolean;
23
+ /** Optional webhook secret for signature validation */
24
+ webhookSecret?: string;
25
+ }
26
+ export interface Customer {
27
+ /** Customer full name */
28
+ name: string;
29
+ /** Customer email address */
30
+ email: string;
31
+ /** Customer phone number (e.g. "0825551234" or "+27825551234") */
32
+ phone?: string;
33
+ /** Customer ID in your system */
34
+ customerId?: string;
35
+ }
36
+ export interface CreatePaymentParams {
37
+ /** Amount in major currency unit (e.g. 299.00 for R299) */
38
+ amount: number;
39
+ /** Currency code (ISO 4217) */
40
+ currency: Currency;
41
+ /** Your internal reference/invoice number */
42
+ reference: string;
43
+ /** Payment description */
44
+ description?: string;
45
+ /** Customer details */
46
+ customer: Customer;
47
+ /** Redirect URLs */
48
+ urls: {
49
+ /** URL to redirect customer after successful payment */
50
+ success: string;
51
+ /** URL to redirect customer after cancelled payment */
52
+ cancel: string;
53
+ /** URL to receive webhook notifications */
54
+ webhook: string;
55
+ };
56
+ /** Additional metadata (up to 10 key-value pairs) */
57
+ metadata?: Record<string, any>;
58
+ }
59
+ export interface PaymentResult {
60
+ /** Unique payment ID from provider */
61
+ id: string;
62
+ /** Payment checkout URL (redirect customer here) */
63
+ checkoutUrl: string;
64
+ /** Payment status */
65
+ status: PaymentStatus;
66
+ /** Amount in major currency unit */
67
+ amount: number;
68
+ /** Currency code */
69
+ currency: Currency;
70
+ /** Your reference */
71
+ reference: string;
72
+ /** Provider name */
73
+ provider: Provider;
74
+ /** ISO 8601 timestamp when payment was created */
75
+ createdAt: string;
76
+ /** ISO 8601 timestamp when checkout URL expires (if applicable) */
77
+ expiresAt?: string;
78
+ /** Raw provider response */
79
+ raw?: any;
80
+ }
81
+ export interface CreateSubscriptionParams {
82
+ /** Amount in major currency unit (e.g. 299.00 for R299) */
83
+ amount: number;
84
+ /** Currency code (ISO 4217) */
85
+ currency: Currency;
86
+ /** Billing interval */
87
+ interval: SubscriptionInterval;
88
+ /** Your internal subscription reference */
89
+ reference: string;
90
+ /** Subscription description */
91
+ description?: string;
92
+ /** Customer details */
93
+ customer: Customer;
94
+ /** Redirect URLs */
95
+ urls: {
96
+ /** URL to redirect customer after successful setup */
97
+ success: string;
98
+ /** URL to redirect customer after cancelled setup */
99
+ cancel: string;
100
+ /** URL to receive webhook notifications */
101
+ webhook: string;
102
+ };
103
+ /** Subscription start date (ISO 8601). Must be future date. */
104
+ startDate?: string;
105
+ /** Day of month to charge (1-28). Only for monthly subscriptions. */
106
+ billingDay?: number;
107
+ /** Additional metadata */
108
+ metadata?: Record<string, any>;
109
+ }
110
+ export interface SubscriptionResult {
111
+ /** Unique subscription ID from provider */
112
+ id: string;
113
+ /** Subscription setup URL (redirect customer here) */
114
+ checkoutUrl: string;
115
+ /** Subscription status */
116
+ status: 'pending' | 'active' | 'cancelled' | 'expired';
117
+ /** Amount in major currency unit */
118
+ amount: number;
119
+ /** Currency code */
120
+ currency: Currency;
121
+ /** Billing interval */
122
+ interval: SubscriptionInterval;
123
+ /** Your reference */
124
+ reference: string;
125
+ /** Provider name */
126
+ provider: Provider;
127
+ /** ISO 8601 timestamp when subscription starts */
128
+ startsAt?: string;
129
+ /** ISO 8601 timestamp when subscription was created */
130
+ createdAt: string;
131
+ /** Raw provider response */
132
+ raw?: any;
133
+ }
134
+ export interface RefundParams {
135
+ /** Original payment ID to refund */
136
+ paymentId: string;
137
+ /** Amount to refund in major currency unit. Omit for full refund. */
138
+ amount?: number;
139
+ /** Reason for refund */
140
+ reason?: string;
141
+ }
142
+ export interface RefundResult {
143
+ /** Refund ID */
144
+ id: string;
145
+ /** Refund status */
146
+ status: 'pending' | 'completed' | 'failed';
147
+ /** Amount refunded in major currency unit */
148
+ amount: number;
149
+ /** Currency code */
150
+ currency: Currency;
151
+ /** Original payment ID */
152
+ paymentId: string;
153
+ /** ISO 8601 timestamp when refund was created */
154
+ createdAt: string;
155
+ /** Raw provider response */
156
+ raw?: any;
157
+ }
158
+ export interface WebhookEvent {
159
+ /** Event type */
160
+ type: WebhookEventType;
161
+ /** Payment or subscription details */
162
+ payment?: PaymentResult;
163
+ subscription?: SubscriptionResult;
164
+ refund?: RefundResult;
165
+ /** Raw provider payload */
166
+ raw: any;
167
+ }
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * PayBridge — Unified payment SDK types
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Currency conversion utilities
3
+ */
4
+ import { Currency } from '../types';
5
+ /**
6
+ * Convert major currency unit to minor unit (cents)
7
+ * @example toMinorUnit(299.00, 'ZAR') => 29900
8
+ */
9
+ export declare function toMinorUnit(amount: number, currency: Currency): number;
10
+ /**
11
+ * Convert minor unit (cents) to major currency unit
12
+ * @example toMajorUnit(29900, 'ZAR') => 299.00
13
+ */
14
+ export declare function toMajorUnit(amount: number, currency: Currency): number;
15
+ /**
16
+ * Get decimal places for currency
17
+ * Most currencies use 2 decimal places, some use 0
18
+ */
19
+ export declare function getDecimalPlaces(currency: Currency): number;
20
+ /**
21
+ * Format amount with currency symbol
22
+ * @example formatCurrency(299.00, 'ZAR') => "R299.00"
23
+ */
24
+ export declare function formatCurrency(amount: number, currency: Currency): string;
25
+ /**
26
+ * Validate amount is positive and has correct decimal places
27
+ */
28
+ export declare function validateAmount(amount: number, currency: Currency): void;