Skip to main content

PayPal Community

  • Dashboard
  • Send and Request
  • Wallet
  • Business
  • Help
Log in

Le forum de Communauté ne sera plus disponible à partir du 30 Juin 2025. Le Forum de la communauté n’est pas disponible pour les nouveaux messages ou les réponses; les articles précédents restent disponibles pour vérification. Afin de connaître les options d’assistance complètes, rendez-vous sur PayPal.com/HelpCenter

Si vous souhaitez signaler du contenu illégal et contraire au Règlement sur les services numériques de l’Union Européenne (DSA), veuillez cliquer ici.

since ‎Oct-01-2024
Country: United Kingdom
Type: Personal
logix92
logix92
New Community Member
2
Posts
0
Kudos
1
Solution
Helper
Ice Breaker
Active
View all
Latest Contributions by logix92
  • Topics logix92 has Participated In
  • Latest Contributions by logix92

Re: PayPal integration with Next, Lambda and API G...

by logix92 in Sandbox Environment
‎Oct-01-2024 03:48 PM
‎Oct-01-2024 03:48 PM
OK I have found a solution to this - I could delete post, but figured someone else may find it useful if coming across - the issue was that when using Lambda integration vs Lambda proxy integration (I was using direct lambda integration, not proxy) - the httpMethod and path needed to be accessed using the `event.` handle i.e.   As the failure point was the `if` statement for httpmethod and path, I used a combination of cloudwatch logs to observe the `event` object being sent through to verify the structure of it.    The way to access the lambda method and path is like below: event.requestContext.http.method event.requestContext.http.path   Once I changed this, the if was accessed properly and I was able to successfully proceed to entering email/password within the PayPal window as the order was successfully created.   Please mark this as resolved.     ... View more

PayPal integration with Next, Lambda and API Gatew...

