import env from 'dotenv' ; env . config ( { path : './.env' } ) ; import bodyParser from 'body-parser' ; import express from 'express' ; import Stripe from 'stripe' ; import { generateResponse } from './utils' ; const stripePublishableKey = process . env . STRIPE_PUBLISHABLE_KEY || '' ; const stripeSecretKey = process . env . STRIPE_SECRET_KEY || '' ; const stripeWebhookSecret = process . env . STRIPE_WEBHOOK_SECRET || '' ; const app = express ( ) ; app . use ( ( req , res , next ) : void => { if ( req . originalUrl === '/webhook' ) { next ( ) ; } else { bodyParser . json ( ) ( req , res , next ) ; } } ) ; interface Order { items : object [ ] ; } const calculateOrderAmount = ( _order ? ) : number => { return 1400 ; } ; function getKeys ( payment_method ? ) { let secret_key = stripeSecretKey ; let publishable_key = stripePublishableKey ; switch ( payment_method ) { case 'grabpay' : case 'fpx' : publishable_key = process . env . STRIPE_PUBLISHABLE_KEY_MY ; secret_key = process . env . STRIPE_SECRET_KEY_MY ; break ; case 'au_becs_debit' : publishable_key = process . env . STRIPE_PUBLISHABLE_KEY_AU ; secret_key = process . env . STRIPE_SECRET_KEY_AU ; break ; case 'oxxo' : publishable_key = process . env . STRIPE_PUBLISHABLE_KEY_MX ; secret_key = process . env . STRIPE_SECRET_KEY_MX ; break ; case 'wechat_pay' : publishable_key = process . env . STRIPE_PUBLISHABLE_KEY_WECHAT ; secret_key = process . env . STRIPE_SECRET_KEY_WECHAT ; break ; default : publishable_key = process . env . STRIPE_PUBLISHABLE_KEY ; secret_key = process . env . STRIPE_SECRET_KEY ; } return { secret_key , publishable_key } ; } app . get ( '/stripe-key' , ( req , res ) : express . Response < any > => { const { publishable_key } = getKeys ( req . query . paymentMethod as string ) ; return res . send ( { publishableKey : publishable_key } ) ; } ) ; app . post ( '/create-payment-intent' , async ( req , res ) : Promise < express . Response < any > > => { const { email , items , currency , request_three_d_secure , payment_method_types = [ ] , client = 'ios' , } = req . body ; const { secret_key } = getKeys ( payment_method_types [ 0 ] ) ; const stripe = new Stripe ( secret_key as string , { apiVersion : '2020-08-27' , typescript : true , } ) ; const customer = await stripe . customers . create ( { email } ) ; const params = { amount : calculateOrderAmount ( items ) , currency , customer : customer . id , payment_method_options : { card : { request_three_d_secure : request_three_d_secure || 'automatic' , } , sofort : { preferred_language : 'en' , } , wechat_pay : { app_id : 'wx65907d6307c3827d' , client : client , } , } , payment_method_types : payment_method_types , } ; try { const paymentIntent = await stripe . paymentIntents . create ( params ) ; return res . send ( { clientSecret : paymentIntent . client_secret , } ) ; } catch ( error ) { return res . send ( { error : error . raw . message , } ) ; } } ) ; app . post ( '/create-payment-intent-with-payment-method' , async ( req , res ) : Promise < express . Response < any > > => { const { items , currency , request_three_d_secure , email , } = req . body ; const { secret_key } = getKeys ( ) ; const stripe = new Stripe ( secret_key as string , { apiVersion : '2020-08-27' , typescript : true , } ) ; const customers = await stripe . customers . list ( { email , } ) ; if ( ! customers . data [ 0 ] ) { return res . send ( { error : 'There is no associated customer object to the provided e-mail' , } ) ; } const paymentMethods = await stripe . paymentMethods . list ( { customer : customers . data [ 0 ] . id , type : 'card' , } ) ; if ( ! paymentMethods . data [ 0 ] ) { return res . send ( { error : `There is no associated payment method to the provided customer's e-mail` , } ) ; } const params = { amount : calculateOrderAmount ( items ) , currency , payment_method_options : { card : { request_three_d_secure : request_three_d_secure || 'automatic' , } , } , payment_method : paymentMethods . data [ 0 ] . id , customer : customers . data [ 0 ] . id , } ; const paymentIntent = await stripe . paymentIntents . create ( params ) ; return res . send ( { clientSecret : paymentIntent . client_secret , paymentMethodId : paymentMethods . data [ 0 ] . id , } ) ; } ) ; app . post ( '/pay-without-webhooks' , async ( req , res ) : Promise < express . Response < any > > => { const { paymentMethodId , paymentIntentId , items , currency , useStripeSdk , cvcToken , email , } = req . body ; const orderAmount = calculateOrderAmount ( items ) ; const { secret_key } = getKeys ( ) ; const stripe = new Stripe ( secret_key as string , { apiVersion : '2020-08-27' , typescript : true , } ) ; try { if ( cvcToken && email ) { const customers = await stripe . customers . list ( { email , } ) ; if ( ! customers . data [ 0 ] ) { return res . send ( { error : 'There is no associated customer object to the provided e-mail' , } ) ; } const paymentMethods = await stripe . paymentMethods . list ( { customer : customers . data [ 0 ] . id , type : 'card' , } ) ; if ( ! paymentMethods . data [ 0 ] ) { return res . send ( { error : `There is no associated payment method to the provided customer's e-mail` , } ) ; } const params = { amount : orderAmount , confirm : true , confirmation_method : 'manual' , currency , payment_method : paymentMethods . data [ 0 ] . id , payment_method_options : { card : { cvc_token : cvcToken , } , } , use_stripe_sdk : useStripeSdk , customer : customers . data [ 0 ] . id , } ; const intent = await stripe . paymentIntents . create ( params ) ; return res . send ( generateResponse ( intent ) ) ; } else if ( paymentMethodId ) { const params = { amount : orderAmount , confirm : true , confirmation_method : 'manual' , currency , payment_method : paymentMethodId , use_stripe_sdk : useStripeSdk , } ; const intent = await stripe . paymentIntents . create ( params ) ; return res . send ( generateResponse ( intent ) ) ; } else if ( paymentIntentId ) { const intent = await stripe . paymentIntents . confirm ( paymentIntentId ) ; return res . send ( generateResponse ( intent ) ) ; } return res . sendStatus ( 400 ) ; } catch ( e ) { return res . send ( { error : e . message } ) ; } } ) ; app . post ( '/create-setup-intent' , async ( req , res ) => { const { email , payment_method_types = [ ] , } = req . body ; const { secret_key } = getKeys ( payment_method_types [ 0 ] ) ; const stripe = new Stripe ( secret_key as string , { apiVersion : '2020-08-27' , typescript : true , } ) ; const customer = await stripe . customers . create ( { email } ) ; const setupIntent = await stripe . setupIntents . create ( { customer : customer . id , payment_method_types , } ) ; return res . send ( { publishableKey : process . env . STRIPE_PUBLISHABLE_KEY , clientSecret : setupIntent . client_secret , } ) ; } ) ; app . post ( '/webhook' , bodyParser . raw ( { type : 'application/json' } ) , ( req , res ) : express . Response < any > => { let event ; const { secret_key } = getKeys ( ) ; const stripe = new Stripe ( secret_key as string , { apiVersion : '2020-08-27' , typescript : true , } ) ; try { event = stripe . webhooks . constructEvent ( req . body , req . headers [ 'stripe-signature' ] || [ ] , stripeWebhookSecret ) ; } catch ( err ) { console . log ( `⚠️  Webhook signature verification failed.` ) ; return res . sendStatus ( 400 ) ; } const data = event . data ; const eventType = event . type ; if ( eventType === 'payment_intent.succeeded' ) { const pi = data . object as Stripe . PaymentIntent ; console . log ( `🔔  Webhook received: ${ pi . object } ${ pi . status }!` ) ; console . log ( '💰 Payment captured!' ) ; } if ( eventType === 'payment_intent.payment_failed' ) { const pi = data . object as Stripe . PaymentIntent ; console . log ( `🔔  Webhook received: ${ pi . object } ${ pi . status }!` ) ; console . log ( '❌ Payment failed.' ) ; } if ( eventType === 'setup_intent.setup_failed' ) { console . log ( `🔔  A SetupIntent has failed the to setup a PaymentMethod.` ) ; } if ( eventType === 'setup_intent.succeeded' ) { console . log ( `🔔  A SetupIntent has successfully setup a PaymentMethod for future use.` ) ; } if ( eventType === 'setup_intent.created' ) { const setupIntent = data . object as Stripe . SetupIntent ; console . log ( `🔔  A new SetupIntent is created. ${ setupIntent . id }` ) ; } return res . sendStatus ( 200 ) ; } ) ; app . post ( '/charge-card-off-session' , async ( req , res ) => { let paymentIntent , customer ; const { secret_key } = getKeys ( ) ; const stripe = new Stripe ( secret_key as string , { apiVersion : '2020-08-27' , typescript : true , } ) ; try { customer = await stripe . customers . list ( { email : req . body . email , } ) ; const paymentMethods = await stripe . paymentMethods . list ( { customer : customer . data [ 0 ] . id , type : 'card' , } ) ; paymentIntent = await stripe . paymentIntents . create ( { amount : calculateOrderAmount ( ) , currency : 'usd' , payment_method : paymentMethods . data [ 0 ] . id , customer : customer . data [ 0 ] . id , off_session : true , confirm : true , } ) ; return res . send ( { succeeded : true , clientSecret : paymentIntent . client_secret , publicKey : stripePublishableKey , } ) ; } catch ( err ) { if ( err . code === 'authentication_required' ) { return res . send ( { error : 'authentication_required' , paymentMethod : err . raw . payment_method . id , clientSecret : err . raw . payment_intent . client_secret , publicKey : stripePublishableKey , amount : calculateOrderAmount ( ) , card : { brand : err . raw . payment_method . card . brand , last4 : err . raw . payment_method . card . last4 , } , } ) ; } else if ( err . code ) { return res . send ( { error : err . code , clientSecret : err . raw . payment_intent . client_secret , publicKey : stripePublishableKey , } ) ; } else { console . log ( 'Unknown error occurred' , err ) ; return res . sendStatus ( 500 ) ; } } } ) ; app . post ( '/payment-sheet' , async ( _ , res ) => { const { secret_key } = getKeys ( ) ; const stripe = new Stripe ( secret_key as string , { apiVersion : '2020-08-27' , typescript : true , } ) ; const customers = await stripe . customers . list ( ) ; const customer = customers . data [ 0 ] ; if ( ! customer ) { return res . send ( { error : 'You have no customer created' , } ) ; } const ephemeralKey = await stripe . ephemeralKeys . create ( { customer : customer . id } , { apiVersion : '2020-08-27' } ) ; const paymentIntent = await stripe . paymentIntents . create ( { amount : 1099 , currency : 'usd' , customer : customer . id , } ) ; return res . json ( { paymentIntent : paymentIntent . client_secret , ephemeralKey : ephemeralKey . secret , customer : customer . id , } ) ; } ) ; app . listen ( 4242 , ( ) : void => console . log ( `Node server listening on port ${ 4242 }!` ) ) ;