chub-dev 0.1.0 → 0.1.2-beta.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 +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: payments
|
|
3
|
+
description: "Razorpay Node.js SDK coding guidelines for building payment systems with orders, payments, refunds, and subscriptions"
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "2.9.6"
|
|
7
|
+
updated-on: "2026-03-02"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "razorpay,payments,india,checkout,upi"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Razorpay Node.js Coding Guidelines
|
|
13
|
+
|
|
14
|
+
You are a Razorpay payment gateway coding expert. Help me with writing code using the Razorpay Node.js SDK for building payment systems with orders, payments, refunds, subscriptions, customers, and invoices.
|
|
15
|
+
|
|
16
|
+
Please follow the following guidelines when generating code.
|
|
17
|
+
|
|
18
|
+
You can find the official SDK documentation and code samples here:
|
|
19
|
+
https://razorpay.com/docs/payments/server-integration/nodejs/
|
|
20
|
+
|
|
21
|
+
## Golden Rule: Use the Correct and Current SDK
|
|
22
|
+
|
|
23
|
+
Always use the official Razorpay Node.js SDK, which is the standard library for all Razorpay API interactions.
|
|
24
|
+
|
|
25
|
+
**Library Name:** Razorpay Node.js SDK
|
|
26
|
+
**NPM Package:** `razorpay`
|
|
27
|
+
**Current Version:** 2.9.6
|
|
28
|
+
**Supported Node.js Versions:** Node.js 10+
|
|
29
|
+
|
|
30
|
+
**Installation:**
|
|
31
|
+
- **Correct:** `npm install razorpay` or `yarn add razorpay`
|
|
32
|
+
|
|
33
|
+
**APIs and Usage:**
|
|
34
|
+
- **Correct:** `const Razorpay = require('razorpay')`
|
|
35
|
+
- **Correct:** `const instance = new Razorpay({ key_id: 'YOUR_KEY_ID', key_secret: 'YOUR_KEY_SECRET' })`
|
|
36
|
+
- **Correct:** `instance.orders.create({...})` for creating orders
|
|
37
|
+
- **Correct:** `instance.payments.fetch(paymentId)` for fetching payments
|
|
38
|
+
- **Incorrect:** Using unofficial Razorpay libraries or wrappers
|
|
39
|
+
- **Incorrect:** Exposing credentials in front-end applications
|
|
40
|
+
|
|
41
|
+
## Authentication and Initialization
|
|
42
|
+
|
|
43
|
+
The Razorpay Node.js library requires your Key ID and Key Secret for authentication. You can obtain these from the Razorpay Dashboard at Settings > API Keys.
|
|
44
|
+
|
|
45
|
+
### Environment Variables (Recommended)
|
|
46
|
+
|
|
47
|
+
Set up environment variables for secure credential management:
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
// Load environment variables
|
|
51
|
+
require('dotenv').config();
|
|
52
|
+
|
|
53
|
+
// Initialize Razorpay instance
|
|
54
|
+
const Razorpay = require('razorpay');
|
|
55
|
+
|
|
56
|
+
const instance = new Razorpay({
|
|
57
|
+
key_id: process.env.RAZORPAY_KEY_ID,
|
|
58
|
+
key_secret: process.env.RAZORPAY_KEY_SECRET
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Direct Initialization
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const Razorpay = require('razorpay');
|
|
66
|
+
|
|
67
|
+
const instance = new Razorpay({
|
|
68
|
+
key_id: 'rzp_test_xxxxxxxxxx',
|
|
69
|
+
key_secret: 'your_key_secret_here'
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Client Configuration Options
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
const instance = new Razorpay({
|
|
77
|
+
key_id: process.env.RAZORPAY_KEY_ID,
|
|
78
|
+
key_secret: process.env.RAZORPAY_KEY_SECRET,
|
|
79
|
+
headers: {
|
|
80
|
+
'X-Razorpay-Account': 'acc_xxxxxxxxxxxxx' // Optional: For partner integrations
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Orders API
|
|
86
|
+
|
|
87
|
+
### Create Order
|
|
88
|
+
|
|
89
|
+
Create an order before accepting payments from customers:
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
const Razorpay = require('razorpay');
|
|
93
|
+
const instance = new Razorpay({
|
|
94
|
+
key_id: process.env.RAZORPAY_KEY_ID,
|
|
95
|
+
key_secret: process.env.RAZORPAY_KEY_SECRET
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
async function createOrder() {
|
|
99
|
+
try {
|
|
100
|
+
const options = {
|
|
101
|
+
amount: 50000, // Amount in paise (50000 paise = ₹500)
|
|
102
|
+
currency: "INR",
|
|
103
|
+
receipt: "receipt_order_12345",
|
|
104
|
+
notes: {
|
|
105
|
+
key1: "value1",
|
|
106
|
+
key2: "value2"
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const order = await instance.orders.create(options);
|
|
111
|
+
console.log('Order ID:', order.id);
|
|
112
|
+
console.log('Order:', order);
|
|
113
|
+
return order;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('Error creating order:', error);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Fetch Order Details
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
async function fetchOrder(orderId) {
|
|
125
|
+
try {
|
|
126
|
+
const order = await instance.orders.fetch(orderId);
|
|
127
|
+
console.log('Order details:', order);
|
|
128
|
+
return order;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('Error fetching order:', error);
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Fetch All Orders
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
async function fetchAllOrders() {
|
|
140
|
+
try {
|
|
141
|
+
const options = {
|
|
142
|
+
count: 10, // Number of orders to fetch (default: 10, max: 100)
|
|
143
|
+
skip: 0, // Number of orders to skip (for pagination)
|
|
144
|
+
from: 1640995200, // Unix timestamp (fetch orders from this time)
|
|
145
|
+
to: 1672531199 // Unix timestamp (fetch orders till this time)
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const orders = await instance.orders.all(options);
|
|
149
|
+
console.log('Orders:', orders);
|
|
150
|
+
return orders;
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error('Error fetching orders:', error);
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Fetch Payments for an Order
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
async function fetchOrderPayments(orderId) {
|
|
162
|
+
try {
|
|
163
|
+
const payments = await instance.orders.fetchPayments(orderId);
|
|
164
|
+
console.log('Payments for order:', payments);
|
|
165
|
+
return payments;
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error('Error fetching order payments:', error);
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Payments API
|
|
174
|
+
|
|
175
|
+
### Fetch Payment Details
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
async function fetchPayment(paymentId) {
|
|
179
|
+
try {
|
|
180
|
+
const payment = await instance.payments.fetch(paymentId);
|
|
181
|
+
console.log('Payment details:', payment);
|
|
182
|
+
return payment;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error('Error fetching payment:', error);
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Fetch All Payments
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
async function fetchAllPayments() {
|
|
194
|
+
try {
|
|
195
|
+
const options = {
|
|
196
|
+
count: 10,
|
|
197
|
+
skip: 0,
|
|
198
|
+
from: 1640995200,
|
|
199
|
+
to: 1672531199
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const payments = await instance.payments.all(options);
|
|
203
|
+
console.log('Payments:', payments);
|
|
204
|
+
return payments;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error('Error fetching payments:', error);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Capture Payment
|
|
213
|
+
|
|
214
|
+
Capture an authorized payment:
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
async function capturePayment(paymentId, amount) {
|
|
218
|
+
try {
|
|
219
|
+
const payment = await instance.payments.capture(paymentId, amount, "INR");
|
|
220
|
+
console.log('Payment captured:', payment);
|
|
221
|
+
return payment;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error('Error capturing payment:', error);
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Update Payment
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
async function updatePayment(paymentId) {
|
|
233
|
+
try {
|
|
234
|
+
const notes = {
|
|
235
|
+
notes: {
|
|
236
|
+
note_key_1: "updated value 1",
|
|
237
|
+
note_key_2: "updated value 2"
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const payment = await instance.payments.edit(paymentId, notes);
|
|
242
|
+
console.log('Payment updated:', payment);
|
|
243
|
+
return payment;
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error('Error updating payment:', error);
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Refunds API
|
|
252
|
+
|
|
253
|
+
### Create Refund
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
async function createRefund(paymentId) {
|
|
257
|
+
try {
|
|
258
|
+
const options = {
|
|
259
|
+
amount: 10000, // Amount in paise to refund
|
|
260
|
+
speed: "normal", // "normal" or "optimum"
|
|
261
|
+
notes: {
|
|
262
|
+
notes_key_1: "Refund reason"
|
|
263
|
+
},
|
|
264
|
+
receipt: "Receipt No. 31"
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const refund = await instance.payments.refund(paymentId, options);
|
|
268
|
+
console.log('Refund created:', refund);
|
|
269
|
+
return refund;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.error('Error creating refund:', error);
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Fetch Refund Details
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
async function fetchRefund(paymentId, refundId) {
|
|
281
|
+
try {
|
|
282
|
+
const refund = await instance.payments.fetchRefund(paymentId, refundId);
|
|
283
|
+
console.log('Refund details:', refund);
|
|
284
|
+
return refund;
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error('Error fetching refund:', error);
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Fetch All Refunds for a Payment
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
async function fetchPaymentRefunds(paymentId) {
|
|
296
|
+
try {
|
|
297
|
+
const refunds = await instance.payments.fetchMultipleRefund(paymentId);
|
|
298
|
+
console.log('Refunds:', refunds);
|
|
299
|
+
return refunds;
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.error('Error fetching refunds:', error);
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Fetch All Refunds
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
async function fetchAllRefunds() {
|
|
311
|
+
try {
|
|
312
|
+
const options = {
|
|
313
|
+
count: 10,
|
|
314
|
+
skip: 0,
|
|
315
|
+
from: 1640995200,
|
|
316
|
+
to: 1672531199
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const refunds = await instance.refunds.all(options);
|
|
320
|
+
console.log('All refunds:', refunds);
|
|
321
|
+
return refunds;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.error('Error fetching all refunds:', error);
|
|
324
|
+
throw error;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Customers API
|
|
330
|
+
|
|
331
|
+
### Create Customer
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
async function createCustomer() {
|
|
335
|
+
try {
|
|
336
|
+
const customerData = {
|
|
337
|
+
name: "John Doe",
|
|
338
|
+
email: "john.doe@example.com",
|
|
339
|
+
contact: "+919876543210",
|
|
340
|
+
fail_existing: 0, // 0 to return existing customer if exists, 1 to fail
|
|
341
|
+
notes: {
|
|
342
|
+
customer_type: "premium"
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const customer = await instance.customers.create(customerData);
|
|
347
|
+
console.log('Customer created:', customer);
|
|
348
|
+
return customer;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
console.error('Error creating customer:', error);
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Fetch Customer Details
|
|
357
|
+
|
|
358
|
+
```javascript
|
|
359
|
+
async function fetchCustomer(customerId) {
|
|
360
|
+
try {
|
|
361
|
+
const customer = await instance.customers.fetch(customerId);
|
|
362
|
+
console.log('Customer details:', customer);
|
|
363
|
+
return customer;
|
|
364
|
+
} catch (error) {
|
|
365
|
+
console.error('Error fetching customer:', error);
|
|
366
|
+
throw error;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Update Customer
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
async function updateCustomer(customerId) {
|
|
375
|
+
try {
|
|
376
|
+
const updates = {
|
|
377
|
+
name: "Jane Doe",
|
|
378
|
+
email: "jane.doe@example.com",
|
|
379
|
+
contact: "+919876543211"
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
const customer = await instance.customers.edit(customerId, updates);
|
|
383
|
+
console.log('Customer updated:', customer);
|
|
384
|
+
return customer;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error('Error updating customer:', error);
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Fetch All Customers
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
async function fetchAllCustomers() {
|
|
396
|
+
try {
|
|
397
|
+
const options = {
|
|
398
|
+
count: 10,
|
|
399
|
+
skip: 0
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const customers = await instance.customers.all(options);
|
|
403
|
+
console.log('Customers:', customers);
|
|
404
|
+
return customers;
|
|
405
|
+
} catch (error) {
|
|
406
|
+
console.error('Error fetching customers:', error);
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Subscriptions API
|
|
413
|
+
|
|
414
|
+
### Create Subscription
|
|
415
|
+
|
|
416
|
+
```javascript
|
|
417
|
+
async function createSubscription() {
|
|
418
|
+
try {
|
|
419
|
+
const subscriptionData = {
|
|
420
|
+
plan_id: "plan_xxxxxxxxxxxxx",
|
|
421
|
+
customer_notify: 1,
|
|
422
|
+
quantity: 1,
|
|
423
|
+
total_count: 12,
|
|
424
|
+
start_at: Math.floor(Date.now() / 1000) + 86400, // Start after 1 day
|
|
425
|
+
addons: [
|
|
426
|
+
{
|
|
427
|
+
item: {
|
|
428
|
+
name: "Extra Storage",
|
|
429
|
+
amount: 5000,
|
|
430
|
+
currency: "INR"
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
],
|
|
434
|
+
notes: {
|
|
435
|
+
subscription_type: "premium"
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
const subscription = await instance.subscriptions.create(subscriptionData);
|
|
440
|
+
console.log('Subscription created:', subscription);
|
|
441
|
+
return subscription;
|
|
442
|
+
} catch (error) {
|
|
443
|
+
console.error('Error creating subscription:', error);
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Fetch Subscription Details
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
async function fetchSubscription(subscriptionId) {
|
|
453
|
+
try {
|
|
454
|
+
const subscription = await instance.subscriptions.fetch(subscriptionId);
|
|
455
|
+
console.log('Subscription details:', subscription);
|
|
456
|
+
return subscription;
|
|
457
|
+
} catch (error) {
|
|
458
|
+
console.error('Error fetching subscription:', error);
|
|
459
|
+
throw error;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Cancel Subscription
|
|
465
|
+
|
|
466
|
+
```javascript
|
|
467
|
+
async function cancelSubscription(subscriptionId) {
|
|
468
|
+
try {
|
|
469
|
+
const options = {
|
|
470
|
+
cancel_at_cycle_end: 0 // 0 to cancel immediately, 1 to cancel at end of cycle
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
const subscription = await instance.subscriptions.cancel(subscriptionId, options);
|
|
474
|
+
console.log('Subscription cancelled:', subscription);
|
|
475
|
+
return subscription;
|
|
476
|
+
} catch (error) {
|
|
477
|
+
console.error('Error cancelling subscription:', error);
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Fetch All Subscriptions
|
|
484
|
+
|
|
485
|
+
```javascript
|
|
486
|
+
async function fetchAllSubscriptions() {
|
|
487
|
+
try {
|
|
488
|
+
const options = {
|
|
489
|
+
count: 10,
|
|
490
|
+
skip: 0
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
const subscriptions = await instance.subscriptions.all(options);
|
|
494
|
+
console.log('Subscriptions:', subscriptions);
|
|
495
|
+
return subscriptions;
|
|
496
|
+
} catch (error) {
|
|
497
|
+
console.error('Error fetching subscriptions:', error);
|
|
498
|
+
throw error;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## Plans API
|
|
504
|
+
|
|
505
|
+
### Create Plan
|
|
506
|
+
|
|
507
|
+
```javascript
|
|
508
|
+
async function createPlan() {
|
|
509
|
+
try {
|
|
510
|
+
const planData = {
|
|
511
|
+
period: "monthly",
|
|
512
|
+
interval: 1,
|
|
513
|
+
item: {
|
|
514
|
+
name: "Premium Plan",
|
|
515
|
+
amount: 99900, // Amount in paise
|
|
516
|
+
currency: "INR",
|
|
517
|
+
description: "Premium monthly subscription"
|
|
518
|
+
},
|
|
519
|
+
notes: {
|
|
520
|
+
plan_type: "premium"
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
const plan = await instance.plans.create(planData);
|
|
525
|
+
console.log('Plan created:', plan);
|
|
526
|
+
return plan;
|
|
527
|
+
} catch (error) {
|
|
528
|
+
console.error('Error creating plan:', error);
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Fetch Plan Details
|
|
535
|
+
|
|
536
|
+
```javascript
|
|
537
|
+
async function fetchPlan(planId) {
|
|
538
|
+
try {
|
|
539
|
+
const plan = await instance.plans.fetch(planId);
|
|
540
|
+
console.log('Plan details:', plan);
|
|
541
|
+
return plan;
|
|
542
|
+
} catch (error) {
|
|
543
|
+
console.error('Error fetching plan:', error);
|
|
544
|
+
throw error;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Fetch All Plans
|
|
550
|
+
|
|
551
|
+
```javascript
|
|
552
|
+
async function fetchAllPlans() {
|
|
553
|
+
try {
|
|
554
|
+
const options = {
|
|
555
|
+
count: 10,
|
|
556
|
+
skip: 0
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
const plans = await instance.plans.all(options);
|
|
560
|
+
console.log('Plans:', plans);
|
|
561
|
+
return plans;
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error('Error fetching plans:', error);
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Invoices API
|
|
570
|
+
|
|
571
|
+
### Create Invoice
|
|
572
|
+
|
|
573
|
+
```javascript
|
|
574
|
+
async function createInvoice() {
|
|
575
|
+
try {
|
|
576
|
+
const invoiceData = {
|
|
577
|
+
type: "invoice",
|
|
578
|
+
description: "Invoice for the month of January 2025",
|
|
579
|
+
customer: {
|
|
580
|
+
name: "John Doe",
|
|
581
|
+
email: "john.doe@example.com",
|
|
582
|
+
contact: "+919876543210"
|
|
583
|
+
},
|
|
584
|
+
line_items: [
|
|
585
|
+
{
|
|
586
|
+
name: "Premium Subscription",
|
|
587
|
+
description: "Monthly subscription",
|
|
588
|
+
amount: 99900,
|
|
589
|
+
currency: "INR",
|
|
590
|
+
quantity: 1
|
|
591
|
+
}
|
|
592
|
+
],
|
|
593
|
+
currency: "INR",
|
|
594
|
+
email_notify: 1,
|
|
595
|
+
sms_notify: 1,
|
|
596
|
+
date: Math.floor(Date.now() / 1000)
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
const invoice = await instance.invoices.create(invoiceData);
|
|
600
|
+
console.log('Invoice created:', invoice);
|
|
601
|
+
return invoice;
|
|
602
|
+
} catch (error) {
|
|
603
|
+
console.error('Error creating invoice:', error);
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Fetch Invoice Details
|
|
610
|
+
|
|
611
|
+
```javascript
|
|
612
|
+
async function fetchInvoice(invoiceId) {
|
|
613
|
+
try {
|
|
614
|
+
const invoice = await instance.invoices.fetch(invoiceId);
|
|
615
|
+
console.log('Invoice details:', invoice);
|
|
616
|
+
return invoice;
|
|
617
|
+
} catch (error) {
|
|
618
|
+
console.error('Error fetching invoice:', error);
|
|
619
|
+
throw error;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Fetch All Invoices
|
|
625
|
+
|
|
626
|
+
```javascript
|
|
627
|
+
async function fetchAllInvoices() {
|
|
628
|
+
try {
|
|
629
|
+
const options = {
|
|
630
|
+
count: 10,
|
|
631
|
+
skip: 0
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
const invoices = await instance.invoices.all(options);
|
|
635
|
+
console.log('Invoices:', invoices);
|
|
636
|
+
return invoices;
|
|
637
|
+
} catch (error) {
|
|
638
|
+
console.error('Error fetching invoices:', error);
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Cancel Invoice
|
|
645
|
+
|
|
646
|
+
```javascript
|
|
647
|
+
async function cancelInvoice(invoiceId) {
|
|
648
|
+
try {
|
|
649
|
+
const invoice = await instance.invoices.cancel(invoiceId);
|
|
650
|
+
console.log('Invoice cancelled:', invoice);
|
|
651
|
+
return invoice;
|
|
652
|
+
} catch (error) {
|
|
653
|
+
console.error('Error cancelling invoice:', error);
|
|
654
|
+
throw error;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
## Payment Verification
|
|
660
|
+
|
|
661
|
+
### Verify Payment Signature
|
|
662
|
+
|
|
663
|
+
Verify payment signatures to ensure payment authenticity:
|
|
664
|
+
|
|
665
|
+
```javascript
|
|
666
|
+
const crypto = require('crypto');
|
|
667
|
+
const { validatePaymentVerification } = require('razorpay/dist/utils/razorpay-utils');
|
|
668
|
+
|
|
669
|
+
// Method 1: Using Razorpay's built-in utility
|
|
670
|
+
function verifyPaymentSignature(orderId, paymentId, signature) {
|
|
671
|
+
try {
|
|
672
|
+
const isValid = validatePaymentVerification(
|
|
673
|
+
{ order_id: orderId, payment_id: paymentId },
|
|
674
|
+
signature,
|
|
675
|
+
process.env.RAZORPAY_KEY_SECRET
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
if (isValid) {
|
|
679
|
+
console.log('Payment signature verified successfully');
|
|
680
|
+
return true;
|
|
681
|
+
} else {
|
|
682
|
+
console.log('Invalid payment signature');
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
} catch (error) {
|
|
686
|
+
console.error('Error verifying payment signature:', error);
|
|
687
|
+
return false;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Method 2: Manual verification
|
|
692
|
+
function verifyPaymentSignatureManual(orderId, paymentId, signature) {
|
|
693
|
+
try {
|
|
694
|
+
const generatedSignature = crypto
|
|
695
|
+
.createHmac('sha256', process.env.RAZORPAY_KEY_SECRET)
|
|
696
|
+
.update(`${orderId}|${paymentId}`)
|
|
697
|
+
.digest('hex');
|
|
698
|
+
|
|
699
|
+
const isValid = generatedSignature === signature;
|
|
700
|
+
|
|
701
|
+
if (isValid) {
|
|
702
|
+
console.log('Payment signature verified successfully');
|
|
703
|
+
return true;
|
|
704
|
+
} else {
|
|
705
|
+
console.log('Invalid payment signature');
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
} catch (error) {
|
|
709
|
+
console.error('Error verifying payment signature:', error);
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
## Webhook Handling and Validation
|
|
716
|
+
|
|
717
|
+
### Express.js Webhook Integration
|
|
718
|
+
|
|
719
|
+
Handle and validate incoming Razorpay webhooks:
|
|
720
|
+
|
|
721
|
+
```javascript
|
|
722
|
+
const express = require('express');
|
|
723
|
+
const crypto = require('crypto');
|
|
724
|
+
const { validateWebhookSignature } = require('razorpay/dist/utils/razorpay-utils');
|
|
725
|
+
|
|
726
|
+
const app = express();
|
|
727
|
+
|
|
728
|
+
// IMPORTANT: Use express.text() to get raw body for webhook signature validation
|
|
729
|
+
app.use(express.json({
|
|
730
|
+
verify: (req, res, buf) => {
|
|
731
|
+
req.rawBody = buf.toString();
|
|
732
|
+
}
|
|
733
|
+
}));
|
|
734
|
+
|
|
735
|
+
// Webhook validation middleware
|
|
736
|
+
function validateWebhook(req, res, next) {
|
|
737
|
+
const signature = req.headers['x-razorpay-signature'];
|
|
738
|
+
const webhookSecret = process.env.RAZORPAY_WEBHOOK_SECRET;
|
|
739
|
+
|
|
740
|
+
try {
|
|
741
|
+
const isValid = validateWebhookSignature(
|
|
742
|
+
req.rawBody,
|
|
743
|
+
signature,
|
|
744
|
+
webhookSecret
|
|
745
|
+
);
|
|
746
|
+
|
|
747
|
+
if (!isValid) {
|
|
748
|
+
return res.status(400).json({ error: 'Invalid signature' });
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
next();
|
|
752
|
+
} catch (error) {
|
|
753
|
+
console.error('Webhook validation error:', error);
|
|
754
|
+
return res.status(400).json({ error: 'Webhook validation failed' });
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Webhook endpoint
|
|
759
|
+
app.post('/webhook', validateWebhook, (req, res) => {
|
|
760
|
+
const event = req.body;
|
|
761
|
+
|
|
762
|
+
console.log('Webhook event:', event.event);
|
|
763
|
+
|
|
764
|
+
switch (event.event) {
|
|
765
|
+
case 'payment.authorized':
|
|
766
|
+
handlePaymentAuthorized(event.payload.payment.entity);
|
|
767
|
+
break;
|
|
768
|
+
|
|
769
|
+
case 'payment.captured':
|
|
770
|
+
handlePaymentCaptured(event.payload.payment.entity);
|
|
771
|
+
break;
|
|
772
|
+
|
|
773
|
+
case 'payment.failed':
|
|
774
|
+
handlePaymentFailed(event.payload.payment.entity);
|
|
775
|
+
break;
|
|
776
|
+
|
|
777
|
+
case 'order.paid':
|
|
778
|
+
handleOrderPaid(event.payload.order.entity);
|
|
779
|
+
break;
|
|
780
|
+
|
|
781
|
+
case 'refund.created':
|
|
782
|
+
handleRefundCreated(event.payload.refund.entity);
|
|
783
|
+
break;
|
|
784
|
+
|
|
785
|
+
case 'subscription.activated':
|
|
786
|
+
handleSubscriptionActivated(event.payload.subscription.entity);
|
|
787
|
+
break;
|
|
788
|
+
|
|
789
|
+
case 'subscription.cancelled':
|
|
790
|
+
handleSubscriptionCancelled(event.payload.subscription.entity);
|
|
791
|
+
break;
|
|
792
|
+
|
|
793
|
+
case 'invoice.paid':
|
|
794
|
+
handleInvoicePaid(event.payload.invoice.entity);
|
|
795
|
+
break;
|
|
796
|
+
|
|
797
|
+
default:
|
|
798
|
+
console.log('Unhandled event:', event.event);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
res.json({ status: 'ok' });
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
function handlePaymentAuthorized(payment) {
|
|
805
|
+
console.log('Payment authorized:', payment.id);
|
|
806
|
+
// Capture the payment or perform other actions
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function handlePaymentCaptured(payment) {
|
|
810
|
+
console.log('Payment captured:', payment.id);
|
|
811
|
+
// Update order status, send confirmation email, etc.
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function handlePaymentFailed(payment) {
|
|
815
|
+
console.log('Payment failed:', payment.id);
|
|
816
|
+
// Notify customer, update order status, etc.
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function handleOrderPaid(order) {
|
|
820
|
+
console.log('Order paid:', order.id);
|
|
821
|
+
// Process order fulfillment
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function handleRefundCreated(refund) {
|
|
825
|
+
console.log('Refund created:', refund.id);
|
|
826
|
+
// Update records, notify customer
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
function handleSubscriptionActivated(subscription) {
|
|
830
|
+
console.log('Subscription activated:', subscription.id);
|
|
831
|
+
// Grant access to subscription features
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
function handleSubscriptionCancelled(subscription) {
|
|
835
|
+
console.log('Subscription cancelled:', subscription.id);
|
|
836
|
+
// Revoke access, send cancellation email
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
function handleInvoicePaid(invoice) {
|
|
840
|
+
console.log('Invoice paid:', invoice.id);
|
|
841
|
+
// Update invoice status, send receipt
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
app.listen(3000, () => {
|
|
845
|
+
console.log('Webhook server listening on port 3000');
|
|
846
|
+
});
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### Manual Webhook Signature Validation
|
|
850
|
+
|
|
851
|
+
```javascript
|
|
852
|
+
const crypto = require('crypto');
|
|
853
|
+
|
|
854
|
+
function validateWebhookManual(webhookBody, signature, secret) {
|
|
855
|
+
try {
|
|
856
|
+
const generatedSignature = crypto
|
|
857
|
+
.createHmac('sha256', secret)
|
|
858
|
+
.update(webhookBody)
|
|
859
|
+
.digest('hex');
|
|
860
|
+
|
|
861
|
+
return generatedSignature === signature;
|
|
862
|
+
} catch (error) {
|
|
863
|
+
console.error('Error validating webhook:', error);
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// Usage
|
|
869
|
+
app.post('/webhook', (req, res) => {
|
|
870
|
+
const signature = req.headers['x-razorpay-signature'];
|
|
871
|
+
const isValid = validateWebhookManual(
|
|
872
|
+
req.rawBody,
|
|
873
|
+
signature,
|
|
874
|
+
process.env.RAZORPAY_WEBHOOK_SECRET
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
if (!isValid) {
|
|
878
|
+
return res.status(400).json({ error: 'Invalid signature' });
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Process webhook event
|
|
882
|
+
res.json({ status: 'ok' });
|
|
883
|
+
});
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
## Transfers API (Route)
|
|
887
|
+
|
|
888
|
+
### Create Transfer
|
|
889
|
+
|
|
890
|
+
Transfer funds to linked accounts:
|
|
891
|
+
|
|
892
|
+
```javascript
|
|
893
|
+
async function createTransfer(paymentId) {
|
|
894
|
+
try {
|
|
895
|
+
const transferData = {
|
|
896
|
+
transfers: [
|
|
897
|
+
{
|
|
898
|
+
account: "acc_xxxxxxxxxxxxx",
|
|
899
|
+
amount: 10000, // Amount in paise
|
|
900
|
+
currency: "INR",
|
|
901
|
+
notes: {
|
|
902
|
+
name: "Transfer to vendor",
|
|
903
|
+
roll_no: "IEC2011025"
|
|
904
|
+
},
|
|
905
|
+
linked_account_notes: ["branch"],
|
|
906
|
+
on_hold: 0, // 0 to transfer immediately, 1 to hold
|
|
907
|
+
on_hold_until: null
|
|
908
|
+
}
|
|
909
|
+
]
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
const transfer = await instance.payments.transfer(paymentId, transferData);
|
|
913
|
+
console.log('Transfer created:', transfer);
|
|
914
|
+
return transfer;
|
|
915
|
+
} catch (error) {
|
|
916
|
+
console.error('Error creating transfer:', error);
|
|
917
|
+
throw error;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
### Fetch Transfer Details
|
|
923
|
+
|
|
924
|
+
```javascript
|
|
925
|
+
async function fetchTransfer(transferId) {
|
|
926
|
+
try {
|
|
927
|
+
const transfer = await instance.transfers.fetch(transferId);
|
|
928
|
+
console.log('Transfer details:', transfer);
|
|
929
|
+
return transfer;
|
|
930
|
+
} catch (error) {
|
|
931
|
+
console.error('Error fetching transfer:', error);
|
|
932
|
+
throw error;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
## Virtual Accounts API
|
|
938
|
+
|
|
939
|
+
### Create Virtual Account
|
|
940
|
+
|
|
941
|
+
```javascript
|
|
942
|
+
async function createVirtualAccount() {
|
|
943
|
+
try {
|
|
944
|
+
const vaData = {
|
|
945
|
+
receivers: {
|
|
946
|
+
types: ["bank_account"]
|
|
947
|
+
},
|
|
948
|
+
description: "Virtual Account for customer XYZ",
|
|
949
|
+
customer_id: "cust_xxxxxxxxxxxxx",
|
|
950
|
+
close_by: Math.floor(Date.now() / 1000) + 86400 * 30, // Close after 30 days
|
|
951
|
+
notes: {
|
|
952
|
+
purpose: "Rent collection"
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
const virtualAccount = await instance.virtualAccounts.create(vaData);
|
|
957
|
+
console.log('Virtual Account created:', virtualAccount);
|
|
958
|
+
return virtualAccount;
|
|
959
|
+
} catch (error) {
|
|
960
|
+
console.error('Error creating virtual account:', error);
|
|
961
|
+
throw error;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
### Fetch Virtual Account Details
|
|
967
|
+
|
|
968
|
+
```javascript
|
|
969
|
+
async function fetchVirtualAccount(vaId) {
|
|
970
|
+
try {
|
|
971
|
+
const virtualAccount = await instance.virtualAccounts.fetch(vaId);
|
|
972
|
+
console.log('Virtual Account details:', virtualAccount);
|
|
973
|
+
return virtualAccount;
|
|
974
|
+
} catch (error) {
|
|
975
|
+
console.error('Error fetching virtual account:', error);
|
|
976
|
+
throw error;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
## Error Handling
|
|
982
|
+
|
|
983
|
+
### Comprehensive Error Handling
|
|
984
|
+
|
|
985
|
+
```javascript
|
|
986
|
+
async function safeApiCall() {
|
|
987
|
+
try {
|
|
988
|
+
const order = await instance.orders.create({
|
|
989
|
+
amount: 50000,
|
|
990
|
+
currency: "INR",
|
|
991
|
+
receipt: "receipt_12345"
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
return {
|
|
995
|
+
success: true,
|
|
996
|
+
data: order
|
|
997
|
+
};
|
|
998
|
+
} catch (error) {
|
|
999
|
+
console.error('Razorpay API Error:', {
|
|
1000
|
+
statusCode: error.statusCode,
|
|
1001
|
+
error: error.error,
|
|
1002
|
+
description: error.error?.description,
|
|
1003
|
+
field: error.error?.field,
|
|
1004
|
+
reason: error.error?.reason
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
return {
|
|
1008
|
+
success: false,
|
|
1009
|
+
error: {
|
|
1010
|
+
code: error.statusCode,
|
|
1011
|
+
message: error.error?.description || 'An error occurred',
|
|
1012
|
+
field: error.error?.field
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
### Common Error Codes
|
|
1020
|
+
|
|
1021
|
+
Handle specific error scenarios:
|
|
1022
|
+
|
|
1023
|
+
```javascript
|
|
1024
|
+
async function handleErrors() {
|
|
1025
|
+
try {
|
|
1026
|
+
const payment = await instance.payments.fetch('pay_xxxxxxxxxxxxx');
|
|
1027
|
+
return payment;
|
|
1028
|
+
} catch (error) {
|
|
1029
|
+
switch (error.statusCode) {
|
|
1030
|
+
case 400:
|
|
1031
|
+
console.error('Bad Request - Invalid parameters');
|
|
1032
|
+
break;
|
|
1033
|
+
case 401:
|
|
1034
|
+
console.error('Unauthorized - Invalid API credentials');
|
|
1035
|
+
break;
|
|
1036
|
+
case 404:
|
|
1037
|
+
console.error('Not Found - Resource does not exist');
|
|
1038
|
+
break;
|
|
1039
|
+
case 500:
|
|
1040
|
+
console.error('Internal Server Error - Razorpay issue');
|
|
1041
|
+
break;
|
|
1042
|
+
default:
|
|
1043
|
+
console.error('Unknown error:', error);
|
|
1044
|
+
}
|
|
1045
|
+
throw error;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
## Complete Payment Flow Example
|
|
1051
|
+
|
|
1052
|
+
### Server-Side Integration
|
|
1053
|
+
|
|
1054
|
+
```javascript
|
|
1055
|
+
const express = require('express');
|
|
1056
|
+
const Razorpay = require('razorpay');
|
|
1057
|
+
const crypto = require('crypto');
|
|
1058
|
+
const { validatePaymentVerification } = require('razorpay/dist/utils/razorpay-utils');
|
|
1059
|
+
|
|
1060
|
+
const app = express();
|
|
1061
|
+
app.use(express.json());
|
|
1062
|
+
|
|
1063
|
+
const instance = new Razorpay({
|
|
1064
|
+
key_id: process.env.RAZORPAY_KEY_ID,
|
|
1065
|
+
key_secret: process.env.RAZORPAY_KEY_SECRET
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
// Step 1: Create order
|
|
1069
|
+
app.post('/create-order', async (req, res) => {
|
|
1070
|
+
try {
|
|
1071
|
+
const { amount, currency, receipt } = req.body;
|
|
1072
|
+
|
|
1073
|
+
const options = {
|
|
1074
|
+
amount: amount * 100, // Convert to paise
|
|
1075
|
+
currency: currency || 'INR',
|
|
1076
|
+
receipt: receipt || `receipt_${Date.now()}`,
|
|
1077
|
+
notes: {
|
|
1078
|
+
description: 'Order payment'
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
const order = await instance.orders.create(options);
|
|
1083
|
+
|
|
1084
|
+
res.json({
|
|
1085
|
+
success: true,
|
|
1086
|
+
order: {
|
|
1087
|
+
id: order.id,
|
|
1088
|
+
amount: order.amount,
|
|
1089
|
+
currency: order.currency
|
|
1090
|
+
},
|
|
1091
|
+
key_id: process.env.RAZORPAY_KEY_ID
|
|
1092
|
+
});
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
console.error('Error creating order:', error);
|
|
1095
|
+
res.status(500).json({
|
|
1096
|
+
success: false,
|
|
1097
|
+
message: 'Failed to create order'
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
// Step 2: Verify payment
|
|
1103
|
+
app.post('/verify-payment', async (req, res) => {
|
|
1104
|
+
try {
|
|
1105
|
+
const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body;
|
|
1106
|
+
|
|
1107
|
+
const isValid = validatePaymentVerification(
|
|
1108
|
+
{ order_id: razorpay_order_id, payment_id: razorpay_payment_id },
|
|
1109
|
+
razorpay_signature,
|
|
1110
|
+
process.env.RAZORPAY_KEY_SECRET
|
|
1111
|
+
);
|
|
1112
|
+
|
|
1113
|
+
if (isValid) {
|
|
1114
|
+
// Payment is successful, update database
|
|
1115
|
+
const payment = await instance.payments.fetch(razorpay_payment_id);
|
|
1116
|
+
|
|
1117
|
+
res.json({
|
|
1118
|
+
success: true,
|
|
1119
|
+
message: 'Payment verified successfully',
|
|
1120
|
+
payment: {
|
|
1121
|
+
id: payment.id,
|
|
1122
|
+
amount: payment.amount,
|
|
1123
|
+
status: payment.status
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1126
|
+
} else {
|
|
1127
|
+
res.status(400).json({
|
|
1128
|
+
success: false,
|
|
1129
|
+
message: 'Payment verification failed'
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
console.error('Error verifying payment:', error);
|
|
1134
|
+
res.status(500).json({
|
|
1135
|
+
success: false,
|
|
1136
|
+
message: 'Payment verification error'
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
// Step 3: Fetch payment details
|
|
1142
|
+
app.get('/payment/:id', async (req, res) => {
|
|
1143
|
+
try {
|
|
1144
|
+
const payment = await instance.payments.fetch(req.params.id);
|
|
1145
|
+
res.json({
|
|
1146
|
+
success: true,
|
|
1147
|
+
payment
|
|
1148
|
+
});
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
console.error('Error fetching payment:', error);
|
|
1151
|
+
res.status(500).json({
|
|
1152
|
+
success: false,
|
|
1153
|
+
message: 'Failed to fetch payment'
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
app.listen(3000, () => {
|
|
1159
|
+
console.log('Server running on port 3000');
|
|
1160
|
+
});
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
## Security Best Practices
|
|
1164
|
+
|
|
1165
|
+
### Never Expose Credentials
|
|
1166
|
+
|
|
1167
|
+
```javascript
|
|
1168
|
+
// Good - Use environment variables
|
|
1169
|
+
const instance = new Razorpay({
|
|
1170
|
+
key_id: process.env.RAZORPAY_KEY_ID,
|
|
1171
|
+
key_secret: process.env.RAZORPAY_KEY_SECRET
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
// Bad - Hardcoded credentials
|
|
1175
|
+
const instance = new Razorpay({
|
|
1176
|
+
key_id: 'rzp_test_xxxxxxxxxxxx',
|
|
1177
|
+
key_secret: 'your_secret_here'
|
|
1178
|
+
});
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
### Always Validate Webhooks
|
|
1182
|
+
|
|
1183
|
+
```javascript
|
|
1184
|
+
// Always verify webhook signatures before processing
|
|
1185
|
+
const isValid = validateWebhookSignature(
|
|
1186
|
+
req.rawBody,
|
|
1187
|
+
req.headers['x-razorpay-signature'],
|
|
1188
|
+
process.env.RAZORPAY_WEBHOOK_SECRET
|
|
1189
|
+
);
|
|
1190
|
+
|
|
1191
|
+
if (!isValid) {
|
|
1192
|
+
return res.status(400).json({ error: 'Invalid signature' });
|
|
1193
|
+
}
|
|
1194
|
+
```
|
|
1195
|
+
|
|
1196
|
+
### Verify Payment Signatures
|
|
1197
|
+
|
|
1198
|
+
```javascript
|
|
1199
|
+
// Always verify payment signatures on the server
|
|
1200
|
+
const isValid = validatePaymentVerification(
|
|
1201
|
+
{ order_id: orderId, payment_id: paymentId },
|
|
1202
|
+
signature,
|
|
1203
|
+
process.env.RAZORPAY_KEY_SECRET
|
|
1204
|
+
);
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
## Useful Links
|
|
1208
|
+
|
|
1209
|
+
- **Documentation:** https://razorpay.com/docs/
|
|
1210
|
+
- **API Reference:** https://razorpay.com/docs/api/
|
|
1211
|
+
- **Node.js SDK Docs:** https://razorpay.com/docs/payments/server-integration/nodejs/
|
|
1212
|
+
- **NPM Package:** https://www.npmjs.com/package/razorpay
|
|
1213
|
+
- **GitHub Repository:** https://github.com/razorpay/razorpay-node
|
|
1214
|
+
- **Dashboard:** https://dashboard.razorpay.com/
|
|
1215
|
+
- **Support:** https://razorpay.com/support/
|
|
1216
|
+
|
|
1217
|
+
## Notes
|
|
1218
|
+
|
|
1219
|
+
This guide covers the core functionality of the Razorpay Node.js SDK. The SDK provides a promise-based API for all Razorpay services including payments, orders, refunds, subscriptions, customers, invoices, transfers, and virtual accounts. Always use environment variables for credentials and validate all payment signatures and webhook signatures to ensure security.
|