by logix92 in Sandbox Environment
‎Oct-01-2024 03:22 PM
‎Oct-01-2024 03:22 PM
Hi all,   I am integrating PayPal into a Next JS front-end, hosted on AWS Amplify using Lambda and API Gateway to communicate with PayPal API.   For now this is Sandbox to test integration. No matter what I try, I keep getting 400 Invalid Request (Which is an else statement in my Lambda function). I am sure I have followed PayPal documentation as closely as possible. In terms of API gateway config I have ensured CORS is setup correctly and the request is definitely hitting the Lambda but failing for some reason I can not figure out. My Front-end code is like so:   // src/utils/paypalUtils.js const API_ENDPOINT = 'https://1uwgpcbn4f.execute-api.eu-west-1.amazonaws.com'; export const createOrder = async (course) => { try { console.log('Creating order for course:', JSON.stringify(course, null, 2)); const response = await fetch(`${API_ENDPOINT}/create-paypal-order`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ cart: [ { id: course.slug, name: course.title, price: course.price, quantity: "1", deliveryOption: course.deliveryOption } ] }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(`Failed to create order: ${response.status} ${response.statusText}. ${JSON.stringify(errorData)}`); } const orderData = await response.json(); if (!orderData.id) { throw new Error(`Order ID is missing from the response: ${JSON.stringify(orderData)}`); } console.log('Order created successfully:', orderData.id); return orderData.id; } catch (error) { console.error('Error creating order:', error); throw error; } }; export const onApprove = async (data, actions) => { try { const response = await fetch(`${API_ENDPOINT}/capture-paypal-order?orderID=${data.orderID}`, { method: 'POST', }); if (!response.ok) { throw new Error('Failed to capture order'); } const captureData = await response.json(); const captureStatus = captureData.status; if (captureStatus === "COMPLETED") { console.log('Payment completed successfully', captureData); return { success: true, data: captureData }; } else { throw new Error(`Payment not completed. Status: ${captureStatus}`); } } catch (error) { console.error('Error capturing order:', error); throw error; } };   My Lambda function is like so:   import https from 'https'; import { v4 as uuidv4 } from 'uuid'; // Import the uuid function const PAYPAL_API_BASE = 'api-m.sandbox.paypal.com'; // Use 'api-m.paypal.com' for production const PAYPAL_CLIENT_ID = process.env.PAYPAL_CLIENT_ID; const PAYPAL_CLIENT_SECRET = process.env.PAYPAL_CLIENT_SECRET; const headers = { "Access-Control-Allow-Origin": "*", // Adjust this to your frontend URL for production "Access-Control-Allow-Headers": "Content-Type", "Access-Control-Allow-Methods": "OPTIONS,POST,GET" }; async function getAccessToken() { const auth = Buffer.from(`${PAYPAL_CLIENT_ID}:${PAYPAL_CLIENT_SECRET}`).toString('base64'); const options = { hostname: PAYPAL_API_BASE, path: '/v1/oauth2/token', method: 'POST', headers: { 'Authorization': `Basic ${auth}`, 'Content-Type': 'application/x-www-form-urlencoded' } }; return new Promise((resolve, reject) => { const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => { const jsonData = JSON.parse(data); resolve(jsonData.access_token); }); }); req.on('error', reject); req.write('grant_type=client_credentials'); req.end(); }); } async function createPayPalOrder(accessToken, orderData) { const options = { hostname: PAYPAL_API_BASE, path: '/v2/checkout/orders', method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'PayPal-Request-Id': uuidv4() // Generate a unique ID for idempotency } }; return new Promise((resolve, reject) => { const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => { if (res.statusCode >= 200 && res.statusCode < 300) { resolve(JSON.parse(data)); } else { reject(new Error(`Failed to create order: ${res.statusCode} ${data}`)); } }); }); req.on('error', reject); req.write(JSON.stringify(orderData)); req.end(); }); } async function capturePayPalOrder(accessToken, orderId) { const options = { hostname: PAYPAL_API_BASE, path: `/v2/checkout/orders/${orderId}/capture`, method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }; return new Promise((resolve, reject) => { const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => { if (res.statusCode >= 200 && res.statusCode < 300) { resolve(JSON.parse(data)); } else { reject(new Error(`Failed to capture order: ${res.statusCode} ${data}`)); } }); }); req.on('error', reject); req.end(); }); } export const handler = async (event) => { console.log('Received event:', JSON.stringify(event, null, 2)); const { httpMethod, path, body, queryStringParameters } = event; try { const accessToken = await getAccessToken(); if (httpMethod === 'POST' && path === '/create-paypal-order') { const cartData = JSON.parse(body); console.log('Parsed cart data:', cartData); // Construct the order data const orderData = { intent: 'CAPTURE', purchase_units: cartData.cart.map(item => ({ amount: { currency_code: 'GBP', value: item.price, breakdown: { item_total: { currency_code: 'GBP', value: item.price } } }, items: [ { name: item.name, description: `${item.name} - ${item.deliveryOption} delivery`, sku: item.id, unit_amount: { currency_code: 'GBP', value: item.price }, quantity: item.quantity } ] })) }; console.log('PayPal order data:', orderData); const result = await createPayPalOrder(accessToken, orderData); console.log('PayPal API response:', result); return { statusCode: 200, headers: headers, body: JSON.stringify({ id: result.id }), }; } else if (httpMethod === 'POST' && path === '/capture-paypal-order') { const orderId = queryStringParameters.orderID; const result = await capturePayPalOrder(accessToken, orderId); return { statusCode: 200, headers: headers, body: JSON.stringify(result), }; } else { return { statusCode: 400, headers: headers, body: JSON.stringify({ message: 'Invalid request' }), }; } } catch (error) { console.error('Error:', error); return { statusCode: 500, headers: headers, body: JSON.stringify({ error: 'Internal server error', details: error.message }) }; } };     A cloudwatch log of said event:   2024-10-01T21:59:28.272Z 26115af9-00e1-4d66-a278-52a3e903684a INFO Received event: { "version": "2.0", "routeKey": "POST /create-paypal-order", "rawPath": "/create-paypal-order", "rawQueryString": "", "headers": { "accept": "*/*", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": "en-GB,en-US;q=0.9,en;q=0.8", "content-length": "136", "content-type": "application/json", "host": "1uwgpcbn4f.execute-api.eu-west-1.amazonaws.com", "origin": "https://main.d2ige300djz6d5.amplifyapp.com", "priority": "u=1, i", "referer": "https://main.d2ige300djz6d5.amplifyapp.com/", "sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "cross-site", "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36", "x-amzn-trace-id": "Root=1-66fc70bf-04fc2b5c0ea975cd522342ed", "x-forwarded-for": "154.60.94.168", "x-forwarded-port": "443", "x-forwarded-proto": "https" }, "requestContext": { "accountId": "682033468988", "apiId": "1uwgpcbn4f", "domainName": "1uwgpcbn4f.execute-api.eu-west-1.amazonaws.com", "domainPrefix": "1uwgpcbn4f", "http": { "method": "POST", "path": "/create-paypal-order", "protocol": "HTTP/1.1", "sourceIp": "154.60.94.168", "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36" }, "requestId": "e_aOCj50DoEEJwA=", "routeKey": "POST /create-paypal-order", "stage": "$default", "time": "01/Oc[Removed. Phone #s not permitted]+0000", "timeEpoch": 1727819967904 }, "body": "{\"cart\":[{\"id\":\"ecg-course-for-beginners\",\"name\":\"ECG Course for Beginners\",\"price\":\"299.99\",\"quantity\":\"1\",\"deliveryOption\":\"remote\"}]}", "isBase64Encoded": false }   I have a package.json for the uuid component setup so there is no issue there, and I have setup environment variables within my Lambda that have the paypal client and secret. Any insights would be appreciated. ... View more
Paypal Logo
  • Help
  • Contact Us
  • Security
  • Fees
  • © 1999-2025 PayPal, Inc. All rights reserved.
  • Privacy
  • Legal
  • Cookies
  • Policy Updates

The money in your balance is eligible for pass-through FDIC insurance.

The PayPal Cash Mastercard is issued by The Bancorp Bank pursuant to a license by Mastercard International Incorporated. The Bancorp Bank; Member FDIC.

Powered by Khoros