#charaktarrr_error
1 messages · Page 1 of 1 (latest)
👋 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/1449071730617352343
📝 Have more to share? Add more details, code, screenshots, videos, etc. below.
We use the dotnet SDK 48.5 for Basil API
setup intent eventid: evt_1Sc6GDLqit5oPG41QhtFy5r6
invoiceID: in_1ScwN0Lqit5oPG41Mh6E3qY6
Thanks for the info and object IDs, looking in to this
Hello
Jumping into to help out here..
Can you clarify what surface you're working with here? Like are you using Checkout Sessions or Payment Element or something else?
The exact step by step instructions would help too in order to reproduce this behavior myself
we use checkout sessions here in this case. This is the code for generating the checkoutsecret:
Product product = null;
if (singleItemPriceAmount.HasValue) {
product = _dbContext.Products
.FirstOrDefault(p => p.ProductId == productId);
}
var options = new Stripe.Checkout.SessionCreateOptions {
PaymentMethodTypes = paymentMethods,
Metadata = metaData,
UiMode = "embedded",
Mode = mode.ToString(),
Customer = stripeCustomerId,
ReturnUrl = $"{globalCleverlySettings.ApplicationBaseUrl}/checkout/success" + (productId != null ? "/"+productId.ToString() : ""),
BillingAddressCollection = "required",
};
if (mode == SessionCreateMode_Enum.setup) {
options.CustomText = new SessionCustomTextOptions() {
Submit = new SessionCustomTextSubmitOptions() { Message = "Bitte hinterlege dein Zahlungsmittel, damit wir die Buchung deines Abopakets abschließen können. Wenn du einen späteren Abostart vereinbart hast, wird dein Zahlungsmittel erst zum Start deines Abos belastet, andernfalls startet dein Abo sofort und wir belasten anschließend dein Zahlungsmittel." },
};
} else {
// Use lineItems if provided, otherwise fall back to priceIds with default quantity
if (lineItems != null && lineItems.Any()) {
options.LineItems = lineItems.Select(item =>
new SessionLineItemOptions {
Price = item.PriceId,
Quantity = item.Quantity
}).ToList();
} else {
options.LineItems = priceIds.Select(priceId =>
new SessionLineItemOptions {
Price = singleItemPriceAmount.HasValue ? null : priceId,
Quantity = quantity ?? 1,
PriceData = singleItemPriceAmount.HasValue ? new SessionLineItemPriceDataOptions {
UnitAmount = singleItemPriceAmount.Value,
Currency = "eur",
Product = product!.StripeProductId,
} : null
}
).ToList();
}
if (mode == SessionCreateMode_Enum.subscription) {
var description = "";
description = $"Abostart: {subscriptionStartDate ?? DateTime.UtcNow:dd.MM.yyyy}";
description += runtimeInMonths != null ? $" - Laufzeit: {runtimeInMonths} Monate" : "";
var subscriptionMetaData = new Dictionary<string, string>{
{ "initialPeriod",runtimeInMonths?.ToString() ?? "" }
};
options.SubscriptionData = new SessionSubscriptionDataOptions() {
Metadata = subscriptionMetaData,
Description = description
};
if (subscriptionStartDate.HasValue && subscriptionStartDate < DateTime.UtcNow) {
subscriptionStartDate = DateTime.UtcNow;
}
if (subscriptionStartDate.HasValue && subscriptionStartDate.Value.Date > DateTime.UtcNow.Date) {
options.SubscriptionData.BillingCycleAnchor = subscriptionStartDate;
options.SubscriptionData.ProrationBehavior = "none";
}
}
if (options.Mode == "payment") {
options.InvoiceCreation = new SessionInvoiceCreationOptions() { Enabled = true };
}
if (couponIds?.Count > 0) {
options.Discounts = couponIds.Select(d => new SessionDiscountOptions() { Coupon = d }).ToList();
} else {
if (mode == SessionCreateMode_Enum.subscription) {
options.AllowPromotionCodes = true;
}
}
}
var service = new Stripe.Checkout.SessionService();
var session = await service.CreateAsync(options);
return session.ClientSecret;
when we setup the subscription to start later, the issue appears. When the subscription starts immediately, the address and name are being applied as we expect to the invoice and the stripe customer profile
So generally, any billing information collected via the Elements is stored on the payment method object by default
have you checked the payment method object to see if it has the billing info you've collected?
Can you share the example customer where the address and name is being set?
yes, In my initial post I wrote that the payment method includes all collected data correctly, but not the invoice generated later and also not the profile.
I did post the eventid for the setup_intent and the invoiceid in my second message. This is a sample customer where that happened cus_TZEinhURqcXkpq
setup intent eventid: evt_1Sc6GDLqit5oPG41QhtFy5r6
invoiceID: in_1ScwN0Lqit5oPG41Mh6E3qY6
Sorry i got a bit confused.
cus_TZEinhURqcXkpq is where the address was set or wasn't set?
where it wasnt set
Can you share the customer ID where it was set?
I have a few theories about why it could be happening..
-
One is that the customer ID you used had an empty address associated with it when you created the Customer. So we didn't overwrite it with the new one
-
Second theory is that the flow might be different for new customer objects created by the Checkout Session versus existing customer ID passed in to the Checkout Session
I just noticed now that the stripe profiles don't show Billing Addresses for all our customers, like this one cus_TXR85yxkZXa28d
But the name is correctly there, but this could be because we set the name via api. I would have too look into that
But why is the billing address from the payment method not being used in the invoices?
I assume you're referring to customer_address field? If so, it relies on customer.address to be filled out
https://docs.stripe.com/api/invoices/object#invoice_object-customer_address
I expected that the collected Address is being applied as Billing Address for the customer
If you look at the Customer creation request, you're passing in empty values for the address - https://dashboard.stripe.com/acct_1ISlKWLqit5oPG41/logs/req_diKnpvkypRtIxm
It is creating an underlying address object that's associated with the customer and in that case, we just don't overwrite the existing address.
Can you try creating a brand new customer first, set nothing under address field and then create a test checkout session with it?
we do that already, this is the code for creating the customer:
if (String.IsNullOrEmpty(customer.StripeId) && !string.IsNullOrEmpty(email)) {
var customerService = new Stripe.CustomerService();
var stripeCustomer = await customerService.CreateAsync(new Stripe.CustomerCreateOptions() {
Metadata = new Dictionary<string, string>() { { "AccountGroupId", customer.AccountGroupId.ToString() } },
Email = email
});
customer.StripeId = stripeCustomer.Id;
_dbContext.Customers.Update(customer);
await _dbContext.SaveChangesAsync();
}
return customer;
In the request I shared, address was being set
to empty strings
okay one thing you could try is rather than creating a Customer in advance, allow the Checkout Session to create a Customer automatically by passing customer_creation: 'always'
I believe one of my colleagues tested this and if you pass an existing customer ID, Checkout doesn't set it's address upon collection. The collected address is set on the payment method instead.
If you let Checkout Session create a new customer instead then it will set the collected address to the customer
I found a place where we create the customer with address, i have to look into that
I will try this, might take a while. Can I get back to this tomorrow here?
The thread might be closed but you can open up a new one and follow up
okay, thank you very much!