n8n-nodes-agnicwallet 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/README.md ADDED
@@ -0,0 +1,305 @@
1
+ # n8n-nodes-agnicwallet
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/n8n-nodes-agnicwallet)](https://www.npmjs.com/package/n8n-nodes-agnicwallet)
4
+ [![License](https://img.shields.io/npm/l/n8n-nodes-agnicwallet)](https://github.com/agnicpay/agnicwallet-project/blob/main/LICENSE)
5
+
6
+ N8N community node for AgnicWallet - automated Web3 payments for X402-enabled APIs.
7
+
8
+ Make HTTP requests to X402-enabled APIs with automatic blockchain payment handling via AgnicWallet. No manual wallet management, no complex crypto operations - just authenticate and automate.
9
+
10
+ ## What is X402?
11
+
12
+ [X402](https://www.x402.org/) is an open standard for HTTP-based payments. APIs return a `402 Payment Required` status with payment details, and your wallet automatically handles the payment to unlock the resource.
13
+
14
+ ## What is AgnicWallet?
15
+
16
+ AgnicWallet is a non-custodial Web3 wallet service built on [Privy](https://privy.io) that handles blockchain payments automatically. Connect once, then all X402 payments happen seamlessly in the background.
17
+
18
+ ## Features
19
+
20
+ - ✅ **Automatic X402 payment handling** - No manual wallet interactions
21
+ - ✅ **OAuth2 authentication** - Secure connection to your AgnicWallet
22
+ - ✅ **API Key support** - For programmatic access and CI/CD
23
+ - ✅ **Multiple HTTP methods** - GET, POST, PUT, DELETE
24
+ - ✅ **Custom headers** - Add any headers your API needs
25
+ - ✅ **JSON body support** - For POST/PUT requests
26
+ - ✅ **Payment metadata** - See exactly what you paid and when
27
+ - ✅ **Monthly spending limits** - Built-in safety controls
28
+ - ✅ **Base Sepolia support** - Currently supports USDC on Base Sepolia testnet
29
+
30
+ ## Installation
31
+
32
+ ### For self-hosted N8N:
33
+
34
+ ```bash
35
+ npm install -g n8n-nodes-agnicwallet
36
+ ```
37
+
38
+ Then restart N8N:
39
+
40
+ ```bash
41
+ n8n start
42
+ ```
43
+
44
+ ### For Docker:
45
+
46
+ Add to your Dockerfile:
47
+
48
+ ```dockerfile
49
+ FROM n8nio/n8n:latest
50
+
51
+ USER root
52
+ RUN npm install -g n8n-nodes-agnicwallet
53
+ USER node
54
+ ```
55
+
56
+ ### For n8n.cloud:
57
+
58
+ Not yet available. This node must first be approved as a community node by the N8N team.
59
+
60
+ ## Setup
61
+
62
+ ### 1. Create AgnicWallet Account
63
+
64
+ 1. Go to [AgnicWallet](https://agnicwallet-project.vercel.app)
65
+ 2. Sign up with email/social login (powered by Privy)
66
+ 3. Your embedded wallet is created automatically
67
+
68
+ ### 2. Connect to N8N
69
+
70
+ #### Option A: OAuth2 (Recommended)
71
+
72
+ 1. In N8N, add the **AgnicWallet X402 Request** node
73
+ 2. Select **OAuth2** authentication
74
+ 3. Click **Connect my account**
75
+ 4. Authorize AgnicWallet in the popup
76
+ 5. Done! Your wallet is connected
77
+
78
+ #### Option B: API Key
79
+
80
+ 1. Log in to [AgnicWallet](https://agnicwallet-project.vercel.app)
81
+ 2. Go to **Settings** → **API Tokens**
82
+ 3. Generate a new token
83
+ 4. In N8N, select **API Key** authentication
84
+ 5. Paste your token
85
+ 6. Done!
86
+
87
+ ## Usage
88
+
89
+ ### Basic Example: ChatGPT via X402
90
+
91
+ Configure the node:
92
+
93
+ - **Method:** `POST`
94
+ - **URL:** `https://agnicbillo-proxy.asad-safari.workers.dev/v1/custom/chatgpt/v1/chat/completions`
95
+ - **Headers:**
96
+ - Name: `X-AgnicBillo-Key`
97
+ - Value: `agb_qroy8w9rb5lnpcla8ydl`
98
+ - **Body:**
99
+ ```json
100
+ {
101
+ "model": "gpt-3.5-turbo",
102
+ "messages": [
103
+ {"role": "user", "content": "Hello!"}
104
+ ]
105
+ }
106
+ ```
107
+
108
+ **What happens:**
109
+ 1. Node makes POST request
110
+ 2. Receives `402 Payment Required`
111
+ 3. Automatically signs payment with your wallet
112
+ 4. Retries with payment proof
113
+ 5. Returns ChatGPT response with payment metadata
114
+
115
+ **Response:**
116
+ ```json
117
+ {
118
+ "id": "chatcmpl-...",
119
+ "choices": [
120
+ {
121
+ "message": {
122
+ "role": "assistant",
123
+ "content": "Hello! How can I help you?"
124
+ }
125
+ }
126
+ ],
127
+ "_agnicWallet": {
128
+ "paymentMade": true,
129
+ "amountPaid": 0.01,
130
+ "timestamp": "2025-10-28T13:46:44.079Z"
131
+ }
132
+ }
133
+ ```
134
+
135
+ ### Example: Protected Content
136
+
137
+ Simple GET request with payment:
138
+
139
+ - **Method:** `GET`
140
+ - **URL:** `https://www.x402.org/protected`
141
+
142
+ Node automatically handles the $0.01 payment and returns the protected content.
143
+
144
+ ### Example: Dynamic Content
145
+
146
+ Use N8N expressions for dynamic requests:
147
+
148
+ - **Body:**
149
+ ```json
150
+ {
151
+ "model": "gpt-3.5-turbo",
152
+ "messages": [
153
+ {"role": "user", "content": "{{ $json.userMessage }}"}
154
+ ]
155
+ }
156
+ ```
157
+
158
+ This pulls the message from previous nodes in your workflow.
159
+
160
+ ## Configuration Options
161
+
162
+ ### Authentication
163
+ - **OAuth2** (recommended) - Secure account connection
164
+ - **API Key** - For automation and CI/CD
165
+
166
+ ### HTTP Methods
167
+ - GET
168
+ - POST
169
+ - PUT
170
+ - DELETE
171
+
172
+ ### Headers
173
+ Add multiple custom headers as key-value pairs
174
+
175
+ ### Body (POST/PUT only)
176
+ JSON body for sending data to the API
177
+
178
+ ## How It Works
179
+
180
+ 1. **Make request** - Node sends HTTP request to X402 API
181
+ 2. **Check for 402** - If API returns `402 Payment Required`, node extracts payment details
182
+ 3. **Sign payment** - Node calls AgnicWallet backend to sign payment with your wallet
183
+ 4. **Retry request** - Node retries with `X-PAYMENT` header containing payment proof
184
+ 5. **Return response** - API validates payment and returns protected resource
185
+
186
+ ## Payment Details
187
+
188
+ - **Network:** Base Sepolia (testnet)
189
+ - **Token:** USDC
190
+ - **Typical cost:** $0.01 per request
191
+ - **Monthly limit:** $100 (configurable)
192
+ - **Payment method:** EIP-3009 TransferWithAuthorization (gasless)
193
+
194
+ ## Security
195
+
196
+ - **Non-custodial** - Your keys, your crypto (via Privy)
197
+ - **OAuth2** - Industry-standard authentication
198
+ - **Spending limits** - Monthly caps prevent overspending
199
+ - **Payment review** - See all payments in AgnicWallet dashboard
200
+ - **Revocable access** - Disconnect N8N anytime
201
+
202
+ ## Troubleshooting
203
+
204
+ ### "Payment signing failed"
205
+
206
+ **Causes:**
207
+ - AgnicWallet credentials not connected
208
+ - Insufficient USDC balance
209
+ - Backend server down
210
+
211
+ **Solutions:**
212
+ 1. Reconnect credentials in N8N
213
+ 2. Check balance at [AgnicWallet](https://agnicwallet-project.vercel.app)
214
+ 3. Check backend status
215
+
216
+ ### "Request failed after payment"
217
+
218
+ **Causes:**
219
+ - Invalid URL
220
+ - Wrong headers
221
+ - Malformed JSON body
222
+
223
+ **Solutions:**
224
+ 1. Verify URL is correct
225
+ 2. Check required headers for the API
226
+ 3. Validate JSON syntax
227
+
228
+ ### "Body field not visible"
229
+
230
+ The body field only appears when Method is **POST** or **PUT**. For GET requests, no body is shown (HTTP standard).
231
+
232
+ ## Examples & Workflows
233
+
234
+ See [example workflows](https://github.com/agnicpay/agnicwallet-project/tree/main/examples) in the GitHub repository.
235
+
236
+ ## API Reference
237
+
238
+ ### Node Properties
239
+
240
+ | Property | Type | Required | Description |
241
+ |----------|------|----------|-------------|
242
+ | authentication | options | Yes | OAuth2 or API Key |
243
+ | method | options | Yes | HTTP method |
244
+ | url | string | Yes | X402 API endpoint |
245
+ | headers | collection | No | Custom headers |
246
+ | body | json | No* | JSON body (*POST/PUT only) |
247
+
248
+ ## Limitations
249
+
250
+ - **Networks:** Currently Base Sepolia only (mainnet coming soon)
251
+ - **Body types:** JSON only (form-encoded coming soon)
252
+ - **Query params:** Use in URL for now (dedicated field coming soon)
253
+
254
+ See [ENHANCEMENT_PLAN.md](https://github.com/agnicpay/agnicwallet-project/blob/main/n8n-nodes-agnicwallet/nodes/X402HttpRequest/ENHANCEMENT_PLAN.md) for upcoming features.
255
+
256
+ ## Contributing
257
+
258
+ Contributions welcome! Please open issues or PRs at [GitHub](https://github.com/agnicpay/agnicwallet-project).
259
+
260
+ ## Support
261
+
262
+ - **Issues:** [GitHub Issues](https://github.com/agnicpay/agnicwallet-project/issues)
263
+ - **Docs:** [Full Documentation](https://github.com/agnicpay/agnicwallet-project)
264
+ - **X402 Standard:** [x402.org](https://www.x402.org/)
265
+
266
+ ## License
267
+
268
+ MIT - See [LICENSE](https://github.com/agnicpay/agnicwallet-project/blob/main/LICENSE)
269
+
270
+ ## Links
271
+
272
+ - [NPM Package](https://www.npmjs.com/package/n8n-nodes-agnicwallet)
273
+ - [GitHub Repository](https://github.com/agnicpay/agnicwallet-project)
274
+ - [AgnicWallet Dashboard](https://agnicwallet-project.vercel.app)
275
+ - [X402 Protocol](https://www.x402.org/)
276
+ - [N8N Documentation](https://docs.n8n.io)
277
+
278
+ ## Roadmap
279
+
280
+ ### v1.1.0
281
+ - Query parameters support
282
+ - Form-encoded body
283
+ - Timeout configuration
284
+
285
+ ### v1.2.0
286
+ - Multiple networks (Base mainnet, Polygon, etc.)
287
+ - Retry logic
288
+ - Rate limiting
289
+
290
+ ### v2.0.0
291
+ - File upload support
292
+ - Streaming responses
293
+ - Webhook triggers
294
+
295
+ ## Acknowledgments
296
+
297
+ Built with:
298
+ - [N8N](https://n8n.io) - Workflow automation
299
+ - [Privy](https://privy.io) - Embedded wallets
300
+ - [X402 Protocol](https://www.x402.org/) - HTTP payment standard
301
+ - [Base](https://base.org) - L2 blockchain
302
+
303
+ ---
304
+
305
+ Made with ❤️ by the AgnicWallet team
@@ -0,0 +1,8 @@
1
+ import { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class AgnicWalletApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgnicWalletApi = void 0;
4
+ class AgnicWalletApi {
5
+ constructor() {
6
+ this.name = 'agnicWalletApi';
7
+ this.displayName = 'AgnicWallet API';
8
+ this.documentationUrl = 'https://docs.agnicwallet.com/n8n';
9
+ this.properties = [
10
+ {
11
+ displayName: 'User ID',
12
+ name: 'userId',
13
+ type: 'string',
14
+ default: '',
15
+ required: true,
16
+ description: 'Your AgnicWallet user ID (from dashboard)',
17
+ placeholder: 'user_2kX9mNz8pQw7VbC',
18
+ },
19
+ {
20
+ displayName: 'API Token',
21
+ name: 'apiToken',
22
+ type: 'string',
23
+ typeOptions: {
24
+ password: true,
25
+ },
26
+ default: '',
27
+ required: true,
28
+ description: 'Your AgnicWallet API token (starts with agnic_tok_)',
29
+ placeholder: 'agnic_tok_sk_live_...',
30
+ },
31
+ ];
32
+ this.authenticate = {
33
+ type: 'generic',
34
+ properties: {
35
+ headers: {
36
+ 'X-Agnic-Token': '={{$credentials.apiToken}}',
37
+ },
38
+ },
39
+ };
40
+ }
41
+ }
42
+ exports.AgnicWalletApi = AgnicWalletApi;
@@ -0,0 +1,8 @@
1
+ import { ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class AgnicWalletOAuth2Api implements ICredentialType {
3
+ name: string;
4
+ extends: string[];
5
+ displayName: string;
6
+ documentationUrl: string;
7
+ properties: INodeProperties[];
8
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgnicWalletOAuth2Api = void 0;
4
+ class AgnicWalletOAuth2Api {
5
+ constructor() {
6
+ this.name = 'agnicWalletOAuth2Api';
7
+ this.extends = ['oAuth2Api'];
8
+ this.displayName = 'AgnicWallet OAuth2 API';
9
+ this.documentationUrl = 'https://docs.agnicwallet.com/oauth';
10
+ this.properties = [
11
+ {
12
+ displayName: 'Grant Type',
13
+ name: 'grantType',
14
+ type: 'hidden',
15
+ default: 'authorizationCode',
16
+ },
17
+ {
18
+ displayName: 'Authorization URL',
19
+ name: 'authUrl',
20
+ type: 'string',
21
+ default: 'https://agnicwallet-project.onrender.com/oauth/authorize',
22
+ required: true,
23
+ description: 'The OAuth2 authorization endpoint',
24
+ },
25
+ {
26
+ displayName: 'Access Token URL',
27
+ name: 'accessTokenUrl',
28
+ type: 'string',
29
+ default: 'https://agnicwallet-project.onrender.com/oauth/token',
30
+ required: true,
31
+ description: 'The OAuth2 token endpoint',
32
+ },
33
+ {
34
+ displayName: 'Client ID',
35
+ name: 'clientId',
36
+ type: 'string',
37
+ default: 'n8n_default',
38
+ required: true,
39
+ description: 'OAuth2 Client ID (default: n8n_default)',
40
+ },
41
+ {
42
+ displayName: 'Client Secret',
43
+ name: 'clientSecret',
44
+ type: 'string',
45
+ typeOptions: {
46
+ password: true,
47
+ },
48
+ default: '',
49
+ description: 'OAuth2 Client Secret (optional for PKCE)',
50
+ },
51
+ {
52
+ displayName: 'Scope',
53
+ name: 'scope',
54
+ type: 'string',
55
+ default: 'payments:sign balance:read',
56
+ description: 'OAuth2 scopes',
57
+ },
58
+ {
59
+ displayName: 'Auth URI Query Parameters',
60
+ name: 'authQueryParameters',
61
+ type: 'string',
62
+ default: '',
63
+ description: 'Additional query parameters for authorization URL',
64
+ },
65
+ {
66
+ displayName: 'Authentication',
67
+ name: 'authentication',
68
+ type: 'options',
69
+ options: [
70
+ {
71
+ name: 'Body',
72
+ value: 'body',
73
+ },
74
+ {
75
+ name: 'Header',
76
+ value: 'header',
77
+ },
78
+ ],
79
+ default: 'body',
80
+ description: 'How to send credentials',
81
+ },
82
+ {
83
+ displayName: 'Use PKCE',
84
+ name: 'usePKCE',
85
+ type: 'boolean',
86
+ default: true,
87
+ description: 'Whether to use PKCE (Proof Key for Code Exchange)',
88
+ },
89
+ ];
90
+ }
91
+ }
92
+ exports.AgnicWalletOAuth2Api = AgnicWalletOAuth2Api;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class X402HttpRequest implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.X402HttpRequest = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ class X402HttpRequest {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: 'AgnicWallet X402 Request',
9
+ name: 'agnicWalletX402Request',
10
+ group: ['transform'],
11
+ version: 1,
12
+ description: 'Make HTTP requests to X402-enabled APIs with automatic payment via AgnicWallet',
13
+ defaults: {
14
+ name: 'AgnicWallet X402',
15
+ },
16
+ usableAsTool: true,
17
+ inputs: ['main'],
18
+ outputs: ['main'],
19
+ credentials: [
20
+ {
21
+ name: 'agnicWalletOAuth2Api',
22
+ required: false,
23
+ displayOptions: {
24
+ show: {
25
+ authentication: ['oAuth2'],
26
+ },
27
+ },
28
+ },
29
+ {
30
+ name: 'agnicWalletApi',
31
+ required: false,
32
+ displayOptions: {
33
+ show: {
34
+ authentication: ['apiKey'],
35
+ },
36
+ },
37
+ },
38
+ ],
39
+ properties: [
40
+ {
41
+ displayName: 'Authentication',
42
+ name: 'authentication',
43
+ type: 'options',
44
+ options: [
45
+ {
46
+ name: 'OAuth2',
47
+ value: 'oAuth2',
48
+ description: 'Recommended: Connect your account',
49
+ },
50
+ {
51
+ name: 'API Key',
52
+ value: 'apiKey',
53
+ description: 'For CI/CD or programmatic access',
54
+ },
55
+ ],
56
+ default: 'oAuth2',
57
+ description: 'How to authenticate with AgnicWallet',
58
+ },
59
+ {
60
+ displayName: 'Method',
61
+ name: 'method',
62
+ type: 'options',
63
+ options: [
64
+ {
65
+ name: 'GET',
66
+ value: 'GET',
67
+ },
68
+ {
69
+ name: 'POST',
70
+ value: 'POST',
71
+ },
72
+ {
73
+ name: 'PUT',
74
+ value: 'PUT',
75
+ },
76
+ {
77
+ name: 'DELETE',
78
+ value: 'DELETE',
79
+ },
80
+ ],
81
+ default: 'GET',
82
+ description: 'The HTTP method to use',
83
+ },
84
+ {
85
+ displayName: 'URL',
86
+ name: 'url',
87
+ type: 'string',
88
+ default: '',
89
+ required: true,
90
+ placeholder: 'https://api.example.com/endpoint',
91
+ description: 'The URL of the X402-enabled API',
92
+ },
93
+ {
94
+ displayName: 'Headers',
95
+ name: 'headers',
96
+ type: 'fixedCollection',
97
+ typeOptions: {
98
+ multipleValues: true,
99
+ },
100
+ default: {},
101
+ options: [
102
+ {
103
+ name: 'header',
104
+ displayName: 'Header',
105
+ values: [
106
+ {
107
+ displayName: 'Name',
108
+ name: 'name',
109
+ type: 'string',
110
+ default: '',
111
+ description: 'Name of the header',
112
+ },
113
+ {
114
+ displayName: 'Value',
115
+ name: 'value',
116
+ type: 'string',
117
+ default: '',
118
+ description: 'Value of the header',
119
+ },
120
+ ],
121
+ },
122
+ ],
123
+ description: 'Additional headers to send with the request',
124
+ },
125
+ {
126
+ displayName: 'Body',
127
+ name: 'body',
128
+ type: 'json',
129
+ default: '{}',
130
+ displayOptions: {
131
+ show: {
132
+ method: ['POST', 'PUT'],
133
+ },
134
+ },
135
+ description: 'JSON body to send with the request',
136
+ },
137
+ ],
138
+ };
139
+ }
140
+ async execute() {
141
+ const items = this.getInputData();
142
+ const returnData = [];
143
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
144
+ try {
145
+ // Get authentication type
146
+ const authentication = this.getNodeParameter('authentication', itemIndex);
147
+ let apiBaseUrl;
148
+ let authHeader;
149
+ // Use AgnicWallet backend API endpoint (production cloud by default)
150
+ // Can override with AGNICWALLET_API_URL environment variable for local development
151
+ apiBaseUrl = process.env.AGNICWALLET_API_URL || 'https://agnicwallet-project.onrender.com';
152
+ if (authentication === 'oAuth2') {
153
+ // OAuth2 authentication
154
+ const credentials = await this.getCredentials('agnicWalletOAuth2Api', itemIndex);
155
+ authHeader = `Bearer ${credentials.oauthTokenData.access_token}`;
156
+ }
157
+ else {
158
+ // API Key authentication
159
+ const credentials = await this.getCredentials('agnicWalletApi', itemIndex);
160
+ const { apiToken } = credentials;
161
+ authHeader = apiToken;
162
+ }
163
+ // Get parameters
164
+ const method = this.getNodeParameter('method', itemIndex);
165
+ const url = this.getNodeParameter('url', itemIndex);
166
+ const headersConfig = this.getNodeParameter('headers', itemIndex, {});
167
+ const body = this.getNodeParameter('body', itemIndex, '{}');
168
+ // Build headers
169
+ const headers = {
170
+ 'Content-Type': 'application/json',
171
+ };
172
+ if (headersConfig.header) {
173
+ headersConfig.header.forEach((h) => {
174
+ headers[h.name] = h.value;
175
+ });
176
+ }
177
+ // Make request with X402 payment handling
178
+ const response = await makeX402Request(this, {
179
+ url,
180
+ method,
181
+ headers,
182
+ body: method === 'POST' || method === 'PUT' ? JSON.parse(body) : undefined,
183
+ agnicWalletApi: apiBaseUrl,
184
+ authHeader,
185
+ isOAuth: authentication === 'oAuth2',
186
+ });
187
+ returnData.push({
188
+ json: response,
189
+ pairedItem: {
190
+ item: itemIndex,
191
+ },
192
+ });
193
+ }
194
+ catch (error) {
195
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
196
+ if (this.continueOnFail()) {
197
+ returnData.push({
198
+ json: {
199
+ error: errorMessage,
200
+ },
201
+ pairedItem: {
202
+ item: itemIndex,
203
+ },
204
+ });
205
+ continue;
206
+ }
207
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), errorMessage, {
208
+ itemIndex,
209
+ });
210
+ }
211
+ }
212
+ return [returnData];
213
+ }
214
+ }
215
+ exports.X402HttpRequest = X402HttpRequest;
216
+ // Helper function: Make X402 request with automatic payment
217
+ async function makeX402Request(context, config) {
218
+ const { url, method, headers, body, agnicWalletApi, authHeader, isOAuth } = config;
219
+ try {
220
+ // 1. Try the request first (may return 402)
221
+ context.logger.info(`Making initial request to: ${url}`);
222
+ let response = await fetch(url, {
223
+ method,
224
+ headers,
225
+ body: body ? JSON.stringify(body) : undefined,
226
+ });
227
+ context.logger.info(`Response status: ${response.status}`);
228
+ // 2. If 402 Payment Required, use AgnicWallet to sign
229
+ if (response.status === 402) {
230
+ context.logger.info('402 Payment Required detected, parsing payment requirements...');
231
+ // Get response text first for debugging
232
+ const responseText = await response.text();
233
+ context.logger.info(`Payment requirements response: ${responseText}`);
234
+ let paymentRequirements;
235
+ try {
236
+ paymentRequirements = JSON.parse(responseText);
237
+ }
238
+ catch (parseError) {
239
+ throw new Error(`Failed to parse payment requirements: ${parseError instanceof Error ? parseError.message : 'Unknown error'}. Response: ${responseText}`);
240
+ }
241
+ context.logger.info(`Payment required: ${JSON.stringify(paymentRequirements)}`);
242
+ // 3. Call AgnicWallet signing API
243
+ context.logger.info(`Calling AgnicWallet API at: ${agnicWalletApi}/api/sign-payment`);
244
+ // Build auth headers based on auth type
245
+ const authHeaders = {
246
+ 'Content-Type': 'application/json',
247
+ };
248
+ if (isOAuth) {
249
+ // OAuth: Use Authorization header with Bearer token
250
+ authHeaders['Authorization'] = authHeader;
251
+ }
252
+ else {
253
+ // API Key: Use X-Agnic-Token header
254
+ authHeaders['X-Agnic-Token'] = authHeader;
255
+ }
256
+ const signingResponse = await fetch(`${agnicWalletApi}/api/sign-payment`, {
257
+ method: 'POST',
258
+ headers: authHeaders,
259
+ body: JSON.stringify({
260
+ paymentRequirements,
261
+ requestData: { url, method, body },
262
+ }),
263
+ });
264
+ if (!signingResponse.ok) {
265
+ const errorText = await signingResponse.text();
266
+ context.logger.error(`AgnicWallet signing failed: ${errorText}`);
267
+ throw new Error(`Payment signing failed (${signingResponse.status}): ${errorText}`);
268
+ }
269
+ const signingResult = await signingResponse.json();
270
+ const { paymentHeader, amountPaid } = signingResult;
271
+ context.logger.info(`Payment signed successfully: $${amountPaid}`);
272
+ context.logger.info(`Payment header (Base64): ${paymentHeader}`);
273
+ // 4. Retry original request with payment header
274
+ // The paymentHeader is already Base64-encoded and X402-compliant
275
+ context.logger.info('Retrying request with X402 payment header...');
276
+ response = await fetch(url, {
277
+ method,
278
+ headers: {
279
+ ...headers,
280
+ 'X-PAYMENT': paymentHeader,
281
+ },
282
+ body: body ? JSON.stringify(body) : undefined,
283
+ });
284
+ context.logger.info(`Retry response status: ${response.status}`);
285
+ if (!response.ok) {
286
+ const errorText = await response.text();
287
+ throw new Error(`Request failed after payment (${response.status}): ${errorText}`);
288
+ }
289
+ const resultText = await response.text();
290
+ let result;
291
+ try {
292
+ result = JSON.parse(resultText);
293
+ }
294
+ catch (parseError) {
295
+ context.logger.warn(`Response is not JSON: ${resultText}`);
296
+ result = { data: resultText };
297
+ }
298
+ return {
299
+ ...(typeof result === 'object' && result !== null ? result : {}),
300
+ _agnicWallet: {
301
+ paymentMade: true,
302
+ amountPaid,
303
+ timestamp: new Date().toISOString(),
304
+ },
305
+ };
306
+ }
307
+ // 5. If no payment required, just return the result
308
+ if (!response.ok) {
309
+ const errorText = await response.text();
310
+ throw new Error(`Request failed (${response.status} ${response.statusText}): ${errorText}`);
311
+ }
312
+ const resultText = await response.text();
313
+ try {
314
+ return JSON.parse(resultText);
315
+ }
316
+ catch (parseError) {
317
+ context.logger.warn(`Response is not JSON: ${resultText}`);
318
+ return { data: resultText };
319
+ }
320
+ }
321
+ catch (error) {
322
+ context.logger.error(`Error in makeX402Request: ${error instanceof Error ? error.message : 'Unknown error'}`);
323
+ throw error;
324
+ }
325
+ }
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "n8n-nodes-agnicwallet",
3
+ "version": "1.0.0",
4
+ "description": "n8n community node for AgnicWallet - automated Web3 payments for X402 APIs",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "agnicwallet",
9
+ "x402",
10
+ "web3",
11
+ "crypto",
12
+ "payments"
13
+ ],
14
+ "license": "MIT",
15
+ "homepage": "https://agnicwallet.com",
16
+ "author": {
17
+ "name": "AgnicWallet",
18
+ "email": "support@agnicwallet.com"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/agnicpay/agnicwallet-project.git"
23
+ },
24
+ "main": "index.js",
25
+ "scripts": {
26
+ "build": "tsc && gulp build:icons",
27
+ "dev": "tsc --watch",
28
+ "format": "prettier nodes credentials --write",
29
+ "lint": "tslint -p tsconfig.json -c tslint.json",
30
+ "lintfix": "tslint --fix -p tsconfig.json -c tslint.json",
31
+ "prepublishOnly": "npm run build && npm run lint -c .eslintrc.prepublish.js nodes credentials package.json",
32
+ "test": "jest"
33
+ },
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "n8n": {
38
+ "n8nNodesApiVersion": 1,
39
+ "credentials": [
40
+ "dist/credentials/AgnicWalletApi.credentials.js",
41
+ "dist/credentials/AgnicWalletOAuth2Api.credentials.js"
42
+ ],
43
+ "nodes": [
44
+ "dist/nodes/X402HttpRequest/X402HttpRequest.node.js"
45
+ ]
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^20.10.0",
49
+ "@typescript-eslint/parser": "^6.13.0",
50
+ "eslint": "^8.54.0",
51
+ "eslint-plugin-n8n-nodes-base": "^1.16.1",
52
+ "gulp": "^4.0.2",
53
+ "n8n-workflow": "^1.40.0",
54
+ "prettier": "^3.1.0",
55
+ "tslint": "^5.20.1",
56
+ "typescript": "^5.3.0"
57
+ },
58
+ "peerDependencies": {
59
+ "n8n-workflow": "*"
60
+ }
61
+ }