Hello am getting this error when i try to create a subscription to my Ionic 5 angular 14, capacitor 5 project
Setup Intent: {id: 'seti_1Pej4HGozbMWFnur4OWfvqdA', object: 'setup_intent', automatic_payment_methods: {…}, cancellation_reason: null, client_secret: 'seti_1Pej4HGozbMWFnur4OWfvqdA_secret_QVkZdP11j4gFm56rj95UypBo3PHvYU8', …}
subscription.page.ts:127 Setup Intent ID: seti_1Pej4HGozbMWFnur4OWfvqdA
subscription.page.ts:128 Payment Method: pm_1Pej4lGozbMWFnurI7EVBUxj
subscription.page.ts:140 Subscribing with Payment Method ID: pm_1Pej4lGozbMWFnurI7EVBUxj
subscription.page.ts:141 Subscribing with SetupIntent ID: seti_1Pej4HGozbMWFnur4OWfvqdA
subscription.page.ts:149 Could not determine which URL to request: StripeSetupIntent instance has invalid ID:
in this component code
import { Component, AfterViewInit, ElementRef, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { UserData } from 'src/app/services/user-data/user-data';
import { loadStripe, Stripe, StripeElements, StripeElementsOptions, PaymentMethod } from '@stripe/stripe-js';
import Swal from 'sweetalert2';
@Component({
selector: 'app-subscription',
templateUrl: 'subscription.page.html',
styleUrls: ['subscription.page.scss'],
})
export class SubscriptionPage implements AfterViewInit {
@ViewChild('paymentElement') paymentElementRef: ElementRef;
stripe: Stripe;
elements: StripeElements;
clientSecret: string;
planId = 'price_1OPuphGozbMWFnudfddsfgh';
customerId: any;
isPaymentElementFilled: boolean = false;
appearance: StripeElementsOptions['appearance'] = {
theme: 'stripe',
variables: {
colorPrimary: '#0570de',
colorBackground: '#ffffff',
colorText: '#30313d',
colorDanger: '#df1b41',
fontFamily: 'Ideal Sans, system-ui, sans-serif',
spacingUnit: '2px',
borderRadius: '4px',
},
};
user: any = {};
email: string = '';
uid: string = '';
paymentMethod: string | PaymentMethod;
menuOpenCopyright: boolean = false;
modalOpen: boolean = false;
cardInputFocused: boolean = false;
constructor(public router: Router, public userData: UserData) {
this.user = this.userData.getUserData();
this.uid = this.user.uid;
this.email = this.user.email;
}
ngAfterViewInit() {
this.createCustomerAndSetupIntent();
}
createCustomerAndSetupIntent() {
this.userData.createCustomer(this.email).subscribe((customerResponse: any) => {
if (customerResponse.success) {
this.customerId = customerResponse.customer.id;
this.userData.createSetupIntent(this.customerId).subscribe((setupIntentResponse: any) => {
if (setupIntentResponse.success) {
this.clientSecret = setupIntentResponse.setupIntent.client_secret;
console.log('Client Secret:', this.clientSecret);
this.initializeStripe().then(() => {
this.createPaymentElement(this.clientSecret);
}).catch(error => {
console.error('Error initializing Stripe:', error);
});
} else {
console.error(setupIntentResponse.error);
}
});
} else {
console.error(customerResponse.error);
}
});
}
async initializeStripe() {
const stripePromise = loadStripe('pk_test_51HiSUoGozbMWFnurWW3azSXFZV47mcnH8p4MQG6HvbHuszrDPvUFYuq15TbVqZujcJNv4CSHSqkAkFm3pRk7nwod00iHfdert');
this.stripe = await stripePromise;
}
createPaymentElement(clientSecret: string) {
if (!this.stripe) {
console.error('Stripe is not initialized.');
return;
}
this.elements = this.stripe.elements({
clientSecret: clientSecret,
appearance: this.appearance,
});
const paymentElementOptions = {};
const paymentElement = this.elements.create('payment', paymentElementOptions);
paymentElement.on('change', (event) => {
this.isPaymentElementFilled = event.complete;
});
paymentElement.mount(this.paymentElementRef.nativeElement);
}
async confirmPayment() {
const result: any = await this.stripe.confirmSetup({
elements: this.elements,
confirmParams: {
return_url: window.location.href,
payment_method_data: {
billing_details: {
email: this.email,
},
},
},
redirect: 'if_required' // Disable automatic redirection
});
console.log('Setup Intent:', result.setupIntent);
if (result.error) {
console.error(result.error);
} else if (result.setupIntent) {
const setupIntent = result.setupIntent;
if (setupIntent.status === 'succeeded') {
const paymentMethod = setupIntent.payment_method;
this.paymentMethod = paymentMethod;
console.log('Setup Intent ID:', setupIntent.id); // Log setupIntent ID
console.log('Payment Method:', paymentMethod); // Log payment method
this.subscribe(paymentMethod, setupIntent.id);
} else {
console.error('Setup Intent not succeeded:', setupIntent);
}
} else {
console.error('Unexpected result structure:', result);
}
}
async subscribe(paymentMethod: string | PaymentMethod, setupIntentId: string) {
const paymentMethodId = typeof paymentMethod === 'string' ? paymentMethod : paymentMethod.id;
console.log('Subscribing with Payment Method ID:', paymentMethodId); // Log payment method ID
console.log('Subscribing with SetupIntent ID:', setupIntentId); // Log setupIntent ID
this.userData.createSubscription(this.customerId, this.planId, setupIntentId).subscribe((subscriptionResponse: any) => {
if (subscriptionResponse.success) {
console.log('Subscription successful:', subscriptionResponse.subscription);
this.showSubscriptionSuccess();
this.router.navigate(['app/tablinks/home']);
} else {
console.error(subscriptionResponse.error);
}
});
}
showSubscriptionSuccess() {
Swal.fire({
title: 'Subscription Successful',
text: 'Your subscription has been successfully created.',
icon: 'success',
confirmButtonText: 'OK'
});
}
user-data functions
createCustomer(email: string): Observable<any> {
const url = this.appData.getApiUrl() + 'createCustomer';
const data = this.jsonToURLEncoded({
api_signature: this.api_signature,
email: email,
});
return this.http.post(url, data, { headers: this.options.headers });
}
createSetupIntent(customerId: string): Observable<any> {
const url = this.appData.getApiUrl() + 'createSetupIntent';
const data = this.jsonToURLEncoded({
customerId: customerId,
});
return this.http.post(url, data, { headers: this.options.headers });
}
createSubscription(customerId: string, planId: string, setupIntentId: string): Observable<any> {
const url = this.appData.getApiUrl() + 'createSubscription';
const data = this.jsonToURLEncoded({
customerId: customerId,
planId: planId,
setupIntentId: setupIntentId
});
return this.http.post(url, data, { headers: this.options.headers });
}
php functions
function createCustomer() {
$request = SlimSlim::getInstance()->request();
$response['success'] = true;
$userEmail = $request->post('email');
try {
// Create a new Stripe customer
$customer = StripeCustomer::create([
'email' => $userEmail,
]);
$userStripeCustomerId = $customer->id;
// Update the user record in the database with the Stripe customer ID
$db = getDB();
$sql = "UPDATE users SET customer_id = :customer_id WHERE email = :email";
$stmt = $db->prepare($sql);
$stmt->bindParam(":customer_id", $userStripeCustomerId, PDO::PARAM_STR);
$stmt->bindParam(":email", $userEmail, PDO::PARAM_STR);
$stmt->execute();
$response = [
'customer' => $customer,
'success' => true,
];
} catch (StripeExceptionCardException $e) {
$response = [
'error' => $e->getMessage(),
'success' => false,
];
}
echo json_encode($response);
}
function createSetupIntent() {
$request = SlimSlim::getInstance()->request();
$response['success'] = true;
$customerId = $request->post('customerId');
try {
// Create a SetupIntent for the given customer
$setupIntent = StripeSetupIntent::create([
'customer' => $customerId,
]);
$clientSecret = $setupIntent->client_secret;
$response = [
'setupIntent' => $setupIntent,
'clientSecret' => $clientSecret,
'success' => true,
];
} catch (StripeExceptionCardException $e) {
$response = [
'error' => $e->getMessage(),
'success' => false,
];
}
echo json_encode($response);
}
function createSubscription() {
$request = SlimSlim::getInstance()->request();
$response = ['success' => true];
$customerId = $request->post('customerId');
$planId = $request->post('planId');
$setupIntentId = $request->post('setupIntentId'); // Receiving setupIntentId from frontend
// Log received setupIntentId
error_log("Received setupIntentId: " . $setupIntentId);
try {
// Retrieve the SetupIntent using the setupIntentId
$setupIntent = StripeSetupIntent::retrieve($setupIntentId);
// Log the retrieved setupIntent
error_log("Retrieved SetupIntent: " . print_r($setupIntent, true));
if ($setupIntent->status !== 'succeeded') {
throw new Exception("SetupIntent is not succeeded.");
}
$paymentMethod = $setupIntent->payment_method;
// Create a subscription for the customer with the specified plan
$subscription = StripeSubscription::create([
'customer' => $customerId,
'items' => [
[
'price' => $planId,
],
],
'default_payment_method' => $paymentMethod,
]);
$response = [
'subscription' => $subscription,
'success' => true,
];
} catch (StripeExceptionApiErrorException $e) {
// Log Stripe API errors
error_log("Stripe API error: " . $e->getMessage());
$response = [
'error' => $e->getMessage(),
'success' => false,
];
} catch (Exception $e) {
// Log general exceptions
error_log("General error: " . $e->getMessage());
$response = [
'error' => $e->getMessage(),
'success' => false,
];
}
echo json_encode($response);
}
It looks like the issue stems from how the setupIntentId and paymentMethodId are being used in the subscription creation process. The error message “Could not determine which URL to request: StripeSetupIntent instance has invalid ID” suggests that there’s a problem with the ID being passed. How do i fix that? Is a problem with the code or i have to do some implementation in Stripe dashboard?
Can you give me any help? Thanks