#ortega_paymentsheet-group

1 messages ยท Page 1 of 1 (latest)

ivory zephyrBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1278842355352469515

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

modern walrus
#

(give me a few minutes)

willow nova
#

Thank you koopajah

#

To add to this, the connection with the backend and the application works perfectly. The problem is that I want a payment to be processed and the user to be able to store payment methods for future purchases.

modern walrus
#

Can you share your client-side code (the Swift part) where you initialize the PaymentSheet?

willow nova
#

Yes

#

It's an extractSubview():

// MARK: Implementation New PaymentSheet
if let paymentSheet = model.paymentSheet {
PaymentSheet.PaymentButton(
paymentSheet: paymentSheet,
onCompletion: model.onPaymentCompletion
) {
Text("Buy")
}
} else {
Text("Loading...")
}

        if let result = model.paymentResult {
            switch result {
            case .completed:
                // print("Payment completed successfully!")
                Text("Payment successfully!")
            case .failed(let error):
                Text("Payment failed: \(error.localizedDescription)")
            case .canceled:
                Text("Payment canceled.")
            }
        }

In the main view I call the function in the onAppear state:

let total = totalAmount(subtotal: subtotal, taxes: salesTax)

        model.preparePaymentSheet(total: Int(total)) { success in
            if success {
                print("El monto total a enviar al backend es: \(total)")
            } else {
                print("No se pudo obtener el total a enviar al backend")
            }
        } onError: { error in
            print("Error al preparar la hoja de pago: \(error.localizedDescription)")
        }

I ask for the total purchase.

modern walrus
#

yeah none of those are configuring the PaymentSheet. I need to see where you configure it, pass the API key, client_secret, etc.

#

ortega_paymentsheet-group

willow nova
#

What I did is that when a user registers in my application, it automatically creates a new customer in the Stripe dashboard. Therefore I can retrieve the customerId and also the ephemeralKey to be able to make a paymentIntent.

modern walrus
#

yeah the reason I'm asking is that 99% of the time you pass the wrong ids to that part of the code

