const appearance = {
theme: 'night',
};
const stripe = Stripe('pk_test_51PccgFRo1v56iAOxEVEimciGkyyLOcjVE98T3rqOHLuvx28QNxI8sfvYN0zwSka8vLRIIIEdkOHorjb5OJUdwhIx00VRs64Seu');
// Set up Stripe Elements
const elements = stripe.elements({appearance: {theme: 'night'}});
const card = elements.create('card' );
card.mount('#payment-element');
document.querySelector("#payment-form").addEventListener("submit", async (event) => {
event.preventDefault();
document.getElementById('submit').disabled = true;
const name = document.querySelector("#name").value;
const email = document.querySelector("#email").value;
try {
// Create the customer by sending data to the server
const customerResponse = await fetch("http://localhost:4242/create-customer", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name, email }),
});
console.log(customerResponse);
// Ensure the response is JSON
if (!customerResponse.ok) {
throw new Error("Failed to create customer.");
}
const customerData = await customerResponse.json();
console.log("Customer created:", customerData);
// Create a token for the card details
const { token, error } = await stripe.createToken(card);
if (error) {
console.error('Error creating token:', error);
alert('Failed to tokenize card details. Please try again.');
document.getElementById('submit').disabled = false;
return;
}
// Proceed to initialize the payment process
await initializePayment(customerData.customerId, token.id);
} catch (error) {
document.querySelector("#error-message").textContent = error.message || "Failed to create customer.";
console.error("Error:", error);
document.getElementById('submit').disabled = false;
}
});
async function initializePayment(customerId, tokenId) {
try {
// Create the checkout session
const sessionResponse = await fetch("http://localhost:4242/create-checkout-session", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
customer: customerId, // Pass the customer ID to backend
token: tokenId, // Pass the tokenized card ID to backend
priceId: 'price_1PfUDSRo1v56iAOxxLORAlv9'
})
});
if (!sessionResponse.ok) {
const errorData = await sessionResponse.json();
throw new Error(errorData.message || `Failed to create checkout session.`);
}
const sessionData = await sessionResponse.json();
window.location.href = sessionData.url; // Redirect to the Stripe Checkout or success page
} catch (error) {
document.querySelector("#error-message").textContent = error.message || "Failed to process payment.";
console.error('Error:', error);
} finally {
document.getElementById('submit').disabled = false;
}
}
public class Server {
private static final Gson gson = new Gson();
public static void main(String[] args) {
port(4242);
options("/*", (request, response) -> {
String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
if (accessControlRequestHeaders != null) {
response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
}
String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
if (accessControlRequestMethod != null) {
response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
}
return "OK";
});
before((request, response) -> {
response.header("Access-Control-Allow-Origin", "*"); // Allow all origins
response.header("Access-Control-Allow-Headers", "*");
response.header("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
response.header("Access-Control-Allow-Credentials", "true");
});
// Set Stripe API keys directly in the code
Stripe.apiKey = "sk_test_yHMt2Vkexample";
// Domain URL
String domainUrl = "http://localhost:4242";
get("/config", (request, response) -> {
response.type("application/json");
Map<String, Object> responseData = new HashMap<>();
responseData.put("publishableKey", "pk_test_51PccgFRo1v56iAOxEVEimciGkyyLOcjVE98T3rqOHLuvx28QNxI8sfvYN0zwSka8vLRIIIEdkOHorjb5OJUdwhIx00VRs64Seu");
responseData.put("proPrice", "price_1PfUDSRo1v56iAOxxLORAlv9");
return gson.toJson(responseData);
});
// Fetch the Checkout Session to display the JSON result on the success page
get("/checkout-session", (request, response) -> {
response.type("application/json");
String sessionId = request.queryParams("sessionId");
Session session = Session.retrieve(sessionId);
return gson.toJson(session);
});
post("/create-customer", (request, response) -> {
response.type("application/json");
Map<String, Object> requestData = gson.fromJson(request.body(), Map.class);
String email = (String) requestData.get("email");
String name = (String) requestData.get("name");
try {
CustomerCreateParams params = CustomerCreateParams.builder()
.setEmail(email)
.setName(name)
.build();
Customer customer = Customer.create(params);
Map<String, Object> responseData = new HashMap<>();
responseData.put("customerId", customer.getId());
responseData.put("email", customer.getEmail());
responseData.put("name", customer.getName());
return gson.toJson(responseData);
} catch (StripeException e) {
response.status(400);
Map<String, Object> errorData = new HashMap<>();
errorData.put("error", e.getMessage());
return gson.toJson(errorData);
}
});
post("/create-checkout-session", (request, response) -> {
response.type("application/json");
// Parse request body as JSON
Map<String, Object> requestData = gson.fromJson(request.body(), Map.class);
// Retrieve the priceId from the JSON payload
String priceId = (String) requestData.get("priceId");
// Create session parameters
SessionCreateParams params = new SessionCreateParams.Builder()
.setSuccessUrl(domainUrl + "/success.html?session_id={CHECKOUT_SESSION_ID}")
.setCancelUrl(domainUrl + "/canceled.html")
.setMode(SessionCreateParams.Mode.SUBSCRIPTION)
.addLineItem(new SessionCreateParams.LineItem.Builder()
.setQuantity(1L)
.setPrice(priceId)
.build()
)
.build();
try {
Session session = Session.create(params);
response.status(303); // HTTP 303 See Other
response.redirect(session.getUrl());
return ""; // Returning an empty string to indicate no body content
} catch (Exception e) {
Map<String, Object> messageData = new HashMap<>();
messageData.put("message", e.getMessage());
Map<String, Object> responseData = new HashMap<>();
responseData.put("error", messageData);
response.status(400);
return gson.toJson(responseData);
}
});
post("/customer-portal", (request, response) -> {
String sessionId = request.queryParams("sessionId");
// Retrieve the Checkout Session to get the customer ID
Session checkoutSession;
try {
checkoutSession = Session.retrieve(sessionId);
} catch (Exception e) {
response.status(400);
return gson.toJson(Collections.singletonMap("error", "Failed to retrieve session: " + e.getMessage()));
}
String customer = checkoutSession.getCustomer();
// Create a Billing Portal session
com.stripe.param.billingportal.SessionCreateParams params =
new com.stripe.param.billingportal.SessionCreateParams.Builder()
.setReturnUrl(domainUrl + "/account") // Redirect to your account page after managing billing
.setCustomer(customer)
.build();
com.stripe.model.billingportal.Session portalSession;
try {
portalSession = com.stripe.model.billingportal.Session.create(params);
} catch (Exception e) {
response.status(400);
return gson.toJson(Collections.singletonMap("error", "Failed to create billing portal session: " + e.getMessage()));
}
// Redirect to the billing portal
response.redirect(portalSession.getUrl(), 303);
return "";
});
post("/webhook", (request, response) -> {
String payload = request.body();
String sigHeader = request.headers("Stripe-Signature");
String endpointSecret = "your_webhook_secret"; // Replace with your actual webhook secret
Event event;
try {
event = Webhook.constructEvent(payload, sigHeader, endpointSecret);
} catch (SignatureVerificationException e) {
response.status(400);
return gson.toJson(Collections.singletonMap("error", "Invalid signature"));
}
// Handle the event
switch (event.getType()) {
case "checkout.session.completed":
// Handle successful payment
System.out.println("Checkout Session completed: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "invoice.payment_succeeded":
// Handle successful payment for invoices
System.out.println("Invoice payment succeeded: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "invoice.payment_failed":
// Handle failed payment for invoices
System.out.println("Invoice payment failed: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "customer.subscription.created":
// Handle subscription creation
System.out.println("Subscription created: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "customer.subscription.deleted":
// Handle subscription cancellation
System.out.println("Subscription canceled: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
default:
response.status(200);
System.out.println("Unhandled event type: " + event.getType());
break;
}
return "";
});
}
}
So this error is caused when initializepayment function executes, but stripe does not accept OPTIONS request due to AWS constraint, based on my javascript is there anything I can do to prevent this from happening because I have my app running on PORT 8443. I can see the customer creation happen on stripe, but it fails to mak the payment.
Your backend code tries to immediately redirect to the Stripe Checkout URL :
response.status(303); // HTTP 303 See Other
response.redirect(session.getUrl());
But your frontend code is expecting instead to get JSON from your backend and extract a URL from that and redirect the browser itself in JS:
const sessionData = await sessionResponse.json();
window.location.href = sessionData.url; // Redirect to the Stripe Checkout or success page
Redirecting with a HTTP 3xx from a server will not work in a fetch/XHR context, which is why your frontend code correctly is doing the redirect, but you haven't changed the backend code to actually work with it(the backend code you probably copied from a Stripe guide where that code would be hit by a <form action="create-checkout-session">
, not a fetch/XHR).
To fix this you should change the backend code to return the information the frontend is expecting.
post("/create-checkout-session", (request, response) -> {
...
Session session = Session.create(params);
Map<String, String> responseData = new HashMap<>();
responseData.put("url", session.getUrl());
return gson.toJson(responseData);
...
}});
Your code has other issues out of scope like using CardElement as well as Checkout on the same page which is a bit strange.