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,257 @@
1
+ /**
2
+ * Payment Skill - Bunq API Client
3
+ *
4
+ * Handles all Bunq API interactions
5
+ */
6
+
7
+ import axios, { AxiosInstance } from 'axios';
8
+ import { BunqConfig } from '../types';
9
+
10
+ export class BunqClient {
11
+ private client: AxiosInstance;
12
+ private config: BunqConfig;
13
+ private baseURL: string;
14
+
15
+ constructor(config: BunqConfig) {
16
+ this.config = config;
17
+ this.baseURL = 'https://api.bunq.com/v1';
18
+
19
+ this.client = axios.create({
20
+ baseURL: this.baseURL,
21
+ headers: {
22
+ 'X-Bunq-Client-Request-Id': this.generateRequestId(),
23
+ 'X-Bunq-Geolocation': '0 0 0 0 NL',
24
+ 'X-Bunq-Language': 'en_US',
25
+ 'X-Bunq-Region': 'en_US',
26
+ 'Content-Type': 'application/json'
27
+ }
28
+ });
29
+
30
+ // Add API key to requests
31
+ this.client.interceptors.request.use((config) => {
32
+ config.headers['X-Bunq-Client-Authentication'] = this.config.apiKey;
33
+ return config;
34
+ });
35
+ }
36
+
37
+ private generateRequestId(): string {
38
+ return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
39
+ }
40
+
41
+ // User Management
42
+ async getUser(userId: string) {
43
+ const response = await this.client.get(`/user/${userId}`);
44
+ return response.data;
45
+ }
46
+
47
+ // Monetary Accounts
48
+ async getMonetaryAccounts(userId: string) {
49
+ const response = await this.client.get(`/user/${userId}/monetary-account`);
50
+ return response.data;
51
+ }
52
+
53
+ async getMonetaryAccount(userId: string, accountId: string) {
54
+ const response = await this.client.get(`/user/${userId}/monetary-account/${accountId}`);
55
+ return response.data;
56
+ }
57
+
58
+ async getAccountBalance(userId: string, accountId: string) {
59
+ const response = await this.client.get(`/user/${userId}/monetary-account/${accountId}`);
60
+ return response.data;
61
+ }
62
+
63
+ // Payments
64
+ async createPayment(
65
+ userId: string,
66
+ accountId: string,
67
+ amount: string,
68
+ currency: string,
69
+ counterpartyIban: string,
70
+ counterpartyName: string,
71
+ description: string
72
+ ) {
73
+ const response = await this.client.post(
74
+ `/user/${userId}/monetary-account/${accountId}/payment`,
75
+ {
76
+ amount: {
77
+ value: amount,
78
+ currency: currency
79
+ },
80
+ counterparty_alias: {
81
+ type: 'IBAN',
82
+ value: counterpartyIban,
83
+ name: counterpartyName
84
+ },
85
+ description: description
86
+ }
87
+ );
88
+ return response.data;
89
+ }
90
+
91
+ async getPayments(userId: string, accountId: string, limit: number = 100) {
92
+ const response = await this.client.get(
93
+ `/user/${userId}/monetary-account/${accountId}/payment?count=${limit}`
94
+ );
95
+ return response.data;
96
+ }
97
+
98
+ async getPayment(userId: string, accountId: string, paymentId: string) {
99
+ const response = await this.client.get(
100
+ `/user/${userId}/monetary-account/${accountId}/payment/${paymentId}`
101
+ );
102
+ return response.data;
103
+ }
104
+
105
+ // Request Inquiries (Payment Requests)
106
+ async createRequestInquiry(
107
+ userId: string,
108
+ accountId: string,
109
+ amount: string,
110
+ currency: string,
111
+ counterpartyAlias: any,
112
+ description: string,
113
+ allowBunqme: boolean = false
114
+ ) {
115
+ const response = await this.client.post(
116
+ `/user/${userId}/monetary-account/${accountId}/request-inquiry`,
117
+ {
118
+ amount_inquired: {
119
+ value: amount,
120
+ currency: currency
121
+ },
122
+ counterparty_alias: counterpartyAlias,
123
+ description: description,
124
+ allow_bunqme: allowBunqme
125
+ }
126
+ );
127
+ return response.data;
128
+ }
129
+
130
+ async getRequestInquiries(userId: string, accountId: string) {
131
+ const response = await this.client.get(
132
+ `/user/${userId}/monetary-account/${accountId}/request-inquiry`
133
+ );
134
+ return response.data;
135
+ }
136
+
137
+ async getRequestInquiry(userId: string, accountId: string, inquiryId: string) {
138
+ const response = await this.client.get(
139
+ `/user/${userId}/monetary-account/${accountId}/request-inquiry/${inquiryId}`
140
+ );
141
+ return response.data;
142
+ }
143
+
144
+ async cancelRequestInquiry(userId: string, accountId: string, inquiryId: string) {
145
+ const response = await this.client.put(
146
+ `/user/${userId}/monetary-account/${accountId}/request-inquiry/${inquiryId}`,
147
+ { status: 'CANCELLED' }
148
+ );
149
+ return response.data;
150
+ }
151
+
152
+ // Draft Payments
153
+ async createDraftPayment(
154
+ userId: string,
155
+ accountId: string,
156
+ payments: any[]
157
+ ) {
158
+ const response = await this.client.post(
159
+ `/user/${userId}/monetary-account/${accountId}/draft-payment`,
160
+ { payments }
161
+ );
162
+ return response.data;
163
+ }
164
+
165
+ async getDraftPayments(userId: string, accountId: string) {
166
+ const response = await this.client.get(
167
+ `/user/${userId}/monetary-account/${accountId}/draft-payment`
168
+ );
169
+ return response.data;
170
+ }
171
+
172
+ async deleteDraftPayment(userId: string, accountId: string, draftId: string) {
173
+ const response = await this.client.delete(
174
+ `/user/${userId}/monetary-account/${accountId}/draft-payment/${draftId}`
175
+ );
176
+ return response.data;
177
+ }
178
+
179
+ // Counterparties
180
+ async createCounterparty(
181
+ userId: string,
182
+ name: string,
183
+ type: string,
184
+ value: string
185
+ ) {
186
+ const response = await this.client.post(`/user/${userId}/counterparty`, {
187
+ name,
188
+ alias: {
189
+ type,
190
+ value,
191
+ name
192
+ }
193
+ });
194
+ return response.data;
195
+ }
196
+
197
+ async getCounterparties(userId: string) {
198
+ const response = await this.client.get(`/user/${userId}/counterparty`);
199
+ return response.data;
200
+ }
201
+
202
+ // Schedules (Recurring Payments)
203
+ async createSchedule(
204
+ userId: string,
205
+ accountId: string,
206
+ payment: any,
207
+ schedule: any
208
+ ) {
209
+ const response = await this.client.post(
210
+ `/user/${userId}/monetary-account/${accountId}/schedule`,
211
+ {
212
+ payment,
213
+ schedule
214
+ }
215
+ );
216
+ return response.data;
217
+ }
218
+
219
+ async getSchedules(userId: string, accountId: string) {
220
+ const response = await this.client.get(
221
+ `/user/${userId}/monetary-account/${accountId}/schedule`
222
+ );
223
+ return response.data;
224
+ }
225
+
226
+ async deleteSchedule(userId: string, accountId: string, scheduleId: string) {
227
+ const response = await this.client.delete(
228
+ `/user/${userId}/monetary-account/${accountId}/schedule/${scheduleId}`
229
+ );
230
+ return response.data;
231
+ }
232
+
233
+ // Cards
234
+ async getCards(userId: string) {
235
+ const response = await this.client.get(`/user/${userId}/card`);
236
+ return response.data;
237
+ }
238
+
239
+ // Export
240
+ async exportStatement(
241
+ userId: string,
242
+ accountId: string,
243
+ dateStart: string,
244
+ dateEnd: string,
245
+ format: 'CSV' | 'PDF' | 'MT940' = 'CSV'
246
+ ) {
247
+ const response = await this.client.post(
248
+ `/user/${userId}/monetary-account/${accountId}/export-statement`,
249
+ {
250
+ date_start: dateStart,
251
+ date_end: dateEnd,
252
+ regional_format: format
253
+ }
254
+ );
255
+ return response.data;
256
+ }
257
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Payment Skill - Wise API Client
3
+ *
4
+ * Handles all Wise API interactions
5
+ */
6
+
7
+ import axios, { AxiosInstance } from 'axios';
8
+ import { WiseConfig } from '../types';
9
+
10
+ export class WiseClient {
11
+ private client: AxiosInstance;
12
+ private config: WiseConfig;
13
+
14
+ constructor(config: WiseConfig) {
15
+ this.config = config;
16
+ const baseURL = config.environment === 'production'
17
+ ? 'https://api.wise.com'
18
+ : 'https://api.sandbox.transferwise.tech';
19
+
20
+ this.client = axios.create({
21
+ baseURL,
22
+ headers: {
23
+ 'Authorization': `Bearer ${config.apiKey}`,
24
+ 'Content-Type': 'application/json'
25
+ }
26
+ });
27
+ }
28
+
29
+ // Profile Management
30
+ async getProfiles() {
31
+ const response = await this.client.get('/v2/profiles');
32
+ return response.data;
33
+ }
34
+
35
+ async getProfile(profileId: string) {
36
+ const response = await this.client.get(`/v2/profiles/${profileId}`);
37
+ return response.data;
38
+ }
39
+
40
+ // Balance Management
41
+ async getBalances(profileId: string) {
42
+ const response = await this.client.get(`/v4/profiles/${profileId}/balances`);
43
+ return response.data;
44
+ }
45
+
46
+ async getBalance(profileId: string, balanceId: string) {
47
+ const response = await this.client.get(`/v4/profiles/${profileId}/balances/${balanceId}`);
48
+ return response.data;
49
+ }
50
+
51
+ // Quote Management
52
+ async createQuote(
53
+ profileId: string,
54
+ sourceCurrency: string,
55
+ targetCurrency: string,
56
+ sourceAmount?: number,
57
+ targetAmount?: number
58
+ ) {
59
+ const body: any = {
60
+ sourceCurrency,
61
+ targetCurrency
62
+ };
63
+
64
+ if (sourceAmount) {
65
+ body.sourceAmount = sourceAmount;
66
+ } else if (targetAmount) {
67
+ body.targetAmount = targetAmount;
68
+ }
69
+
70
+ const response = await this.client.post(`/v3/profiles/${profileId}/quotes`, body);
71
+ return response.data;
72
+ }
73
+
74
+ async getQuote(profileId: string, quoteId: string) {
75
+ const response = await this.client.get(`/v3/profiles/${profileId}/quotes/${quoteId}`);
76
+ return response.data;
77
+ }
78
+
79
+ // Recipient Management
80
+ async createRecipient(
81
+ profileId: string,
82
+ currency: string,
83
+ accountHolderName: string,
84
+ details: any
85
+ ) {
86
+ const response = await this.client.post(`/v1/accounts`, {
87
+ profile: profileId,
88
+ currency,
89
+ type: 'iban',
90
+ accountHolderName,
91
+ details
92
+ });
93
+ return response.data;
94
+ }
95
+
96
+ async getRecipients(profileId: string) {
97
+ const response = await this.client.get(`/v1/accounts?profile=${profileId}`);
98
+ return response.data;
99
+ }
100
+
101
+ async getRecipient(accountId: string) {
102
+ const response = await this.client.get(`/v1/accounts/${accountId}`);
103
+ return response.data;
104
+ }
105
+
106
+ async deleteRecipient(accountId: string) {
107
+ const response = await this.client.delete(`/v1/accounts/${accountId}`);
108
+ return response.data;
109
+ }
110
+
111
+ // Transfer Management
112
+ async createTransfer(
113
+ profileId: string,
114
+ quoteId: string,
115
+ targetAccountId: string,
116
+ reference?: string
117
+ ) {
118
+ const body: any = {
119
+ targetAccount: targetAccountId,
120
+ quoteUuid: quoteId
121
+ };
122
+
123
+ if (reference) {
124
+ body.reference = reference;
125
+ }
126
+
127
+ const response = await this.client.post(`/v1/transfers`, body);
128
+ return response.data;
129
+ }
130
+
131
+ async getTransfer(transferId: string) {
132
+ const response = await this.client.get(`/v1/transfers/${transferId}`);
133
+ return response.data;
134
+ }
135
+
136
+ async cancelTransfer(transferId: string) {
137
+ const response = await this.client.put(`/v1/transfers/${transferId}/cancel`);
138
+ return response.data;
139
+ }
140
+
141
+ async getTransfers(profileId: string, status?: string, limit: number = 100) {
142
+ const params: any = { profile: profileId, limit };
143
+ if (status) {
144
+ params.status = status;
145
+ }
146
+ const response = await this.client.get(`/v1/transfers`, { params });
147
+ return response.data;
148
+ }
149
+
150
+ // Transfer Requirements
151
+ async getTransferRequirements(
152
+ profileId: string,
153
+ quoteId: string,
154
+ targetAccountId: string
155
+ ) {
156
+ const response = await this.client.post(`/v1/transfer-requirements`, {
157
+ targetAccount: targetAccountId,
158
+ quoteUuid: quoteId
159
+ });
160
+ return response.data;
161
+ }
162
+
163
+ // Fund Transfer
164
+ async fundTransfer(profileId: string, transferId: string) {
165
+ const response = await this.client.post(
166
+ `/v3/profiles/${profileId}/transfers/${transferId}/payments`,
167
+ { type: 'BALANCE' }
168
+ );
169
+ return response.data;
170
+ }
171
+
172
+ // Bank Account Details
173
+ async getBankAccountDetails(profileId: string, balanceId: string) {
174
+ const response = await this.client.get(
175
+ `/v4/profiles/${profileId}/balances/${balanceId}/bank-details`
176
+ );
177
+ return response.data;
178
+ }
179
+
180
+ // Webhook Management
181
+ async createWebhook(profileId: string, name: string, triggerOn: string[], url: string) {
182
+ const response = await this.client.post(`/v3/profiles/${profileId}/subscriptions`, {
183
+ name,
184
+ triggerOn,
185
+ delivery: {
186
+ version: '2.0.0',
187
+ url
188
+ }
189
+ });
190
+ return response.data;
191
+ }
192
+
193
+ async getWebhooks(profileId: string) {
194
+ const response = await this.client.get(`/v3/profiles/${profileId}/subscriptions`);
195
+ return response.data;
196
+ }
197
+
198
+ async deleteWebhook(profileId: string, subscriptionId: string) {
199
+ const response = await this.client.delete(
200
+ `/v3/profiles/${profileId}/subscriptions/${subscriptionId}`
201
+ );
202
+ return response.data;
203
+ }
204
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Payment Skill CLI
5
+ *
6
+ * Main entry point for the payment-skill command line interface
7
+ */
8
+
9
+ import { Command } from 'commander';
10
+ import chalk from 'chalk';
11
+ import { configCommands } from './commands/config';
12
+ import { providerCommands } from './commands/provider';
13
+ import { wiseCommands } from './commands/wise';
14
+ import { bunqCommands } from './commands/bunq';
15
+ import { transactionCommands } from './commands/transaction';
16
+ import { merchantCommands } from './commands/merchant';
17
+ import { limitCommands } from './commands/limits';
18
+ import { emergencyCommands } from './commands/emergency';
19
+ import { serverCommands } from './commands/server';
20
+ import { templateCommands } from './commands/template';
21
+ import { payCommand } from './commands/pay';
22
+
23
+ const program = new Command();
24
+
25
+ program
26
+ .name('payment-skill')
27
+ .description('Self-hosted payment orchestration for OpenClaw')
28
+ .version('1.0.0')
29
+ .option('-v, --verbose', 'Enable verbose output')
30
+ .option('-j, --json', 'Output in JSON format')
31
+ .option('-c, --config <path>', 'Path to config file')
32
+ .option('--dry-run', 'Simulate without executing')
33
+ .hook('preAction', (thisCommand) => {
34
+ const options = thisCommand.opts();
35
+ if (options.verbose) {
36
+ console.log(chalk.gray('Verbose mode enabled'));
37
+ }
38
+ });
39
+
40
+ // Add command groups
41
+ program.addCommand(configCommands);
42
+ program.addCommand(providerCommands);
43
+ program.addCommand(wiseCommands);
44
+ program.addCommand(bunqCommands);
45
+ program.addCommand(transactionCommands);
46
+ program.addCommand(merchantCommands);
47
+ program.addCommand(limitCommands);
48
+ program.addCommand(emergencyCommands);
49
+ program.addCommand(serverCommands);
50
+ program.addCommand(templateCommands);
51
+ program.addCommand(payCommand);
52
+
53
+ // Global error handler
54
+ program.exitOverride();
55
+
56
+ try {
57
+ program.parse();
58
+ } catch (error: any) {
59
+ if (error.code === 'commander.help') {
60
+ process.exit(0);
61
+ } else if (error.code === 'commander.version') {
62
+ process.exit(0);
63
+ } else {
64
+ console.error(chalk.red('Error:'), error.message);
65
+ process.exit(1);
66
+ }
67
+ }