#
                   let ephemeralKey = json["ephemeralKey"] as? String,
                   let publishableKey = json["publishableKey"] as? String {```
#

can you log those and then show me a redacted version of each? I especially want the prefix

#

paymentIntentClientSecret should look like pi_123123213_secret_xxxx
ephemeralKey should look like ek_123456
publishableKey should look like pk_1234

#

Ah also you use customerId elsewhere so it should be cus_1234

willow nova
#

Give me a few minutes to try.

#

I have already made a new registration:

Dates send to backend: newpaymentintent@gmail.com, 1234567890, New Payment
CustomerId: cus_QkmyYDYLtlBjZv
Stripe customer created successfully

Received data: {"paymentIntent":{"id":"pi_3PtHOrAZJHGoU7Pr1ta9Zqrd","object":"payment_intent","amount":1400,"amount_capturable":0,"amount_details":{"tip":{}},"amount_received":0,"application":null,"application_fee_amount":null,"automatic_payment_methods":{"allow_redirects":"always","enabled":true},"canceled_at":null,"cancellation_reason":null,"capture_method":"automatic_async","client_secret":"pi_3PtHOrAZJHGoU7Pr1ta9Zqrd_secret_BYPtIte5wcDhi9CRjSxH3yyOM","confirmation_method":"automatic","created":1724972709,"currency":"usd","customer":"cus_QkmyYDYLtlBjZv","description":null,"invoice":null,"last_payment_error":null,"latest_charge":null,"livemode":false,"metadata":{},"next_action":null,"on_behalf_of":null,"payment_method":null,"payment_method_configuration_details":{"id":"pmc_1Pn3zOAZJHGoU7Prat5MbHE1","parent":null},"payment_method_options":{"card":{"installments":null,"mandate_options":null,"network":null,"request_three_d_secure":"automatic"}},"payment_method_types":["card"],"processing":null,"receipt_email":null,"review":null,"setup_future_usage":null,"shipping":null,"source":null,"statement_descriptor":null,"statement_descriptor_suffix":null,"status":"requires_payment_method","transfer_data":null,"transfer_group":null},"ephemeralKey":{"id":"ephkey_1PtHOrAZJHGoU7PrskycQhE4","object":"ephemeral_key","associated_objects":[{"id":"cus_QkmyYDYLtlBjZv","type":"customer"}],"created":1724972709,"expires":1724976309,"livemode":false,"secret":"ek_test_YWNjdF8xUGx4d3BBWkpIR29VN1ByLHg1SjVrcXp5Vk1ZY3RCdFpnbE1IQUtHWGV1eTBLU3Y_00EfC24Brk"},"customer":"cus_QkmyYDYLtlBjZv","publishableKey":"pk_test_51Pe15fHKD95FdBqCHsvpnGg53byBPt4gmaaFBuyMFqErmwy1NOAyYxyXGnzl58XLyp1SVAd7IbKnEG5Mx8WPHlpT00rLI1Qqdd"}

Error preparing payment sheet: Invalid response structure

modern walrus
#

yeah look at the PaymentIntent

#

it's supposed to be the secret but your returned the whole object in JSON

#

fix your server-side code to only return the client_secret

willow nova
#

The logs of backend is:

PaymentIntent creado: {
id: 'pi_3PtHOrAZJHGoU7Pr1ta9Zqrd',
object: 'payment_intent',
amount: 1400,
amount_capturable: 0,
amount_details: { tip: {} },
amount_received: 0,
application: null,
application_fee_amount: null,
automatic_payment_methods: { allow_redirects: 'always', enabled: true },
canceled_at: null,
cancellation_reason: null,
capture_method: 'automatic_async',
client_secret: 'pi_3PtHOrAZJHGoU7Pr1ta9Zqrd_secret_BYPtIte5wcDhi9CRjSxH3yyOM',
confirmation_method: 'automatic',
created: 1724972709,
currency: 'usd',
customer: 'cus_QkmyYDYLtlBjZv',
description: null,
invoice: null,
last_payment_error: null,
latest_charge: null,
livemode: false,
metadata: {},
next_action: null,
on_behalf_of: null,
payment_method: null,
payment_method_configuration_details: { id: 'pmc_1Pn3zOAZJHGoU7Prat5MbHE1', parent: null },
payment_method_options: {
card: {
installments: null,
mandate_options: null,
network: null,
request_three_d_secure: 'automatic'
}
},
payment_method_types: [ 'card' ],
processing: null,
receipt_email: null,
review: null,
setup_future_usage: null,
shipping: null,
source: null,
statement_descriptor: null,
statement_descriptor_suffix: null,
status: 'requires_payment_method',
transfer_data: null,
transfer_group: null
}
EphemeralKey creado: {
id: 'ephkey_1PtHOrAZJHGoU7PrskycQhE4',
object: 'ephemeral_key',
associated_objects: [ { id: 'cus_QkmyYDYLtlBjZv', type: 'customer' } ],
created: 1724972709,
expires: 1724976309,
livemode: false,
secret: 'ek_test_YWNjdF8xUGx4d3BBWkpIR29VN1ByLHg1SjVrcXp5Vk1ZY3RCdFpnbE1IQUtHWGV1eTBLU3Y_00EfC24Brk'
}

modern walrus
#

(see what I said above)

willow nova
#

app.post('/payment-sheet-new', async (req, res) => {
// Use an existing Customer ID if this is a returning customer.
console.log('Cuerpo de payment sheet: ', req.body);
const { amount, currency, customerId } = req.body;

if (!customerId) {
res.status(400).send("Customer ID invalid")
}

const ephemeralKey = await stripe.ephemeralKeys.create(
{customer: customerId},
{apiVersion: '2024-06-20'}
);

const paymentIntent = await stripe.paymentIntents.create({
amount: Math.round(amount*100),
currency: currency,
customer: customerId,
// In the latest version of the API, specifying the automatic_payment_methods parameter
// is optional because Stripe enables its functionality by default.
automatic_payment_methods: {
enabled: true,
},
});

console.log('PaymentIntent creado:', paymentIntent);
console.log('EphemeralKey creado:', ephemeralKey);

res.json({
paymentIntent: paymentIntent,
ephemeralKey: ephemeralKey,
customer: customerId,
publishableKey: 'if i have'
});

});

Actually, This is how the endpoint is implemented.

#

Are you there?

modern walrus
#

yes

#

I told you the issue above twice sorry

#

you just dumped a ton of text and didn't notice

#

yeah look at the PaymentIntent
it's supposed to be the secret but your returned the whole object in JSON
fix your server-side code to only return the client_secret

#

Change either your server-side code to only return the PaymentIntent's client_secret or change your Swift code to parse the JSON and extract client_secret. Right now you are passing the full JSON object

willow nova
#

Sorry, only client_secret of paymentIntent's or ephemeralKey.secret too?

modern walrus
#

both

#

all values should be a string of the exact client_secret/secret/id. Not the whole JSON

willow nova
#

Okey, thank you very much sr!

modern walrus
#

of course! Let me know if that doesn't fix it!