@bloque/payments 0.0.10 → 0.0.11
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 +134 -584
- package/dist/index.cjs +4 -4
- package/dist/index.js +4 -4
- package/dist/types/checkout.d.ts +8 -7
- package/dist/types/common.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
# Bloque Payments SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **TypeScript First**: Built with TypeScript for complete type safety
|
|
8
|
-
- **Simple API**: Intuitive interface for creating and managing checkouts
|
|
9
|
-
- **Multiple Payment Methods**: Support for cards, PSE, and cash payments
|
|
10
|
-
- **Fully Async**: Promise-based API for modern JavaScript workflows
|
|
11
|
-
- **Lightweight**: Minimal dependencies for optimal bundle size
|
|
3
|
+
Official TypeScript/JavaScript SDK for integrating Bloque payments.
|
|
12
4
|
|
|
13
5
|
## Installation
|
|
14
6
|
|
|
@@ -16,630 +8,188 @@ The official TypeScript/JavaScript SDK for integrating [Bloque](https://www.bloq
|
|
|
16
8
|
bun add @bloque/payments
|
|
17
9
|
```
|
|
18
10
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
import { Bloque, type PaymentSubmitPayload } from '@bloque/payments';
|
|
23
|
-
|
|
24
|
-
// Initialize the SDK (server-side only)
|
|
25
|
-
const bloque = new Bloque({
|
|
26
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
27
|
-
mode: 'production', // or 'sandbox' for testing
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
app.post('/api/payments', async (req, res) => {
|
|
31
|
-
try {
|
|
32
|
-
const payload: PaymentSubmitPayload = req.body;
|
|
33
|
-
|
|
34
|
-
// Create payment using SDK
|
|
35
|
-
const payment = await bloque.payments.create({
|
|
36
|
-
payment: payload,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
res.json({ success: true, payment });
|
|
40
|
-
} catch (error) {
|
|
41
|
-
res.status(500).json({ success: false, error: error.message });
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
```
|
|
11
|
+
## Initialize
|
|
45
12
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### Initialize the SDK
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
13
|
+
```ts
|
|
51
14
|
import { Bloque } from '@bloque/payments';
|
|
52
15
|
|
|
53
16
|
const bloque = new Bloque({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### Environment Options
|
|
60
|
-
|
|
61
|
-
- **`sandbox`**: For testing and development
|
|
62
|
-
- **`production`**: For live payments
|
|
63
|
-
|
|
64
|
-
## API Reference
|
|
65
|
-
|
|
66
|
-
### Payments
|
|
67
|
-
|
|
68
|
-
The payments resource allows you to create payments for existing checkout sessions.
|
|
69
|
-
|
|
70
|
-
#### Create a Payment
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
const payment = await bloque.payments.create({
|
|
74
|
-
checkoutId: string; // Required: Checkout ID from an existing checkout
|
|
75
|
-
payment: {
|
|
76
|
-
type: 'card' | 'pse' | 'cash',
|
|
77
|
-
data: {
|
|
78
|
-
// Payment method specific data
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Payment Types**:
|
|
85
|
-
|
|
86
|
-
**Card Payment**:
|
|
87
|
-
```typescript
|
|
88
|
-
{
|
|
89
|
-
type: 'card',
|
|
90
|
-
data: {
|
|
91
|
-
cardNumber: string; // 16-digit card number
|
|
92
|
-
cardholderName: string; // Name on the card
|
|
93
|
-
expiryMonth: string; // MM format
|
|
94
|
-
expiryYear: string; // YY or YYYY format
|
|
95
|
-
cvv: string; // 3-4 digit CVV
|
|
96
|
-
email?: string; // Optional customer email
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
**PSE Payment** (Colombian online banking):
|
|
102
|
-
```typescript
|
|
103
|
-
{
|
|
104
|
-
type: 'pse',
|
|
105
|
-
data: {
|
|
106
|
-
personType: 'natural' | 'juridica'; // Person type
|
|
107
|
-
documentType: string; // Document type (e.g., 'CC', 'NIT')
|
|
108
|
-
documentNumber: string; // Document number
|
|
109
|
-
bankCode: string; // Bank code
|
|
110
|
-
email: string; // Customer email
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
**Cash Payment**:
|
|
116
|
-
```typescript
|
|
117
|
-
{
|
|
118
|
-
type: 'cash',
|
|
119
|
-
data: {
|
|
120
|
-
email: string; // Customer email
|
|
121
|
-
documentType: string; // Document type
|
|
122
|
-
documentNumber: string; // Document number
|
|
123
|
-
fullName: string; // Full name
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
**Payment Response**:
|
|
129
|
-
```typescript
|
|
130
|
-
{
|
|
131
|
-
id: string; // Payment ID
|
|
132
|
-
object: 'payment'; // Object type
|
|
133
|
-
status: 'pending' | 'processing' | 'completed' | 'failed';
|
|
134
|
-
checkout: Checkout; // Associated checkout
|
|
135
|
-
payment_method: 'card' | 'pse' | 'cash';
|
|
136
|
-
amount: number; // Payment amount
|
|
137
|
-
currency: string; // Currency
|
|
138
|
-
created_at: string; // Creation timestamp
|
|
139
|
-
updated_at: string; // Last update timestamp
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Checkout
|
|
144
|
-
|
|
145
|
-
The checkout resource allows you to create payment sessions.
|
|
146
|
-
|
|
147
|
-
#### Create a Checkout
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
const checkout = await bloque.checkout.create({
|
|
151
|
-
name: string; // Required: Name of the checkout
|
|
152
|
-
description?: string; // Optional: Description
|
|
153
|
-
image_url?: string; // Optional: Product/checkout image URL
|
|
154
|
-
items: CheckoutItem[]; // Required: Items to be purchased
|
|
155
|
-
success_url: string; // Required: Redirect URL after success
|
|
156
|
-
cancel_url: string; // Required: Redirect URL after cancellation
|
|
157
|
-
metadata?: Record<string, string | number | boolean>; // Optional: Custom metadata
|
|
158
|
-
expires_at?: string; // Optional: Expiration date (ISO 8601)
|
|
159
|
-
});
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
**Checkout Item**:
|
|
163
|
-
```typescript
|
|
164
|
-
{
|
|
165
|
-
name: string; // Item name
|
|
166
|
-
amount: number; // Price in smallest currency unit (e.g., cents)
|
|
167
|
-
quantity: number; // Quantity
|
|
168
|
-
image_url?: string; // Item image URL
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
#### Checkout Response
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
{
|
|
176
|
-
id: string; // Unique checkout identifier
|
|
177
|
-
object: 'checkout'; // Object type
|
|
178
|
-
url: string; // Public payment URL for the customer
|
|
179
|
-
status: string; // Current checkout status
|
|
180
|
-
amount_total: number; // Total amount
|
|
181
|
-
amount_subtotal: number; // Subtotal amount
|
|
182
|
-
currency: 'USD'; // Currency
|
|
183
|
-
items: CheckoutItem[]; // Items in the checkout
|
|
184
|
-
metadata?: Metadata; // Custom metadata
|
|
185
|
-
created_at: string; // Creation timestamp (ISO 8601)
|
|
186
|
-
updated_at: string; // Last update timestamp (ISO 8601)
|
|
187
|
-
expires_at: string; // Expiration timestamp (ISO 8601)
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
#### Retrieve a Checkout
|
|
192
|
-
|
|
193
|
-
Retrieve the details of an existing checkout by its ID.
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
const checkout = await bloque.checkout.retrieve('checkout_id_here');
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
**Parameters**:
|
|
200
|
-
- `checkoutId` (string): The ID of the checkout to retrieve
|
|
201
|
-
|
|
202
|
-
**Returns**: A `Checkout` object with all the checkout details.
|
|
203
|
-
|
|
204
|
-
#### Cancel a Checkout
|
|
205
|
-
|
|
206
|
-
Cancel an existing checkout that hasn't been completed yet.
|
|
207
|
-
|
|
208
|
-
```typescript
|
|
209
|
-
const checkout = await bloque.checkout.cancel('checkout_id_here');
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
**Parameters**:
|
|
213
|
-
- `checkoutId` (string): The ID of the checkout to cancel
|
|
214
|
-
|
|
215
|
-
**Returns**: A `Checkout` object with updated status reflecting the cancellation.
|
|
216
|
-
|
|
217
|
-
### Webhooks
|
|
218
|
-
|
|
219
|
-
The webhooks resource allows you to verify the authenticity of webhook events sent from Bloque.
|
|
220
|
-
|
|
221
|
-
#### Verify Webhook Signature
|
|
222
|
-
|
|
223
|
-
Verify that a webhook event was actually sent by Bloque using HMAC-SHA256 signature verification.
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
const isValid = bloque.webhooks.verify(
|
|
227
|
-
requestBody,
|
|
228
|
-
signatureHeader,
|
|
229
|
-
{ secret: process.env.WEBHOOK_SECRET }
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
if (isValid) {
|
|
233
|
-
// Process the webhook event
|
|
234
|
-
} else {
|
|
235
|
-
// Reject the webhook
|
|
236
|
-
}
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
**Parameters**:
|
|
240
|
-
- `body` (string | object): The raw webhook request body
|
|
241
|
-
- `signature` (string): The signature from the `x-bloque-signature` header
|
|
242
|
-
- `options` (optional): Verification options
|
|
243
|
-
- `secret` (string): Webhook secret key. Can be set during SDK initialization or passed here
|
|
244
|
-
|
|
245
|
-
**Returns**: `boolean` - `true` if the webhook signature is valid, `false` otherwise
|
|
246
|
-
|
|
247
|
-
**Configuration**:
|
|
248
|
-
|
|
249
|
-
You can set the webhook secret during SDK initialization:
|
|
250
|
-
|
|
251
|
-
```typescript
|
|
252
|
-
const bloque = new Bloque({
|
|
253
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
254
|
-
mode: 'production',
|
|
255
|
-
webhookSecret: process.env.BLOQUE_WEBHOOK_SECRET,
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
// Then you can verify without passing the secret each time
|
|
259
|
-
const isValid = bloque.webhooks.verify(body, signature);
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
Or pass it directly during verification:
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
const isValid = bloque.webhooks.verify(body, signature, {
|
|
266
|
-
secret: process.env.BLOQUE_WEBHOOK_SECRET,
|
|
17
|
+
mode: 'sandbox', // 'sandbox' | 'production'
|
|
18
|
+
accessToken: process.env.BLOQUE_ACCESS_TOKEN!,
|
|
19
|
+
webhookSecret: process.env.BLOQUE_WEBHOOK_SECRET, // optional
|
|
267
20
|
});
|
|
268
21
|
```
|
|
269
22
|
|
|
270
|
-
##
|
|
23
|
+
## Quick Start: Create Checkout
|
|
271
24
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
import { Bloque, type PaymentSubmitPayload } from '@bloque/payments';
|
|
276
|
-
|
|
277
|
-
// Initialize SDK with your API key
|
|
278
|
-
const bloque = new Bloque({
|
|
279
|
-
apiKey: process.env.BLOQUE_API_KEY!,
|
|
280
|
-
mode: 'production',
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
// API endpoint handler
|
|
284
|
-
app.post('/api/payments', async (req, res) => {
|
|
285
|
-
try {
|
|
286
|
-
// Receive payment data from frontend
|
|
287
|
-
const payload: PaymentSubmitPayload = req.body;
|
|
288
|
-
|
|
289
|
-
// Create payment using SDK
|
|
290
|
-
const payment = await bloque.payments.create({
|
|
291
|
-
payment: payload,
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
res.json({ success: true, payment });
|
|
295
|
-
} catch (error) {
|
|
296
|
-
res.status(500).json({ success: false, error: error.message });
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### Payment Methods Examples
|
|
302
|
-
|
|
303
|
-
#### Card Payment
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
// Receive payload from frontend
|
|
307
|
-
const cardPayment: PaymentSubmitPayload = req.body;
|
|
308
|
-
// Example payload:
|
|
309
|
-
// {
|
|
310
|
-
// type: 'card',
|
|
311
|
-
// data: {
|
|
312
|
-
// cardNumber: '4111111111111111',
|
|
313
|
-
// cardholderName: 'John Doe',
|
|
314
|
-
// expiryMonth: '12',
|
|
315
|
-
// expiryYear: '2025',
|
|
316
|
-
// cvv: '123',
|
|
317
|
-
// email: 'john@example.com'
|
|
318
|
-
// }
|
|
319
|
-
// }
|
|
320
|
-
|
|
321
|
-
const payment = await bloque.payments.create({
|
|
322
|
-
payment: cardPayment,
|
|
323
|
-
});
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
#### PSE Payment (Colombian online banking)
|
|
327
|
-
|
|
328
|
-
```typescript
|
|
329
|
-
// Receive payload from frontend
|
|
330
|
-
const psePayment: PaymentSubmitPayload = req.body;
|
|
331
|
-
// Example payload:
|
|
332
|
-
// {
|
|
333
|
-
// type: 'pse',
|
|
334
|
-
// data: {
|
|
335
|
-
// personType: 'natural',
|
|
336
|
-
// documentType: 'CC',
|
|
337
|
-
// documentNumber: '1234567890',
|
|
338
|
-
// bankCode: '1022',
|
|
339
|
-
// email: 'maria@example.com'
|
|
340
|
-
// }
|
|
341
|
-
// }
|
|
342
|
-
|
|
343
|
-
const payment = await bloque.payments.create({
|
|
344
|
-
payment: psePayment,
|
|
345
|
-
});
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
#### Cash Payment
|
|
349
|
-
|
|
350
|
-
```typescript
|
|
351
|
-
// Receive payload from frontend
|
|
352
|
-
const cashPayment: PaymentSubmitPayload = req.body;
|
|
353
|
-
// Example payload:
|
|
354
|
-
// {
|
|
355
|
-
// type: 'cash',
|
|
356
|
-
// data: {
|
|
357
|
-
// email: 'carlos@example.com',
|
|
358
|
-
// documentType: 'CC',
|
|
359
|
-
// documentNumber: '9876543210',
|
|
360
|
-
// fullName: 'Carlos García'
|
|
361
|
-
// }
|
|
362
|
-
// }
|
|
363
|
-
|
|
364
|
-
const payment = await bloque.payments.create({
|
|
365
|
-
payment: cashPayment,
|
|
366
|
-
});
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### Type-Safe Payment Creation
|
|
370
|
-
|
|
371
|
-
The `PaymentSubmitPayload` type is a discriminated union that provides automatic type narrowing:
|
|
372
|
-
|
|
373
|
-
```typescript
|
|
374
|
-
// Backend API handler
|
|
375
|
-
async function handlePayment(payload: PaymentSubmitPayload) {
|
|
376
|
-
// TypeScript automatically narrows the type based on the 'type' field
|
|
377
|
-
switch (payload.type) {
|
|
378
|
-
case 'card':
|
|
379
|
-
// payload.data is CardPaymentFormData
|
|
380
|
-
console.log('Processing card ending in:', payload.data.cardNumber.slice(-4));
|
|
381
|
-
break;
|
|
382
|
-
|
|
383
|
-
case 'pse':
|
|
384
|
-
// payload.data is PSEPaymentFormData
|
|
385
|
-
console.log('Processing PSE for bank:', payload.data.bankCode);
|
|
386
|
-
break;
|
|
387
|
-
|
|
388
|
-
case 'cash':
|
|
389
|
-
// payload.data is CashPaymentFormData
|
|
390
|
-
console.log('Processing cash payment for:', payload.data.fullName);
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Create payment using SDK
|
|
395
|
-
return await bloque.payments.create({
|
|
396
|
-
payment: payload,
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### Webhook Handler
|
|
402
|
-
|
|
403
|
-
Handle incoming webhook events from Bloque and verify their authenticity:
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
25
|
+
```ts
|
|
406
26
|
import { Bloque } from '@bloque/payments';
|
|
407
27
|
|
|
408
|
-
// Initialize SDK with webhook secret
|
|
409
28
|
const bloque = new Bloque({
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
webhookSecret: process.env.BLOQUE_WEBHOOK_SECRET,
|
|
29
|
+
mode: 'sandbox',
|
|
30
|
+
accessToken: process.env.BLOQUE_ACCESS_TOKEN!,
|
|
413
31
|
});
|
|
414
32
|
|
|
415
|
-
// Webhook endpoint
|
|
416
|
-
app.post(
|
|
417
|
-
'/webhooks/bloque',
|
|
418
|
-
(req, res) => {
|
|
419
|
-
const signature = req.headers['x-bloque-signature'] as string;
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
// Verify the webhook signature
|
|
423
|
-
const isValid = bloque.webhooks.verify(req.body.toString(), signature);
|
|
424
|
-
|
|
425
|
-
if (!isValid) {
|
|
426
|
-
return res.status(400).send('Invalid signature');
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Parse and process the event
|
|
430
|
-
const event = JSON.parse(req.body.toString());
|
|
431
|
-
|
|
432
|
-
switch (event.type) {
|
|
433
|
-
case 'checkout.completed':
|
|
434
|
-
console.log('Checkout completed:', event.data);
|
|
435
|
-
// Update database, send confirmation, etc.
|
|
436
|
-
break;
|
|
437
|
-
|
|
438
|
-
case 'payment.succeeded':
|
|
439
|
-
console.log('Payment succeeded:', event.data);
|
|
440
|
-
break;
|
|
441
|
-
|
|
442
|
-
case 'payment.failed':
|
|
443
|
-
console.log('Payment failed:', event.data);
|
|
444
|
-
break;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
res.json({ received: true });
|
|
448
|
-
} catch (error) {
|
|
449
|
-
console.error('Webhook error:', error);
|
|
450
|
-
res.status(400).send('Webhook error');
|
|
451
|
-
}
|
|
452
|
-
},
|
|
453
|
-
);
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
### Basic Checkout with Single Item
|
|
457
|
-
|
|
458
|
-
```typescript
|
|
459
33
|
const checkout = await bloque.checkout.create({
|
|
460
|
-
name: '
|
|
461
|
-
description:
|
|
34
|
+
name: 'Pack Profesional de Productividad',
|
|
35
|
+
description:
|
|
36
|
+
'Periféricos premium para trabajo intensivo y alto rendimiento',
|
|
37
|
+
asset: 'COPM/2',
|
|
38
|
+
image_url: 'https://cdn.bloque.app/checkouts/productivity-pack.png',
|
|
462
39
|
items: [
|
|
463
40
|
{
|
|
464
|
-
name: '
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
},
|
|
468
|
-
],
|
|
469
|
-
success_url: 'https://yourapp.com/success',
|
|
470
|
-
cancel_url: 'https://yourapp.com/cancel',
|
|
471
|
-
});
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
### Checkout with Multiple Items
|
|
475
|
-
|
|
476
|
-
```typescript
|
|
477
|
-
const checkout = await bloque.checkout.create({
|
|
478
|
-
name: 'Shopping Cart',
|
|
479
|
-
description: 'Your selected items',
|
|
480
|
-
items: [
|
|
481
|
-
{
|
|
482
|
-
name: 'Wireless Mouse',
|
|
483
|
-
amount: 25_00,
|
|
484
|
-
quantity: 1,
|
|
485
|
-
image_url: 'https://example.com/mouse.jpg',
|
|
486
|
-
},
|
|
487
|
-
{
|
|
488
|
-
name: 'USB Cable',
|
|
489
|
-
amount: 10_00,
|
|
41
|
+
name: 'Teclado mecánico Keychron K2',
|
|
42
|
+
description: 'Wireless, RGB, switches Blue',
|
|
43
|
+
amount: 450_000_00,
|
|
490
44
|
quantity: 2,
|
|
491
|
-
image_url: 'https://
|
|
45
|
+
image_url: 'https://cdn.bloque.app/items/keychron-k2.png',
|
|
492
46
|
},
|
|
493
|
-
],
|
|
494
|
-
success_url: 'https://yourapp.com/success',
|
|
495
|
-
cancel_url: 'https://yourapp.com/cancel',
|
|
496
|
-
});
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
### Checkout with Metadata and Expiration
|
|
500
|
-
|
|
501
|
-
```typescript
|
|
502
|
-
const checkout = await bloque.checkout.create({
|
|
503
|
-
name: 'Limited Time Offer',
|
|
504
|
-
items: [
|
|
505
47
|
{
|
|
506
|
-
name: '
|
|
507
|
-
|
|
48
|
+
name: 'Mouse Logitech MX Master 3S',
|
|
49
|
+
description: 'Inalámbrico, sensor 8K DPI',
|
|
50
|
+
amount: 380_000_00,
|
|
508
51
|
quantity: 1,
|
|
52
|
+
image_url: 'https://cdn.bloque.app/items/mx-master-3s.png',
|
|
509
53
|
},
|
|
510
54
|
],
|
|
511
|
-
success_url: 'https://
|
|
512
|
-
cancel_url: 'https://
|
|
513
|
-
metadata: {
|
|
514
|
-
user_id: '12345',
|
|
515
|
-
campaign: 'summer_sale',
|
|
516
|
-
discount_applied: true,
|
|
517
|
-
},
|
|
518
|
-
expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // 24 hours
|
|
55
|
+
success_url: 'https://bloque.app/success',
|
|
56
|
+
cancel_url: 'https://bloque.app/cancel',
|
|
519
57
|
});
|
|
520
|
-
```
|
|
521
58
|
|
|
59
|
+
console.log('Checkout URL:', checkout.url);
|
|
60
|
+
```
|
|
522
61
|
|
|
523
|
-
##
|
|
62
|
+
## API
|
|
524
63
|
|
|
525
|
-
|
|
64
|
+
### `Bloque` config
|
|
526
65
|
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
} catch (error) {
|
|
536
|
-
console.error('Failed to create checkout:', error);
|
|
537
|
-
}
|
|
66
|
+
```ts
|
|
67
|
+
type BloqueConfig = {
|
|
68
|
+
mode: 'sandbox' | 'production';
|
|
69
|
+
accessToken: string;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
maxRetries?: number;
|
|
72
|
+
webhookSecret?: string;
|
|
73
|
+
};
|
|
538
74
|
```
|
|
539
75
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
This SDK is written in TypeScript and includes complete type definitions. You'll get full autocomplete and type checking when using TypeScript or modern editors like VS Code:
|
|
543
|
-
|
|
544
|
-
```typescript
|
|
545
|
-
import type {
|
|
546
|
-
// Payment types
|
|
547
|
-
PaymentSubmitPayload,
|
|
548
|
-
PaymentResponse,
|
|
549
|
-
CreatePaymentParams,
|
|
550
|
-
// Checkout types
|
|
551
|
-
Checkout,
|
|
552
|
-
CheckoutStatus,
|
|
553
|
-
CheckoutItem,
|
|
554
|
-
CheckoutParams,
|
|
555
|
-
// Webhook types
|
|
556
|
-
WebhookVerifyOptions,
|
|
557
|
-
} from '@bloque/payments';
|
|
558
|
-
|
|
559
|
-
const item: CheckoutItem = {
|
|
560
|
-
name: 'Product',
|
|
561
|
-
amount: 5000,
|
|
562
|
-
quantity: 1,
|
|
563
|
-
};
|
|
76
|
+
### Checkout
|
|
564
77
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
78
|
+
#### `bloque.checkout.create(params)`
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
type CheckoutParams = {
|
|
82
|
+
name: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
image_url?: string;
|
|
85
|
+
asset?: 'COPM/2' | 'DUSD/6';
|
|
86
|
+
items: {
|
|
87
|
+
name: string;
|
|
88
|
+
description?: string;
|
|
89
|
+
amount: number;
|
|
90
|
+
quantity: number;
|
|
91
|
+
image_url?: string;
|
|
92
|
+
}[];
|
|
93
|
+
success_url: string;
|
|
94
|
+
cancel_url: string;
|
|
95
|
+
metadata?: Record<string, string | number | boolean>;
|
|
96
|
+
expires_at?: string;
|
|
575
97
|
};
|
|
576
98
|
```
|
|
577
99
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
100
|
+
Notes:
|
|
101
|
+
- `asset` defaults to `DUSD/6` when omitted.
|
|
102
|
+
- Creation request is sent using `redirect_url` derived from `success_url`.
|
|
103
|
+
|
|
104
|
+
Response shape:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
type Checkout = {
|
|
108
|
+
id: string;
|
|
109
|
+
object: 'checkout';
|
|
110
|
+
url: string;
|
|
111
|
+
status: 'pending' | 'completed' | 'expired' | 'canceled';
|
|
112
|
+
amount_total: number;
|
|
113
|
+
amount_subtotal: number;
|
|
114
|
+
asset: 'COPM/2' | 'DUSD/6';
|
|
115
|
+
items: {
|
|
116
|
+
name: string;
|
|
117
|
+
description?: string;
|
|
118
|
+
amount: number;
|
|
119
|
+
quantity: number;
|
|
120
|
+
image_url?: string;
|
|
121
|
+
}[];
|
|
122
|
+
metadata?: Record<string, string | number | boolean>;
|
|
123
|
+
created_at: string;
|
|
124
|
+
updated_at: string;
|
|
125
|
+
expires_at: string | null;
|
|
126
|
+
};
|
|
602
127
|
```
|
|
603
128
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
### Building the SDK
|
|
129
|
+
#### `bloque.checkout.retrieve(checkoutId)`
|
|
607
130
|
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
bun run build
|
|
131
|
+
```ts
|
|
132
|
+
const checkout = await bloque.checkout.retrieve('checkout_123');
|
|
611
133
|
```
|
|
612
134
|
|
|
613
|
-
|
|
135
|
+
#### `bloque.checkout.cancel(checkoutId)`
|
|
614
136
|
|
|
615
|
-
```
|
|
616
|
-
|
|
137
|
+
```ts
|
|
138
|
+
const checkout = await bloque.checkout.cancel('checkout_123');
|
|
617
139
|
```
|
|
618
140
|
|
|
619
|
-
###
|
|
141
|
+
### Payments
|
|
620
142
|
|
|
621
|
-
|
|
622
|
-
bun run typecheck
|
|
623
|
-
```
|
|
143
|
+
#### `bloque.payments.create(params)`
|
|
624
144
|
|
|
625
|
-
|
|
145
|
+
Current supported submit payload is card:
|
|
626
146
|
|
|
627
|
-
```
|
|
628
|
-
|
|
147
|
+
```ts
|
|
148
|
+
const payment = await bloque.payments.create({
|
|
149
|
+
checkoutId: 'checkout_123',
|
|
150
|
+
payment: {
|
|
151
|
+
type: 'card',
|
|
152
|
+
data: {
|
|
153
|
+
cardNumber: '4111111111111111',
|
|
154
|
+
cardholderName: 'John Doe',
|
|
155
|
+
expiryMonth: '12',
|
|
156
|
+
expiryYear: '2028',
|
|
157
|
+
cvv: '123',
|
|
158
|
+
email: 'john@example.com',
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
629
162
|
```
|
|
630
163
|
|
|
631
|
-
|
|
164
|
+
Payment response:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
type PaymentResponse = {
|
|
168
|
+
id: string;
|
|
169
|
+
object: 'payment';
|
|
170
|
+
status: 'pending' | 'processing' | 'completed' | 'failed';
|
|
171
|
+
amount: number;
|
|
172
|
+
currency: string;
|
|
173
|
+
created_at: string;
|
|
174
|
+
updated_at: string;
|
|
175
|
+
};
|
|
176
|
+
```
|
|
632
177
|
|
|
633
|
-
|
|
634
|
-
- TypeScript 5.x or higher (for TypeScript projects)
|
|
178
|
+
### Webhooks
|
|
635
179
|
|
|
636
|
-
|
|
180
|
+
Verify webhook signature (`HMAC-SHA256`):
|
|
637
181
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
182
|
+
```ts
|
|
183
|
+
const isValid = bloque.webhooks.verify(
|
|
184
|
+
rawBody,
|
|
185
|
+
signature,
|
|
186
|
+
{ secret: process.env.BLOQUE_WEBHOOK_SECRET! },
|
|
187
|
+
);
|
|
188
|
+
```
|
|
641
189
|
|
|
642
|
-
|
|
190
|
+
You can also set `webhookSecret` during `Bloque` initialization and omit `options` in `verify`.
|
|
643
191
|
|
|
644
|
-
|
|
192
|
+
## Example
|
|
645
193
|
|
|
194
|
+
Full example available at:
|
|
195
|
+
- `examples/basic-checkout.ts`
|
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
27
|
Bloque: ()=>Bloque
|
|
28
28
|
});
|
|
29
|
-
var package_namespaceObject = JSON.parse('{"UU":"@bloque/payments","rE":"0.0.
|
|
29
|
+
var package_namespaceObject = JSON.parse('{"UU":"@bloque/payments","rE":"0.0.11"}');
|
|
30
30
|
class BloqueError extends Error {
|
|
31
31
|
constructor(message){
|
|
32
32
|
super(message);
|
|
@@ -208,7 +208,7 @@ class CheckoutResource extends BaseResource {
|
|
|
208
208
|
const payload = {
|
|
209
209
|
name: params.name,
|
|
210
210
|
description: params.description,
|
|
211
|
-
asset: '
|
|
211
|
+
asset: params.asset ?? 'DUSD/6',
|
|
212
212
|
payment_type: 'shopping_cart',
|
|
213
213
|
image_url: params.image_url,
|
|
214
214
|
items: items,
|
|
@@ -216,7 +216,7 @@ class CheckoutResource extends BaseResource {
|
|
|
216
216
|
expires_at: params.expires_at,
|
|
217
217
|
metadata: params.metadata
|
|
218
218
|
};
|
|
219
|
-
const response = await this.http.post('/
|
|
219
|
+
const response = await this.http.post('/', payload);
|
|
220
220
|
return {
|
|
221
221
|
id: response.payment.urn,
|
|
222
222
|
object: 'checkout',
|
|
@@ -224,7 +224,7 @@ class CheckoutResource extends BaseResource {
|
|
|
224
224
|
status: response.payment.summary.status,
|
|
225
225
|
amount_total: response.payment.amount,
|
|
226
226
|
amount_subtotal: response.payment.amount,
|
|
227
|
-
|
|
227
|
+
asset: response.payment.asset,
|
|
228
228
|
items: params.items,
|
|
229
229
|
created_at: response.payment.created_at,
|
|
230
230
|
updated_at: response.payment.updated_at,
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHmac } from "node:crypto";
|
|
2
|
-
var package_namespaceObject = JSON.parse('{"UU":"@bloque/payments","rE":"0.0.
|
|
2
|
+
var package_namespaceObject = JSON.parse('{"UU":"@bloque/payments","rE":"0.0.11"}');
|
|
3
3
|
class BloqueError extends Error {
|
|
4
4
|
constructor(message){
|
|
5
5
|
super(message);
|
|
@@ -181,7 +181,7 @@ class CheckoutResource extends BaseResource {
|
|
|
181
181
|
const payload = {
|
|
182
182
|
name: params.name,
|
|
183
183
|
description: params.description,
|
|
184
|
-
asset: '
|
|
184
|
+
asset: params.asset ?? 'DUSD/6',
|
|
185
185
|
payment_type: 'shopping_cart',
|
|
186
186
|
image_url: params.image_url,
|
|
187
187
|
items: items,
|
|
@@ -189,7 +189,7 @@ class CheckoutResource extends BaseResource {
|
|
|
189
189
|
expires_at: params.expires_at,
|
|
190
190
|
metadata: params.metadata
|
|
191
191
|
};
|
|
192
|
-
const response = await this.http.post('/
|
|
192
|
+
const response = await this.http.post('/', payload);
|
|
193
193
|
return {
|
|
194
194
|
id: response.payment.urn,
|
|
195
195
|
object: 'checkout',
|
|
@@ -197,7 +197,7 @@ class CheckoutResource extends BaseResource {
|
|
|
197
197
|
status: response.payment.summary.status,
|
|
198
198
|
amount_total: response.payment.amount,
|
|
199
199
|
amount_subtotal: response.payment.amount,
|
|
200
|
-
|
|
200
|
+
asset: response.payment.asset,
|
|
201
201
|
items: params.items,
|
|
202
202
|
created_at: response.payment.created_at,
|
|
203
203
|
updated_at: response.payment.updated_at,
|
package/dist/types/checkout.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ASSETS, Metadata } from './common';
|
|
2
2
|
import type { Customer } from './customer';
|
|
3
3
|
export interface CreateCheckoutPayload {
|
|
4
4
|
name: string;
|
|
5
5
|
description?: string;
|
|
6
6
|
image_url?: string;
|
|
7
|
-
asset:
|
|
7
|
+
asset: ASSETS;
|
|
8
8
|
payment_type: 'shopping_cart';
|
|
9
9
|
items: {
|
|
10
10
|
name: string;
|
|
@@ -20,6 +20,7 @@ export interface CreateCheckoutResponse {
|
|
|
20
20
|
payment: {
|
|
21
21
|
urn: string;
|
|
22
22
|
url: string;
|
|
23
|
+
asset: ASSETS;
|
|
23
24
|
amount: number;
|
|
24
25
|
image_url?: string | null;
|
|
25
26
|
metadata?: Metadata | null;
|
|
@@ -80,11 +81,11 @@ export interface CheckoutParams {
|
|
|
80
81
|
*/
|
|
81
82
|
items: CheckoutItem[];
|
|
82
83
|
/**
|
|
83
|
-
*
|
|
84
|
+
* Asset used for the checkout.
|
|
84
85
|
*
|
|
85
|
-
* @default '
|
|
86
|
+
* @default 'dUSD/6'
|
|
86
87
|
*/
|
|
87
|
-
|
|
88
|
+
asset?: ASSETS;
|
|
88
89
|
/**
|
|
89
90
|
* URL the customer will be redirected to after a successful payment.
|
|
90
91
|
*/
|
|
@@ -144,9 +145,9 @@ export interface Checkout {
|
|
|
144
145
|
*/
|
|
145
146
|
amount_subtotal: number;
|
|
146
147
|
/**
|
|
147
|
-
*
|
|
148
|
+
* Asset used for the checkout.
|
|
148
149
|
*/
|
|
149
|
-
|
|
150
|
+
asset: ASSETS;
|
|
150
151
|
/**
|
|
151
152
|
* Customer associated with the checkout, if any.
|
|
152
153
|
*/
|
package/dist/types/common.d.ts
CHANGED