├── .gitignore ├── .env.example ├── package.json ├── app.js ├── routes └── index.js ├── controllers └── PaymentController.js ├── services └── PaymentService.js └── bin └── www /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /node_modules -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | ACCESS_TOKEN="" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mercadopago", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "axios": "^0.26.0", 10 | "cookie-parser": "~1.4.4", 11 | "debug": "~2.6.9", 12 | "dotenv": "^16.0.0", 13 | "express": "~4.16.1", 14 | "http-errors": "~1.6.3", 15 | "morgan": "~1.9.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const path = require("path"); 3 | const cookieParser = require("cookie-parser"); 4 | const logger = require("morgan"); 5 | const dotenv = require("dotenv"); 6 | 7 | const indexRouter = require("./routes/index"); 8 | 9 | const app = express(); 10 | 11 | dotenv.config(); 12 | 13 | app.use(logger("dev")); 14 | app.use(express.json()); 15 | app.use(express.urlencoded({ extended: false })); 16 | app.use(cookieParser()); 17 | app.use(express.static(path.join(__dirname, "public"))); 18 | 19 | app.use("/", indexRouter); 20 | 21 | module.exports = app; 22 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | 4 | const PaymentController = require("../controllers/PaymentController"); 5 | const PaymentService = require("../services/PaymentService"); 6 | 7 | const PaymentInstance = new PaymentController(new PaymentService()); 8 | 9 | router.get("/", function (req, res, next) { 10 | return res.json({ 11 | "/payment": "generates a payment link", 12 | "/subscription": "generates a subscription link" 13 | }); 14 | }); 15 | 16 | router.get("/payment", function (req, res, next) { 17 | PaymentInstance.getPaymentLink(req, res); 18 | }); 19 | 20 | router.get("/subscription", function (req, res, next) { 21 | PaymentInstance.getSubscriptionLink(req, res); 22 | }); 23 | 24 | module.exports = router; 25 | -------------------------------------------------------------------------------- /controllers/PaymentController.js: -------------------------------------------------------------------------------- 1 | class PaymentController { 2 | constructor(subscriptionService) { 3 | this.subscriptionService = subscriptionService; 4 | } 5 | 6 | async getPaymentLink(req, res) { 7 | try { 8 | const payment = await this.subscriptionService.createPayment(); 9 | 10 | return res.json(payment); 11 | } catch (error) { 12 | console.log(error); 13 | 14 | return res 15 | .status(500) 16 | .json({ error: true, msg: "Failed to create payment" }); 17 | } 18 | } 19 | 20 | async getSubscriptionLink(req, res) { 21 | try { 22 | const subscription = await this.subscriptionService.createSubscription(); 23 | 24 | return res.json(subscription); 25 | } catch (error) { 26 | console.log(error); 27 | 28 | return res 29 | .status(500) 30 | .json({ error: true, msg: "Failed to create subscription" }); 31 | } 32 | } 33 | } 34 | 35 | module.exports = PaymentController; 36 | -------------------------------------------------------------------------------- /services/PaymentService.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | 3 | class PaymentService { 4 | async createPayment() { 5 | const url = "https://api.mercadopago.com/checkout/preferences"; 6 | 7 | const body = { 8 | payer_email: "test_user_46945293@testuser.com", 9 | items: [ 10 | { 11 | title: "Dummy Title", 12 | description: "Dummy description", 13 | picture_url: "http://www.myapp.com/myimage.jpg", 14 | category_id: "category123", 15 | quantity: 1, 16 | unit_price: 10 17 | } 18 | ], 19 | back_urls: { 20 | failure: "/failure", 21 | pending: "/pending", 22 | success: "/success" 23 | } 24 | }; 25 | 26 | const payment = await axios.post(url, body, { 27 | headers: { 28 | "Content-Type": "application/json", 29 | Authorization: `Bearer ${process.env.ACCESS_TOKEN}` 30 | } 31 | }); 32 | 33 | return payment.data; 34 | } 35 | 36 | async createSubscription() { 37 | const url = "https://api.mercadopago.com/preapproval"; 38 | 39 | const body = { 40 | reason: "Suscripción de ejemplo", 41 | auto_recurring: { 42 | frequency: 1, 43 | frequency_type: "months", 44 | transaction_amount: 10, 45 | currency_id: "ARS" 46 | }, 47 | back_url: "https://google.com.ar", 48 | payer_email: "test_user_46945293@testuser.com" 49 | }; 50 | 51 | const subscription = await axios.post(url, body, { 52 | headers: { 53 | "Content-Type": "application/json", 54 | Authorization: `Bearer ${process.env.ACCESS_TOKEN}` 55 | } 56 | }); 57 | 58 | return subscription.data; 59 | } 60 | } 61 | 62 | module.exports = PaymentService; 63 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('mercadopago:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | --------------------------------------------------------------------------------