payment-skill 1.0.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.
Files changed (110) hide show
  1. package/LICENSE +62 -0
  2. package/README.md +545 -0
  3. package/SKILL.md +99 -0
  4. package/SUPPORT.md +153 -0
  5. package/bin/payment-skill.js +2 -0
  6. package/dashboard.html +669 -0
  7. package/dist/api/bunq.d.ts +35 -0
  8. package/dist/api/bunq.d.ts.map +1 -0
  9. package/dist/api/bunq.js +164 -0
  10. package/dist/api/bunq.js.map +1 -0
  11. package/dist/api/wise.d.ts +32 -0
  12. package/dist/api/wise.d.ts.map +1 -0
  13. package/dist/api/wise.js +155 -0
  14. package/dist/api/wise.js.map +1 -0
  15. package/dist/cli.d.ts +8 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +69 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/commands/bunq.d.ts +8 -0
  20. package/dist/commands/bunq.d.ts.map +1 -0
  21. package/dist/commands/bunq.js +193 -0
  22. package/dist/commands/bunq.js.map +1 -0
  23. package/dist/commands/config.d.ts +8 -0
  24. package/dist/commands/config.d.ts.map +1 -0
  25. package/dist/commands/config.js +70 -0
  26. package/dist/commands/config.js.map +1 -0
  27. package/dist/commands/emergency.d.ts +8 -0
  28. package/dist/commands/emergency.d.ts.map +1 -0
  29. package/dist/commands/emergency.js +85 -0
  30. package/dist/commands/emergency.js.map +1 -0
  31. package/dist/commands/limits.d.ts +6 -0
  32. package/dist/commands/limits.d.ts.map +1 -0
  33. package/dist/commands/limits.js +125 -0
  34. package/dist/commands/limits.js.map +1 -0
  35. package/dist/commands/merchant.d.ts +6 -0
  36. package/dist/commands/merchant.d.ts.map +1 -0
  37. package/dist/commands/merchant.js +41 -0
  38. package/dist/commands/merchant.js.map +1 -0
  39. package/dist/commands/pay.d.ts +10 -0
  40. package/dist/commands/pay.d.ts.map +1 -0
  41. package/dist/commands/pay.js +112 -0
  42. package/dist/commands/pay.js.map +1 -0
  43. package/dist/commands/provider.d.ts +6 -0
  44. package/dist/commands/provider.d.ts.map +1 -0
  45. package/dist/commands/provider.js +74 -0
  46. package/dist/commands/provider.js.map +1 -0
  47. package/dist/commands/server.d.ts +8 -0
  48. package/dist/commands/server.d.ts.map +1 -0
  49. package/dist/commands/server.js +92 -0
  50. package/dist/commands/server.js.map +1 -0
  51. package/dist/commands/template.d.ts +8 -0
  52. package/dist/commands/template.d.ts.map +1 -0
  53. package/dist/commands/template.js +161 -0
  54. package/dist/commands/template.js.map +1 -0
  55. package/dist/commands/transaction.d.ts +6 -0
  56. package/dist/commands/transaction.d.ts.map +1 -0
  57. package/dist/commands/transaction.js +72 -0
  58. package/dist/commands/transaction.js.map +1 -0
  59. package/dist/commands/wise.d.ts +8 -0
  60. package/dist/commands/wise.d.ts.map +1 -0
  61. package/dist/commands/wise.js +240 -0
  62. package/dist/commands/wise.js.map +1 -0
  63. package/dist/core/config.d.ts +40 -0
  64. package/dist/core/config.d.ts.map +1 -0
  65. package/dist/core/config.js +201 -0
  66. package/dist/core/config.js.map +1 -0
  67. package/dist/core/template-engine.d.ts +27 -0
  68. package/dist/core/template-engine.d.ts.map +1 -0
  69. package/dist/core/template-engine.js +410 -0
  70. package/dist/core/template-engine.js.map +1 -0
  71. package/dist/core/transaction.d.ts +31 -0
  72. package/dist/core/transaction.d.ts.map +1 -0
  73. package/dist/core/transaction.js +214 -0
  74. package/dist/core/transaction.js.map +1 -0
  75. package/dist/index.d.ts +12 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +36 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/server/server.d.ts +14 -0
  80. package/dist/server/server.d.ts.map +1 -0
  81. package/dist/server/server.js +120 -0
  82. package/dist/server/server.js.map +1 -0
  83. package/dist/types/index.d.ts +141 -0
  84. package/dist/types/index.d.ts.map +1 -0
  85. package/dist/types/index.js +8 -0
  86. package/dist/types/index.js.map +1 -0
  87. package/logo.png +0 -0
  88. package/package.json +78 -0
  89. package/src/api/bunq.ts +257 -0
  90. package/src/api/wise.ts +204 -0
  91. package/src/cli.ts +67 -0
  92. package/src/commands/bunq.ts +223 -0
  93. package/src/commands/config.ts +72 -0
  94. package/src/commands/emergency.ts +94 -0
  95. package/src/commands/limits.ts +126 -0
  96. package/src/commands/merchant.ts +39 -0
  97. package/src/commands/pay.ts +109 -0
  98. package/src/commands/provider.ts +75 -0
  99. package/src/commands/server.ts +59 -0
  100. package/src/commands/template.ts +172 -0
  101. package/src/commands/transaction.ts +66 -0
  102. package/src/commands/wise.ts +279 -0
  103. package/src/core/config.ts +202 -0
  104. package/src/core/template-engine.ts +454 -0
  105. package/src/core/transaction.ts +228 -0
  106. package/src/index.ts +14 -0
  107. package/src/server/server.ts +131 -0
  108. package/src/types/index.ts +178 -0
  109. package/tsconfig.json +23 -0
  110. package/verified-merchants.json +63 -0
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Payment Skill - Transaction Manager
3
+ *
4
+ * Manages all transactions, their states, and lifecycle
5
+ */
6
+
7
+ import * as fs from 'fs-extra';
8
+ import * as path from 'path';
9
+ import { Transaction, TransactionStatus } from '../types';
10
+ import { configManager } from './config';
11
+
12
+ const DATA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.payment-skill');
13
+ const TRANSACTIONS_FILE = path.join(DATA_DIR, 'transactions.json');
14
+
15
+ export class TransactionManager {
16
+ private transactions: Map<string, Transaction> = new Map();
17
+
18
+ constructor() {
19
+ this.loadTransactions();
20
+ }
21
+
22
+ private loadTransactions(): void {
23
+ if (fs.existsSync(TRANSACTIONS_FILE)) {
24
+ const data = fs.readJsonSync(TRANSACTIONS_FILE);
25
+ Object.entries(data).forEach(([id, tx]: [string, any]) => {
26
+ this.transactions.set(id, {
27
+ ...tx,
28
+ createdAt: new Date(tx.createdAt),
29
+ updatedAt: new Date(tx.updatedAt)
30
+ });
31
+ });
32
+ }
33
+ }
34
+
35
+ private saveTransactions(): void {
36
+ const data: Record<string, Transaction> = {};
37
+ this.transactions.forEach((tx, id) => {
38
+ data[id] = tx;
39
+ });
40
+ fs.writeJsonSync(TRANSACTIONS_FILE, data, { spaces: 2 });
41
+ }
42
+
43
+ createTransaction(
44
+ provider: string,
45
+ merchant: string,
46
+ amount: number,
47
+ currency: string,
48
+ metadata?: Record<string, any>
49
+ ): Transaction {
50
+ // Check emergency stop
51
+ if (configManager.isEmergencyStopActive()) {
52
+ throw new Error('Emergency stop is active. Cannot create new transactions.');
53
+ }
54
+
55
+ // Check limits
56
+ this.checkLimits(amount, currency);
57
+
58
+ const transaction: Transaction = {
59
+ id: this.generateTransactionId(),
60
+ provider,
61
+ merchant,
62
+ amount,
63
+ currency: currency.toUpperCase(),
64
+ status: 'pending',
65
+ createdAt: new Date(),
66
+ updatedAt: new Date(),
67
+ metadata
68
+ };
69
+
70
+ this.transactions.set(transaction.id, transaction);
71
+ this.saveTransactions();
72
+
73
+ return transaction;
74
+ }
75
+
76
+ private generateTransactionId(): string {
77
+ return `tx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
78
+ }
79
+
80
+ private checkLimits(amount: number, currency: string): void {
81
+ const limits = configManager.getLimits();
82
+
83
+ // Check per-transaction limit
84
+ if (amount > limits.perTransaction) {
85
+ throw new Error(`Amount ${amount} exceeds per-transaction limit of ${limits.perTransaction}`);
86
+ }
87
+
88
+ // Check daily limit
89
+ const today = new Date().toDateString();
90
+ const dailyTotal = this.getDailyTotal(today);
91
+ if (dailyTotal + amount > limits.daily) {
92
+ throw new Error(`Daily limit of ${limits.daily} would be exceeded`);
93
+ }
94
+
95
+ // Check hourly transaction count
96
+ const hourlyCount = this.getHourlyTransactionCount();
97
+ if (hourlyCount >= limits.maxTransactionsPerHour) {
98
+ throw new Error(`Hourly transaction limit of ${limits.maxTransactionsPerHour} reached`);
99
+ }
100
+
101
+ // Check time window
102
+ const timeWindow = configManager.getTimeWindow();
103
+ if (timeWindow.enabled) {
104
+ const now = new Date();
105
+ const currentTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
106
+
107
+ if (currentTime < timeWindow.start || currentTime > timeWindow.end) {
108
+ throw new Error(`Transactions not allowed outside time window ${timeWindow.start}-${timeWindow.end}`);
109
+ }
110
+ }
111
+ }
112
+
113
+ private getDailyTotal(date: string): number {
114
+ let total = 0;
115
+ this.transactions.forEach(tx => {
116
+ if (tx.createdAt.toDateString() === date &&
117
+ (tx.status === 'completed' || tx.status === 'processing')) {
118
+ total += tx.amount;
119
+ }
120
+ });
121
+ return total;
122
+ }
123
+
124
+ private getHourlyTransactionCount(): number {
125
+ const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
126
+ let count = 0;
127
+ this.transactions.forEach(tx => {
128
+ if (tx.createdAt > oneHourAgo &&
129
+ (tx.status === 'pending' || tx.status === 'processing' || tx.status === 'completed')) {
130
+ count++;
131
+ }
132
+ });
133
+ return count;
134
+ }
135
+
136
+ updateTransactionStatus(
137
+ transactionId: string,
138
+ status: TransactionStatus,
139
+ error?: string
140
+ ): Transaction {
141
+ const tx = this.transactions.get(transactionId);
142
+ if (!tx) {
143
+ throw new Error(`Transaction ${transactionId} not found`);
144
+ }
145
+
146
+ // If emergency stop is active, only allow cancellation
147
+ if (configManager.isEmergencyStopActive() && status !== 'cancelled') {
148
+ throw new Error('Emergency stop is active. Only cancellation allowed.');
149
+ }
150
+
151
+ tx.status = status;
152
+ tx.updatedAt = new Date();
153
+ if (error) {
154
+ tx.error = error;
155
+ }
156
+
157
+ this.transactions.set(transactionId, tx);
158
+ this.saveTransactions();
159
+
160
+ // Update emergency stop pending list
161
+ if (status === 'processing') {
162
+ configManager.addPendingTransaction(transactionId);
163
+ } else if (['completed', 'failed', 'cancelled'].includes(status)) {
164
+ configManager.removePendingTransaction(transactionId);
165
+ }
166
+
167
+ return tx;
168
+ }
169
+
170
+ getTransaction(transactionId: string): Transaction | null {
171
+ return this.transactions.get(transactionId) || null;
172
+ }
173
+
174
+ getTransactions(
175
+ filters?: {
176
+ status?: TransactionStatus;
177
+ provider?: string;
178
+ merchant?: string;
179
+ from?: Date;
180
+ to?: Date;
181
+ }
182
+ ): Transaction[] {
183
+ let txs = Array.from(this.transactions.values());
184
+
185
+ if (filters?.status) {
186
+ txs = txs.filter(tx => tx.status === filters.status);
187
+ }
188
+ if (filters?.provider) {
189
+ txs = txs.filter(tx => tx.provider === filters.provider);
190
+ }
191
+ if (filters?.merchant) {
192
+ txs = txs.filter(tx => tx.merchant === filters.merchant);
193
+ }
194
+ if (filters?.from) {
195
+ txs = txs.filter(tx => tx.createdAt >= filters.from!);
196
+ }
197
+ if (filters?.to) {
198
+ txs = txs.filter(tx => tx.createdAt <= filters.to!);
199
+ }
200
+
201
+ return txs.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
202
+ }
203
+
204
+ getPendingTransactions(): Transaction[] {
205
+ return this.getTransactions({ status: 'pending' });
206
+ }
207
+
208
+ cancelAllPending(): number {
209
+ let count = 0;
210
+ this.transactions.forEach((tx, id) => {
211
+ if (tx.status === 'pending' || tx.status === 'processing') {
212
+ this.updateTransactionStatus(id, 'cancelled', 'Cancelled by emergency stop');
213
+ count++;
214
+ }
215
+ });
216
+ return count;
217
+ }
218
+
219
+ deleteTransaction(transactionId: string): boolean {
220
+ const deleted = this.transactions.delete(transactionId);
221
+ if (deleted) {
222
+ this.saveTransactions();
223
+ }
224
+ return deleted;
225
+ }
226
+ }
227
+
228
+ export const transactionManager = new TransactionManager();
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Payment Skill - Main Entry Point
3
+ *
4
+ * Exports all modules for programmatic use
5
+ */
6
+
7
+ export { WiseClient } from './api/wise';
8
+ export { BunqClient } from './api/bunq';
9
+ export { ConfigManager, configManager } from './core/config';
10
+ export { TransactionManager, transactionManager } from './core/transaction';
11
+ export * from './types';
12
+
13
+ // Version
14
+ export const VERSION = '1.0.0';
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Payment Skill - Express Server
3
+ *
4
+ * Serves the web dashboard and handles webhooks
5
+ */
6
+
7
+ import express from 'express';
8
+ import cors from 'cors';
9
+ import helmet from 'helmet';
10
+ import path from 'path';
11
+ import { configManager } from '../core/config';
12
+ import { transactionManager } from '../core/transaction';
13
+
14
+ export class PaymentSkillServer {
15
+ private app: express.Application;
16
+ private port: number;
17
+
18
+ constructor(port: number = 8080) {
19
+ this.app = express();
20
+ this.port = port;
21
+ this.setupMiddleware();
22
+ this.setupRoutes();
23
+ }
24
+
25
+ private setupMiddleware(): void {
26
+ this.app.use(helmet({
27
+ contentSecurityPolicy: false // Allow inline scripts for dashboard
28
+ }));
29
+ this.app.use(cors());
30
+ this.app.use(express.json());
31
+ this.app.use(express.static(path.join(__dirname, '../../')));
32
+ }
33
+
34
+ private setupRoutes(): void {
35
+ // Health check
36
+ this.app.get('/api/health', (req, res) => {
37
+ res.json({
38
+ status: 'ok',
39
+ version: '1.0.0',
40
+ emergencyStop: configManager.isEmergencyStopActive()
41
+ });
42
+ });
43
+
44
+ // Get configuration
45
+ this.app.get('/api/config', (req, res) => {
46
+ const config = configManager.getConfig();
47
+ // Remove sensitive data
48
+ const safeConfig = {
49
+ ...config,
50
+ providers: Object.entries(config.providers).reduce((acc, [key, val]: [string, any]) => {
51
+ acc[key] = {
52
+ name: val.name,
53
+ environment: val.environment,
54
+ // Don't expose API keys
55
+ apiKey: val.apiKey ? '***' : undefined
56
+ };
57
+ return acc;
58
+ }, {} as any)
59
+ };
60
+ res.json(safeConfig);
61
+ });
62
+
63
+ // Get transactions
64
+ this.app.get('/api/transactions', (req, res) => {
65
+ const transactions = transactionManager.getTransactions();
66
+ res.json(transactions);
67
+ });
68
+
69
+ // Get emergency stop status
70
+ this.app.get('/api/emergency', (req, res) => {
71
+ res.json(configManager.getEmergencyStopState());
72
+ });
73
+
74
+ // Activate emergency stop
75
+ this.app.post('/api/emergency/stop', (req, res) => {
76
+ configManager.activateEmergencyStop(req.body.reason);
77
+ transactionManager.cancelAllPending();
78
+ res.json({ success: true, message: 'Emergency stop activated' });
79
+ });
80
+
81
+ // Deactivate emergency stop
82
+ this.app.post('/api/emergency/resume', (req, res) => {
83
+ configManager.deactivateEmergencyStop();
84
+ res.json({ success: true, message: 'Emergency stop deactivated' });
85
+ });
86
+
87
+ // Get limits
88
+ this.app.get('/api/limits', (req, res) => {
89
+ res.json({
90
+ limits: configManager.getLimits(),
91
+ timeWindow: configManager.getTimeWindow()
92
+ });
93
+ });
94
+
95
+ // Webhook endpoints
96
+ this.app.post('/webhooks/wise', (req, res) => {
97
+ console.log('Wise webhook received:', req.body);
98
+ // Process webhook
99
+ res.status(200).send('OK');
100
+ });
101
+
102
+ this.app.post('/webhooks/bunq', (req, res) => {
103
+ console.log('Bunq webhook received:', req.body);
104
+ // Process webhook
105
+ res.status(200).send('OK');
106
+ });
107
+
108
+ // Dashboard route - serve dashboard.html
109
+ this.app.get('/', (req, res) => {
110
+ res.sendFile(path.join(__dirname, '../../dashboard.html'));
111
+ });
112
+
113
+ this.app.get('/dashboard', (req, res) => {
114
+ res.sendFile(path.join(__dirname, '../../dashboard.html'));
115
+ });
116
+ }
117
+
118
+ start(): void {
119
+ this.app.listen(this.port, () => {
120
+ console.log(`Payment Skill server running on http://localhost:${this.port}`);
121
+ console.log(`Dashboard: http://localhost:${this.port}/dashboard`);
122
+ });
123
+ }
124
+ }
125
+
126
+ // Start server if run directly
127
+ if (require.main === module) {
128
+ const port = parseInt(process.env.PORT || '8080');
129
+ const server = new PaymentSkillServer(port);
130
+ server.start();
131
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Payment Skill - Type Definitions
3
+ *
4
+ * Core types for the payment-skill application
5
+ */
6
+
7
+ // Merchant Types
8
+ export interface Merchant {
9
+ id: string;
10
+ name: string;
11
+ domains: string[];
12
+ categories: string[];
13
+ apiType: string;
14
+ verified: boolean;
15
+ riskLevel: 'low' | 'medium' | 'high';
16
+ canReceivePayments: boolean;
17
+ apiCapabilities: string[];
18
+ }
19
+
20
+ export interface MerchantDetectionResult {
21
+ merchant: string;
22
+ detected: boolean;
23
+ apiType?: string;
24
+ capabilities?: string[];
25
+ authType?: string;
26
+ webhookSupport?: boolean;
27
+ asyncConfirmation?: boolean;
28
+ confidence: number;
29
+ }
30
+
31
+ // Provider Types
32
+ export interface ProviderConfig {
33
+ name: string;
34
+ apiKey: string;
35
+ environment: 'sandbox' | 'production';
36
+ webhookSecret?: string;
37
+ profileId?: string;
38
+ additionalConfig?: Record<string, any>;
39
+ }
40
+
41
+ export interface WiseConfig extends ProviderConfig {
42
+ profileId?: string;
43
+ }
44
+
45
+ export interface BunqConfig extends ProviderConfig {
46
+ installationToken?: string;
47
+ deviceId?: string;
48
+ }
49
+
50
+ // Transaction Types
51
+ export interface Transaction {
52
+ id: string;
53
+ provider: string;
54
+ merchant: string;
55
+ amount: number;
56
+ currency: string;
57
+ status: TransactionStatus;
58
+ createdAt: Date;
59
+ updatedAt: Date;
60
+ metadata?: Record<string, any>;
61
+ error?: string;
62
+ }
63
+
64
+ export type TransactionStatus =
65
+ | 'pending'
66
+ | 'initiated'
67
+ | 'requires_action'
68
+ | 'processing'
69
+ | 'completed'
70
+ | 'failed'
71
+ | 'cancelled'
72
+ | 'on_hold';
73
+
74
+ // Template Types
75
+ export interface CommandTemplate {
76
+ templateId: string;
77
+ merchant: string;
78
+ version: string;
79
+ description: string;
80
+ prerequisites: TemplatePrerequisites;
81
+ steps: TemplateStep[];
82
+ errorHandling: ErrorHandling;
83
+ }
84
+
85
+ export interface TemplatePrerequisites {
86
+ apiKey: 'required' | 'optional' | 'none';
87
+ webhookEndpoint?: 'required' | 'recommended' | 'optional';
88
+ }
89
+
90
+ export interface TemplateStep {
91
+ order: number;
92
+ name: string;
93
+ command: string;
94
+ params: Record<string, any>;
95
+ output?: Record<string, string>;
96
+ async?: boolean;
97
+ confirmation?: ConfirmationConfig;
98
+ nextStep?: NextStepCondition;
99
+ condition?: string;
100
+ }
101
+
102
+ export interface ConfirmationConfig {
103
+ type: 'webhook' | 'poll' | 'manual';
104
+ events?: string[];
105
+ timeout?: number;
106
+ pollInterval?: number;
107
+ }
108
+
109
+ export interface NextStepCondition {
110
+ ifStatus: string;
111
+ then: number | 'complete';
112
+ else?: number | 'complete';
113
+ }
114
+
115
+ export interface ErrorHandling {
116
+ retryOn: string[];
117
+ maxRetries: number;
118
+ fallback?: string;
119
+ }
120
+
121
+ // Limit Types
122
+ export interface LimitConfig {
123
+ perTransaction: number;
124
+ daily: number;
125
+ weekly: number;
126
+ monthly: number;
127
+ maxTransactionsPerHour: number;
128
+ }
129
+
130
+ export interface TimeWindowConfig {
131
+ enabled: boolean;
132
+ start: string;
133
+ end: string;
134
+ timezone: string;
135
+ blockedDays?: string[];
136
+ }
137
+
138
+ // Emergency Stop Types
139
+ export interface EmergencyStopState {
140
+ active: boolean;
141
+ activatedAt?: Date;
142
+ reason?: string;
143
+ pendingTransactions: string[];
144
+ }
145
+
146
+ // API Response Types
147
+ export interface ApiResponse<T> {
148
+ success: boolean;
149
+ data?: T;
150
+ error?: string;
151
+ message?: string;
152
+ }
153
+
154
+ // Webhook Types
155
+ export interface WebhookEvent {
156
+ id: string;
157
+ merchant: string;
158
+ event: string;
159
+ data: any;
160
+ timestamp: Date;
161
+ signature?: string;
162
+ }
163
+
164
+ // CLI Types
165
+ export interface CliOptions {
166
+ verbose?: boolean;
167
+ json?: boolean;
168
+ config?: string;
169
+ dryRun?: boolean;
170
+ }
171
+
172
+ // Server Types
173
+ export interface ServerConfig {
174
+ port: number;
175
+ host: string;
176
+ webhookPath: string;
177
+ dashboardPath: string;
178
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true,
16
+ "moduleResolution": "node",
17
+ "allowSyntheticDefaultImports": true,
18
+ "experimentalDecorators": true,
19
+ "emitDecoratorMetadata": true
20
+ },
21
+ "include": ["src/**/*"],
22
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
23
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "lastUpdated": "2026-03-10",
4
+ "description": "Verified merchants list for PaymentSkill - only these merchants are allowed for transactions",
5
+ "merchants": [
6
+ {
7
+ "id": "stripe-connect",
8
+ "name": "Stripe Connect",
9
+ "domains": ["stripe.com", "connect.stripe.com"],
10
+ "categories": ["payments", "finance"],
11
+ "apiType": "Platform API",
12
+ "verified": true,
13
+ "riskLevel": "low",
14
+ "canReceivePayments": true,
15
+ "apiCapabilities": ["create_charges", "create_transfers", "create_payouts", "create_connected_accounts"]
16
+ },
17
+ {
18
+ "id": "airwallex",
19
+ "name": "Airwallex",
20
+ "domains": ["airwallex.com", "api.airwallex.com"],
21
+ "categories": ["payments", "finance"],
22
+ "apiType": "Connected accounts API",
23
+ "verified": true,
24
+ "riskLevel": "low",
25
+ "canReceivePayments": true,
26
+ "apiCapabilities": ["create_payments", "create_payouts", "create_connected_accounts"]
27
+ },
28
+ {
29
+ "id": "digitalocean",
30
+ "name": "DigitalOcean",
31
+ "domains": ["digitalocean.com", "api.digitalocean.com"],
32
+ "categories": ["cloud", "infrastructure", "hosting"],
33
+ "apiType": "Team API",
34
+ "verified": true,
35
+ "riskLevel": "low",
36
+ "canReceivePayments": false,
37
+ "apiCapabilities": ["create_teams", "manage_droplets", "manage_databases"]
38
+ },
39
+ {
40
+ "id": "clickclack-market",
41
+ "name": "ClickClack Market",
42
+ "domains": ["clickclack.market"],
43
+ "categories": ["marketplace", "shopping"],
44
+ "verified": true,
45
+ "riskLevel": "low",
46
+ "canReceivePayments": true,
47
+ "apiCapabilities": ["custom_api"]
48
+ }
49
+ ],
50
+ "blockedCategories": [
51
+ "gambling",
52
+ "adult",
53
+ "drugs",
54
+ "weapons",
55
+ "tobacco"
56
+ ],
57
+ "verificationRules": {
58
+ "requireDomainMatch": true,
59
+ "allowSubdomains": true,
60
+ "caseSensitive": false,
61
+ "strictMode": true
62
+ }
63
+ }