├── README.md ├── client-side.tsx └── server-side.ts /README.md: -------------------------------------------------------------------------------- 1 | # Mercado Pago Reference Integration 2 | 3 | ## Introduction 4 | 5 | This is a reference integration for Mercado Pago. It is a simple example of how to integrate Mercado Pago with a simple web application. 6 | 7 | ## Steps 8 | 9 | 1. First you have to install mercadopago via npm or yarn. 10 | 2. Then you have to obtain your public key and access token from Mercado Pago, for this check the documentation: https://www.mercadopago.com.ar/developers/es/docs 11 | 3. In the API code of your app, copy and paste the server-side.ts file and use it like a route of your own. (i.e.: http://localhost:3000/api/checkout) 12 | 4. In the client side, use the client-side.tsx file, if you want you can copy the exact component, but keep in mind that you need some important data for sending to the API. 13 | 14 | ## Explanation 15 | 16 | The backend route needs some specific data about the payment, like the user's name, the details of the item, etc. These fields are REQUIRED. 17 | Once the preference is set, through the mercadopago package we are gonna try to create that preference, if everything goes fine, we we'll send the ID of the payment that the response gives us. 18 | 19 | Then in the front, the idea is to receive that ID once the page is loaded, that is why we are using the useEffect. Once the data and the ID is received, we'll be able to press the "Pay" button and Mercado Pago will do his magic. It's important to keep the container with that name, and the PUBLIC_KEY and ACCESS_TOKEN correct in our .env file. 20 | 21 | ## Requirements 22 | 23 | * Frontend in HTML, CSS and Javascript, or any other framework you want to use 24 | * Backend in Node 25 | 26 | -------------------------------------------------------------------------------- /client-side.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useContext } from 'react' 2 | import { TurnoContext, UserContext } from '@context/context' 3 | 4 | // In this example i'm using React 5 | // Other way to use this is using the script tag in the html file 6 | // and then use the global variable window.MercadoPago 7 | 8 | // Then some document.querySelector('.cho-container') to get the element 9 | // and then use the mp.checkout() method 10 | 11 | export default function MPButton() { 12 | const { turno } = useContext(TurnoContext) 13 | const { user } = useContext(UserContext) 14 | 15 | useEffect(() => { 16 | // The async function is needed since we can't do async stuff in the top level of our useEffect 17 | const fetchCheckout = async () => { 18 | const res = await fetch('/api/checkout', { 19 | method: 'POST', 20 | headers: { 21 | 'Content-Type': 'application/json', 22 | }, 23 | body: JSON.stringify({ 24 | user, 25 | turno 26 | }), 27 | }) 28 | const data = await res.json() 29 | 30 | // data.global is the ID that MP returns from the API, it comes from our backend route 31 | if(data.global) { 32 | const script = document.createElement('script') // Here we create the empty script tag 33 | script.type = 'text/javascript' // The type of the script 34 | script.src = 'https://sdk.mercadopago.com/js/v2' // The link where the script is hosted 35 | script.setAttribute('data-preference-id', data.global) // Here we set its data-preference-id to the ID that the Mercado Pago API gives us 36 | document.body.appendChild(script) // Here we append it to the body of our page 37 | 38 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 39 | // @ts-ignore 40 | 41 | // Here we create the button, setting the container, our public key and the ID of the preference that Mercado Pago API returns in its response 42 | const mp = new window.MercadoPago(process.env.NEXT_PUBLIC_MP_PUBLIC_KEY, { 43 | locale: 'es-AR' 44 | }) 45 | 46 | // The ".checkout" is the function that creates the connection between the button and the platform 47 | mp.checkout({ 48 | preference: { 49 | id: data.global 50 | }, 51 | render: { 52 | container: '.cho-container', 53 | label: 'Pagar', 54 | } 55 | }); 56 | } 57 | } 58 | 59 | // Here we just execute the function 60 | fetchCheckout() 61 | //eslint-disable-next-line 62 | }, []) 63 | 64 | return
65 | } 66 | -------------------------------------------------------------------------------- /server-side.ts: -------------------------------------------------------------------------------- 1 | // This is just the package (installed via npm or yarn) and its types 2 | import mercadopago from "mercadopago" 3 | import type { CreatePreferencePayload, PreferencePayer, PreferenceBackUrl } from 'mercadopago/models/preferences/create-payload.model' 4 | 5 | export default function handler(req: Request, res: Response) { 6 | 7 | // Here is where we configure our session, setting the access token provided by MP 8 | mercadopago.configure({ 9 | access_token: process.env.MP_ACCESS_TOKEN, 10 | }) 11 | 12 | // This is just boilerplate data, but really you'll need to catch the important data that MP asks for below 13 | const { user, turno } = req.body // or any other info needed 14 | 15 | // Here we create the "Preference", this is the config for the payment 16 | const preference: CreatePreferencePayload = { 17 | // This is always true * REQUIRED 18 | binary_mode: true, 19 | // The data of the item that the user has to pay for * REQUIRED 20 | items: [ 21 | { 22 | title: `${turno.service} - Nombre de la marca`, 23 | description: `Descripcion del producto`, 24 | picture_url: "url de imagen", 25 | quantity: 1 as number, 26 | currency_id: "currency needed (ARS, USD, etc)", 27 | unit_price: turno.price as number 28 | } 29 | ], 30 | // Data of the user * REQUIRED 31 | payer: { 32 | name: user.name as string, 33 | surname: user.name.split(" ")[1] ?? "TGB" as string, 34 | email: user.email as string 35 | } as PreferencePayer, 36 | // When the user finishes the payment, depending of the status of the payment he'll be redirected, you gotta put your custom urls 37 | back_urls: { 38 | success: "https://success.com", 39 | failure: "https://failure.com", 40 | pending: "https://pending.com" 41 | } as PreferenceBackUrl, 42 | // This is always "approved" 43 | auto_return: "approved" 44 | } 45 | 46 | // Here we config the preference, it's like send it to MP and then its API returns a response object. 47 | // We just need the id from it, so we set the response to { global: response.body.id }. 48 | // This will send an object literal where we can access the ID for our frontend button 49 | mercadopago.preferences.create(preference) 50 | .then(function (response) { 51 | res.status(200).json({global: response.body.id}) 52 | }) 53 | .catch((error) => { 54 | // In an error appears, we'll send the error. 55 | res.status(500).json({global: error}) 56 | }) 57 | } 58 | 59 | // IMPORTANT 60 | 61 | /* 62 | This is the only code needed, but you can save in your DB all the data you need. 63 | If this does not works, check your MP keys, your .env file, or the enviroment variables in your deployment. 64 | In case of not finding a solution to a supposed error, open an issue in this repo so i'll fix it in the future. 65 | */ 66 | --------------------------------------------------------------------------------