@ktmcp-cli/nowpayments 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.
- package/.env.example +17 -0
- package/AGENT.md +513 -0
- package/INSTALL.md +392 -0
- package/LICENSE +21 -0
- package/OPENCLAW.md +628 -0
- package/PROJECT_SUMMARY.md +305 -0
- package/README.md +375 -0
- package/banner.png +0 -0
- package/bin/nowpayments.js +89 -0
- package/examples/basic-payment.js +66 -0
- package/examples/invoice-flow.js +78 -0
- package/examples/monitor-payment.js +94 -0
- package/logo.png +0 -0
- package/openapi.json +2791 -0
- package/package.json +40 -0
- package/src/commands/auth.js +65 -0
- package/src/commands/currencies.js +95 -0
- package/src/commands/estimate.js +85 -0
- package/src/commands/invoice.js +188 -0
- package/src/commands/payment.js +241 -0
- package/src/commands/payout.js +184 -0
- package/src/commands/status.js +28 -0
- package/src/lib/api.js +133 -0
- package/src/lib/auth.js +70 -0
- package/src/lib/config.js +110 -0
- package/test.sh +250 -0
package/OPENCLAW.md
ADDED
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
# NOWPayments CLI - OpenClaw Integration Guide
|
|
2
|
+
|
|
3
|
+
This guide covers integration of the NOWPayments CLI with the OpenClaw agent framework, enabling cryptocurrency payment processing in OpenClaw-based applications.
|
|
4
|
+
|
|
5
|
+
## What is OpenClaw?
|
|
6
|
+
|
|
7
|
+
OpenClaw is an open-source agent framework for building autonomous AI applications. It provides:
|
|
8
|
+
- Multi-agent coordination
|
|
9
|
+
- Tool/skill registration
|
|
10
|
+
- Context management
|
|
11
|
+
- Session persistence
|
|
12
|
+
- Event-driven architecture
|
|
13
|
+
|
|
14
|
+
## Integration Overview
|
|
15
|
+
|
|
16
|
+
The NOWPayments CLI integrates with OpenClaw as a **tool/skill**, allowing OpenClaw agents to:
|
|
17
|
+
- Accept cryptocurrency payments
|
|
18
|
+
- Process invoices
|
|
19
|
+
- Manage payouts
|
|
20
|
+
- Monitor transaction status
|
|
21
|
+
- Handle payment webhooks
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
### 1. Install NOWPayments CLI
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g @ktmcp-cli/nowpayments
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. Configure API Key
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Set API key globally
|
|
35
|
+
nowpayments auth set YOUR_API_KEY
|
|
36
|
+
|
|
37
|
+
# Or use environment variable in OpenClaw config
|
|
38
|
+
export NOWPAYMENTS_API_KEY=your_api_key
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. Verify Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
nowpayments status
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## OpenClaw Skill Definition
|
|
48
|
+
|
|
49
|
+
Create a skill definition file for OpenClaw:
|
|
50
|
+
|
|
51
|
+
### `skills/nowpayments.json`
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"name": "nowpayments",
|
|
56
|
+
"version": "1.0.0",
|
|
57
|
+
"description": "Cryptocurrency payment processing via NOWPayments",
|
|
58
|
+
"category": "payment",
|
|
59
|
+
"commands": {
|
|
60
|
+
"status": {
|
|
61
|
+
"description": "Check NOWPayments API status",
|
|
62
|
+
"execute": "nowpayments status"
|
|
63
|
+
},
|
|
64
|
+
"list_currencies": {
|
|
65
|
+
"description": "List available cryptocurrencies",
|
|
66
|
+
"execute": "nowpayments --json currencies list --available",
|
|
67
|
+
"output": "json"
|
|
68
|
+
},
|
|
69
|
+
"estimate": {
|
|
70
|
+
"description": "Estimate cryptocurrency amount",
|
|
71
|
+
"parameters": {
|
|
72
|
+
"from": { "type": "string", "required": true },
|
|
73
|
+
"to": { "type": "string", "required": true },
|
|
74
|
+
"amount": { "type": "number", "required": true }
|
|
75
|
+
},
|
|
76
|
+
"execute": "nowpayments --json estimate convert --from {from} --to {to} --amount {amount}",
|
|
77
|
+
"output": "json"
|
|
78
|
+
},
|
|
79
|
+
"create_payment": {
|
|
80
|
+
"description": "Create a new payment",
|
|
81
|
+
"parameters": {
|
|
82
|
+
"price": { "type": "number", "required": true },
|
|
83
|
+
"currency": { "type": "string", "required": true },
|
|
84
|
+
"pay_currency": { "type": "string", "required": true },
|
|
85
|
+
"order_id": { "type": "string", "required": false },
|
|
86
|
+
"order_description": { "type": "string", "required": false }
|
|
87
|
+
},
|
|
88
|
+
"execute": "nowpayments --json payment create --price {price} --currency {currency} --pay-currency {pay_currency} {order_id:--order-id} {order_description:--order-description}",
|
|
89
|
+
"output": "json"
|
|
90
|
+
},
|
|
91
|
+
"get_payment": {
|
|
92
|
+
"description": "Get payment status and details",
|
|
93
|
+
"parameters": {
|
|
94
|
+
"payment_id": { "type": "string", "required": true }
|
|
95
|
+
},
|
|
96
|
+
"execute": "nowpayments --json payment get {payment_id}",
|
|
97
|
+
"output": "json"
|
|
98
|
+
},
|
|
99
|
+
"list_payments": {
|
|
100
|
+
"description": "List all payments",
|
|
101
|
+
"parameters": {
|
|
102
|
+
"limit": { "type": "number", "default": 10 },
|
|
103
|
+
"page": { "type": "number", "default": 0 }
|
|
104
|
+
},
|
|
105
|
+
"execute": "nowpayments --json payment list --limit {limit} --page {page}",
|
|
106
|
+
"output": "json"
|
|
107
|
+
},
|
|
108
|
+
"create_invoice": {
|
|
109
|
+
"description": "Create a payment invoice",
|
|
110
|
+
"parameters": {
|
|
111
|
+
"price": { "type": "number", "required": true },
|
|
112
|
+
"currency": { "type": "string", "required": true },
|
|
113
|
+
"order_id": { "type": "string", "required": false },
|
|
114
|
+
"success_url": { "type": "string", "required": false }
|
|
115
|
+
},
|
|
116
|
+
"execute": "nowpayments --json invoice create --price {price} --currency {currency} {order_id:--order-id} {success_url:--success-url}",
|
|
117
|
+
"output": "json"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"events": {
|
|
121
|
+
"payment_created": {
|
|
122
|
+
"description": "Emitted when a payment is created",
|
|
123
|
+
"data": {
|
|
124
|
+
"payment_id": "string",
|
|
125
|
+
"pay_address": "string",
|
|
126
|
+
"pay_amount": "number",
|
|
127
|
+
"pay_currency": "string"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"payment_completed": {
|
|
131
|
+
"description": "Emitted when a payment is confirmed",
|
|
132
|
+
"data": {
|
|
133
|
+
"payment_id": "string",
|
|
134
|
+
"status": "string"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Usage Examples
|
|
142
|
+
|
|
143
|
+
### Example 1: Simple Payment Flow
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
// OpenClaw agent code
|
|
147
|
+
async function processPayment(agent, amount, currency) {
|
|
148
|
+
// 1. Check API status
|
|
149
|
+
const status = await agent.execute('nowpayments', 'status');
|
|
150
|
+
if (!status.success) {
|
|
151
|
+
throw new Error('NOWPayments API unavailable');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 2. Get estimate
|
|
155
|
+
const estimate = await agent.execute('nowpayments', 'estimate', {
|
|
156
|
+
from: currency,
|
|
157
|
+
to: 'BTC',
|
|
158
|
+
amount: amount
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// 3. Create payment
|
|
162
|
+
const payment = await agent.execute('nowpayments', 'create_payment', {
|
|
163
|
+
price: amount,
|
|
164
|
+
currency: currency,
|
|
165
|
+
pay_currency: 'BTC',
|
|
166
|
+
order_id: `ORDER-${Date.now()}`,
|
|
167
|
+
order_description: 'Product purchase'
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// 4. Emit event
|
|
171
|
+
agent.emit('payment_created', payment);
|
|
172
|
+
|
|
173
|
+
// 5. Return payment details
|
|
174
|
+
return {
|
|
175
|
+
paymentId: payment.payment_id,
|
|
176
|
+
address: payment.pay_address,
|
|
177
|
+
amount: payment.pay_amount,
|
|
178
|
+
currency: payment.pay_currency
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Example 2: Payment Monitoring
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
// Monitor payment status
|
|
187
|
+
async function monitorPayment(agent, paymentId) {
|
|
188
|
+
const maxAttempts = 60; // 30 minutes (30s intervals)
|
|
189
|
+
let attempts = 0;
|
|
190
|
+
|
|
191
|
+
while (attempts < maxAttempts) {
|
|
192
|
+
const payment = await agent.execute('nowpayments', 'get_payment', {
|
|
193
|
+
payment_id: paymentId
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
switch (payment.payment_status) {
|
|
197
|
+
case 'finished':
|
|
198
|
+
agent.emit('payment_completed', {
|
|
199
|
+
payment_id: paymentId,
|
|
200
|
+
status: 'completed'
|
|
201
|
+
});
|
|
202
|
+
return { success: true, payment };
|
|
203
|
+
|
|
204
|
+
case 'failed':
|
|
205
|
+
case 'expired':
|
|
206
|
+
agent.emit('payment_failed', {
|
|
207
|
+
payment_id: paymentId,
|
|
208
|
+
status: payment.payment_status
|
|
209
|
+
});
|
|
210
|
+
return { success: false, payment };
|
|
211
|
+
|
|
212
|
+
case 'partially_paid':
|
|
213
|
+
agent.emit('payment_underpaid', {
|
|
214
|
+
payment_id: paymentId,
|
|
215
|
+
expected: payment.pay_amount,
|
|
216
|
+
received: payment.actually_paid
|
|
217
|
+
});
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Wait 30 seconds before next check
|
|
222
|
+
await agent.sleep(30000);
|
|
223
|
+
attempts++;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return { success: false, timeout: true };
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Example 3: Invoice Generation
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
// Generate and track invoice
|
|
234
|
+
async function createInvoice(agent, productId, amount, customerEmail) {
|
|
235
|
+
// Create invoice
|
|
236
|
+
const invoice = await agent.execute('nowpayments', 'create_invoice', {
|
|
237
|
+
price: amount,
|
|
238
|
+
currency: 'USD',
|
|
239
|
+
order_id: `INV-${productId}-${Date.now()}`,
|
|
240
|
+
success_url: `https://example.com/success?product=${productId}`
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Store invoice in agent context
|
|
244
|
+
await agent.context.set(`invoice:${invoice.id}`, {
|
|
245
|
+
invoiceId: invoice.id,
|
|
246
|
+
productId: productId,
|
|
247
|
+
customerEmail: customerEmail,
|
|
248
|
+
amount: amount,
|
|
249
|
+
created: new Date(),
|
|
250
|
+
url: invoice.invoice_url
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Send invoice to customer
|
|
254
|
+
await agent.execute('email', 'send', {
|
|
255
|
+
to: customerEmail,
|
|
256
|
+
subject: 'Your Payment Invoice',
|
|
257
|
+
body: `Please complete your payment: ${invoice.invoice_url}`
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
return invoice;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Example 4: Multi-Currency Support
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
// Let customer choose payment currency
|
|
268
|
+
async function createFlexiblePayment(agent, priceUSD) {
|
|
269
|
+
// Get available currencies
|
|
270
|
+
const currencies = await agent.execute('nowpayments', 'list_currencies');
|
|
271
|
+
|
|
272
|
+
// Get estimates for popular currencies
|
|
273
|
+
const options = await Promise.all([
|
|
274
|
+
agent.execute('nowpayments', 'estimate', {
|
|
275
|
+
from: 'USD',
|
|
276
|
+
to: 'BTC',
|
|
277
|
+
amount: priceUSD
|
|
278
|
+
}),
|
|
279
|
+
agent.execute('nowpayments', 'estimate', {
|
|
280
|
+
from: 'USD',
|
|
281
|
+
to: 'ETH',
|
|
282
|
+
amount: priceUSD
|
|
283
|
+
}),
|
|
284
|
+
agent.execute('nowpayments', 'estimate', {
|
|
285
|
+
from: 'USD',
|
|
286
|
+
to: 'USDT',
|
|
287
|
+
amount: priceUSD
|
|
288
|
+
})
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
// Present options to user
|
|
292
|
+
const choice = await agent.prompt('Choose payment currency:', [
|
|
293
|
+
`Bitcoin: ${options[0].estimated_amount} BTC`,
|
|
294
|
+
`Ethereum: ${options[1].estimated_amount} ETH`,
|
|
295
|
+
`Tether: ${options[2].estimated_amount} USDT`
|
|
296
|
+
]);
|
|
297
|
+
|
|
298
|
+
const selectedCurrency = ['BTC', 'ETH', 'USDT'][choice];
|
|
299
|
+
|
|
300
|
+
// Create payment with selected currency
|
|
301
|
+
return await agent.execute('nowpayments', 'create_payment', {
|
|
302
|
+
price: priceUSD,
|
|
303
|
+
currency: 'USD',
|
|
304
|
+
pay_currency: selectedCurrency,
|
|
305
|
+
order_id: `ORDER-${Date.now()}`
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Event Handling
|
|
311
|
+
|
|
312
|
+
### Set Up Event Listeners
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
// In OpenClaw agent initialization
|
|
316
|
+
agent.on('nowpayments:payment_created', async (data) => {
|
|
317
|
+
console.log('Payment created:', data.payment_id);
|
|
318
|
+
|
|
319
|
+
// Store payment in database
|
|
320
|
+
await agent.db.payments.insert({
|
|
321
|
+
paymentId: data.payment_id,
|
|
322
|
+
address: data.pay_address,
|
|
323
|
+
amount: data.pay_amount,
|
|
324
|
+
currency: data.pay_currency,
|
|
325
|
+
status: 'waiting',
|
|
326
|
+
createdAt: new Date()
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Start monitoring
|
|
330
|
+
agent.schedule('monitor_payment', {
|
|
331
|
+
paymentId: data.payment_id
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
agent.on('nowpayments:payment_completed', async (data) => {
|
|
336
|
+
console.log('Payment completed:', data.payment_id);
|
|
337
|
+
|
|
338
|
+
// Update database
|
|
339
|
+
await agent.db.payments.update(
|
|
340
|
+
{ paymentId: data.payment_id },
|
|
341
|
+
{ status: 'completed', completedAt: new Date() }
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
// Fulfill order
|
|
345
|
+
await agent.execute('order', 'fulfill', {
|
|
346
|
+
paymentId: data.payment_id
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Send confirmation
|
|
350
|
+
await agent.execute('notification', 'send', {
|
|
351
|
+
type: 'payment_success',
|
|
352
|
+
paymentId: data.payment_id
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Webhook Integration
|
|
358
|
+
|
|
359
|
+
### Set Up IPN Handler
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
// In your OpenClaw web server
|
|
363
|
+
app.post('/webhooks/nowpayments/ipn', async (req, res) => {
|
|
364
|
+
const ipnData = req.body;
|
|
365
|
+
|
|
366
|
+
// Verify IPN signature (HMAC-SHA512)
|
|
367
|
+
const signature = req.headers['x-nowpayments-sig'];
|
|
368
|
+
const isValid = verifyIpnSignature(ipnData, signature);
|
|
369
|
+
|
|
370
|
+
if (!isValid) {
|
|
371
|
+
return res.status(401).send('Invalid signature');
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Process payment update
|
|
375
|
+
const { payment_id, payment_status } = ipnData;
|
|
376
|
+
|
|
377
|
+
// Emit event to OpenClaw agents
|
|
378
|
+
await openclaw.broadcast('nowpayments:payment_update', {
|
|
379
|
+
paymentId: payment_id,
|
|
380
|
+
status: payment_status,
|
|
381
|
+
data: ipnData
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
res.status(200).send('OK');
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// IPN signature verification
|
|
388
|
+
function verifyIpnSignature(data, signature) {
|
|
389
|
+
const crypto = require('crypto');
|
|
390
|
+
const ipnSecret = process.env.NOWPAYMENTS_IPN_SECRET;
|
|
391
|
+
|
|
392
|
+
const payload = JSON.stringify(data);
|
|
393
|
+
const expectedSignature = crypto
|
|
394
|
+
.createHmac('sha512', ipnSecret)
|
|
395
|
+
.update(payload)
|
|
396
|
+
.digest('hex');
|
|
397
|
+
|
|
398
|
+
return signature === expectedSignature;
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Advanced Patterns
|
|
403
|
+
|
|
404
|
+
### Pattern 1: Subscription Payments
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
async function createSubscription(agent, plan, customerEmail) {
|
|
408
|
+
const monthlyPrice = plan.price;
|
|
409
|
+
|
|
410
|
+
// Create first payment
|
|
411
|
+
const payment = await agent.execute('nowpayments', 'create_payment', {
|
|
412
|
+
price: monthlyPrice,
|
|
413
|
+
currency: 'USD',
|
|
414
|
+
pay_currency: 'BTC',
|
|
415
|
+
order_id: `SUB-${plan.id}-${Date.now()}`,
|
|
416
|
+
order_description: `${plan.name} - Month 1`
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Schedule monthly reminders
|
|
420
|
+
agent.schedule('subscription_renewal', {
|
|
421
|
+
planId: plan.id,
|
|
422
|
+
customerEmail: customerEmail,
|
|
423
|
+
amount: monthlyPrice
|
|
424
|
+
}, { cron: '0 0 1 * *' }); // First of every month
|
|
425
|
+
|
|
426
|
+
return payment;
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Pattern 2: Batch Processing
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
async function processMonthlyPayouts(agent) {
|
|
434
|
+
// Get all pending payouts
|
|
435
|
+
const payouts = await agent.db.payouts.find({ status: 'pending' });
|
|
436
|
+
|
|
437
|
+
// Group by currency for efficiency
|
|
438
|
+
const grouped = groupBy(payouts, 'currency');
|
|
439
|
+
|
|
440
|
+
for (const [currency, items] of Object.entries(grouped)) {
|
|
441
|
+
for (const item of items) {
|
|
442
|
+
try {
|
|
443
|
+
const payout = await agent.execute('nowpayments', 'create_payout', {
|
|
444
|
+
amount: item.amount,
|
|
445
|
+
currency: currency,
|
|
446
|
+
address: item.address
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
await agent.db.payouts.update(
|
|
450
|
+
{ id: item.id },
|
|
451
|
+
{ status: 'processing', payoutId: payout.id }
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
// Rate limiting
|
|
455
|
+
await agent.sleep(1000);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
await agent.log.error('Payout failed', {
|
|
458
|
+
payoutId: item.id,
|
|
459
|
+
error: error.message
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Pattern 3: Multi-Agent Coordination
|
|
468
|
+
|
|
469
|
+
```javascript
|
|
470
|
+
// Payment Agent
|
|
471
|
+
class PaymentAgent extends OpenClawAgent {
|
|
472
|
+
async onPaymentRequest(data) {
|
|
473
|
+
const payment = await this.execute('nowpayments', 'create_payment', data);
|
|
474
|
+
|
|
475
|
+
// Notify order agent
|
|
476
|
+
await this.send('order-agent', 'payment_created', payment);
|
|
477
|
+
|
|
478
|
+
// Start monitoring
|
|
479
|
+
this.monitorPayment(payment.payment_id);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async onPaymentCompleted(paymentId) {
|
|
483
|
+
// Notify fulfillment agent
|
|
484
|
+
await this.send('fulfillment-agent', 'process_order', { paymentId });
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Order Agent
|
|
489
|
+
class OrderAgent extends OpenClawAgent {
|
|
490
|
+
async onMessage(from, type, data) {
|
|
491
|
+
if (type === 'payment_created') {
|
|
492
|
+
await this.db.orders.update(
|
|
493
|
+
{ id: data.order_id },
|
|
494
|
+
{ paymentId: data.payment_id, status: 'awaiting_payment' }
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Fulfillment Agent
|
|
501
|
+
class FulfillmentAgent extends OpenClawAgent {
|
|
502
|
+
async onMessage(from, type, data) {
|
|
503
|
+
if (type === 'process_order') {
|
|
504
|
+
const order = await this.db.orders.findOne({ paymentId: data.paymentId });
|
|
505
|
+
await this.fulfillOrder(order);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## Testing
|
|
512
|
+
|
|
513
|
+
### Unit Tests
|
|
514
|
+
|
|
515
|
+
```javascript
|
|
516
|
+
describe('NOWPayments Integration', () => {
|
|
517
|
+
let agent;
|
|
518
|
+
|
|
519
|
+
beforeEach(() => {
|
|
520
|
+
agent = new OpenClawAgent({
|
|
521
|
+
skills: ['nowpayments']
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
it('should create payment', async () => {
|
|
526
|
+
const payment = await agent.execute('nowpayments', 'create_payment', {
|
|
527
|
+
price: 100,
|
|
528
|
+
currency: 'USD',
|
|
529
|
+
pay_currency: 'BTC'
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
expect(payment.payment_id).toBeDefined();
|
|
533
|
+
expect(payment.pay_address).toBeDefined();
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
it('should monitor payment status', async () => {
|
|
537
|
+
const paymentId = 'test-payment-123';
|
|
538
|
+
|
|
539
|
+
const result = await monitorPayment(agent, paymentId);
|
|
540
|
+
|
|
541
|
+
expect(result.success).toBeDefined();
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Integration Tests
|
|
547
|
+
|
|
548
|
+
```javascript
|
|
549
|
+
describe('Payment Flow', () => {
|
|
550
|
+
it('should complete full payment lifecycle', async () => {
|
|
551
|
+
// Create payment
|
|
552
|
+
const payment = await createPayment(agent, 100, 'USD');
|
|
553
|
+
expect(payment.paymentId).toBeDefined();
|
|
554
|
+
|
|
555
|
+
// Verify payment created event
|
|
556
|
+
const event = await agent.waitFor('payment_created');
|
|
557
|
+
expect(event.payment_id).toBe(payment.paymentId);
|
|
558
|
+
|
|
559
|
+
// Simulate payment completion (in sandbox)
|
|
560
|
+
// ... payment completion logic ...
|
|
561
|
+
|
|
562
|
+
// Verify completion event
|
|
563
|
+
const completedEvent = await agent.waitFor('payment_completed');
|
|
564
|
+
expect(completedEvent.payment_id).toBe(payment.paymentId);
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Configuration
|
|
570
|
+
|
|
571
|
+
### Environment Variables
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
# Required
|
|
575
|
+
NOWPAYMENTS_API_KEY=your_api_key
|
|
576
|
+
|
|
577
|
+
# Optional
|
|
578
|
+
NOWPAYMENTS_IPN_SECRET=your_ipn_secret
|
|
579
|
+
NOWPAYMENTS_SANDBOX=false
|
|
580
|
+
NOWPAYMENTS_DEFAULT_CURRENCY=USD
|
|
581
|
+
NOWPAYMENTS_DEFAULT_PAY_CURRENCY=BTC
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### OpenClaw Config
|
|
585
|
+
|
|
586
|
+
```yaml
|
|
587
|
+
# openclaw.config.yml
|
|
588
|
+
skills:
|
|
589
|
+
- name: nowpayments
|
|
590
|
+
enabled: true
|
|
591
|
+
config:
|
|
592
|
+
api_key: ${NOWPAYMENTS_API_KEY}
|
|
593
|
+
sandbox: false
|
|
594
|
+
webhook_url: https://your-domain.com/webhooks/nowpayments/ipn
|
|
595
|
+
default_currency: USD
|
|
596
|
+
supported_pay_currencies:
|
|
597
|
+
- BTC
|
|
598
|
+
- ETH
|
|
599
|
+
- USDT
|
|
600
|
+
- LTC
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
## Best Practices
|
|
604
|
+
|
|
605
|
+
1. **Always use JSON output mode** for programmatic access
|
|
606
|
+
2. **Implement proper error handling** for all payment operations
|
|
607
|
+
3. **Use webhooks (IPN)** instead of polling when possible
|
|
608
|
+
4. **Store payment IDs** in your database for tracking
|
|
609
|
+
5. **Validate amounts** before creating payments
|
|
610
|
+
6. **Monitor payment expiration** and notify users
|
|
611
|
+
7. **Implement retry logic** for failed API calls
|
|
612
|
+
8. **Use sandbox mode** for testing
|
|
613
|
+
9. **Secure webhook endpoints** with signature verification
|
|
614
|
+
10. **Log all payment operations** for audit trail
|
|
615
|
+
|
|
616
|
+
## Troubleshooting
|
|
617
|
+
|
|
618
|
+
### Common Issues
|
|
619
|
+
|
|
620
|
+
1. **API Key Not Found**: Ensure environment variable is set or use `nowpayments auth set`
|
|
621
|
+
2. **Rate Limiting**: Implement exponential backoff and respect rate limits
|
|
622
|
+
3. **Webhook Not Received**: Check firewall rules and verify IPN callback URL
|
|
623
|
+
4. **Payment Expired**: Monitor payments and send reminders before expiration
|
|
624
|
+
5. **Currency Not Supported**: Always validate currencies before creating payments
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
This integration guide enables seamless cryptocurrency payment processing in OpenClaw applications using the NOWPayments CLI as a foundation.
|