#loren_api
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/1473737959827177715
π Have more to share? Add more details, code, screenshots, videos, etc. below.
hello! looking at this now
i see this error on your test mode request:
This PaymentIntent requires a mandate, but no existing mandate was found. Collect mandate acceptance from the customer and try again, providing acceptance data in the mandate_data parameter.
is that the error you're getting in prod too?
yes, same error
I can grab you a prod requestId too if you'd like
I can also paste our code for any of those sdk interactions, if that would be helpful
yeah i think that would be helpful, as much code as you can share, especially for confirmAcssDebitSetup()
it does look like you're providing mandate data when setting up the payment method so nothing obvious is jumping out to me
in order of the flow. This is first, we create the setup_intent like this, and return the client_secret to the front end code
the front end code (nextjs app) then calls the Stripe sdk like this
can you share in code blocks (using triple backticks) instead of screenshots so i can copy paste?
yes
return stripe.setupIntents.create({
customer: customerId,
payment_method_types: ["acss_debit"],
usage: "off_session",
...(connectedAccountId && { on_behalf_of: connectedAccountId }),
payment_method_options: {
acss_debit: {
currency: "cad",
verification_method: "automatic",
mandate_options: {
payment_schedule: "combined",
interval_description: "Payments can be initiated at a pre-defined interval or sporadically",
transaction_type: "business",
},
},
},
});
await stripe.confirmAcssDebitSetup(setupResult.setupIntent.client_secret, {
payment_method: {
billing_details: {
name: selectedStore.detail?.name || "",
email: user?.email || selectedStore.detail?.email || "",
},
},
});
ok, give me just a bit to test this, i actually don't have a test integration that uses confirmAcssDebitSetup yet so i'll need to modify an existing one
and then once the payment method is attached, the user shops on the site and goes to check out, and we create an invoice to collect the payment
const invoiceParams: Stripe.InvoiceCreateParams = {
customer: stripeCustomerId,
currency: currency?.toLowerCase() as any,
collection_method: "charge_automatically",
auto_advance: false, // Don't auto-advance, we'll pay it manually
default_payment_method: paymentMethodId, // Attach the payment method
custom_fields: [
{ name: "Pay To", value: `CrumblFoods` },
...(legalEntityName ? [{ name: "Legal Entity", value: String(legalEntityName).slice(0, 30) }] : []),
],
metadata: {},
payment_settings: {
payment_method_types: ["acss_debit"],
},
shipping_cost: {
shipping_rate_data: {
display_name: inventoryOrder.shippingMethod || "Shipping",
type: "fixed_amount",
fixed_amount: {
amount: shippingSubtotal || 0,
currency: String(currency || "usd").toLowerCase() as any,
},
},
},
...(stripeCrumblFoodsConnectedAccountId && {
on_behalf_of: stripeCrumblFoodsConnectedAccountId,
transfer_data: {
destination: stripeCrumblFoodsConnectedAccountId,
},
}),
};
const invoice = await stripeClient.invoices.create(invoiceParams);
and then we add the invoice line items, finalize it, then pay it
for (const li of lineItems) {
const lineItemParams: Stripe.InvoiceItemCreateParams = {
customer: stripeCustomerId,
currency: String(currency || "usd").toLowerCase() as any,
unit_amount: li.unitPrice,
quantity: li.quantity,
description: li.name || li.sku || "Item",
invoice: invoice.id,
} as any;
await stripeClient.invoiceItems.create(lineItemParams);
}
const finalizedInvoice = await stripeClient.invoices.finalizeInvoice(invoice.id);
const paidInvoice = await stripeClient.invoices.pay(finalizedInvoice.id, {
payment_method: paymentMethodId,
});
yeah, no worries, take your time!
I appreciate the help
req_oCZykRSD88O92S
here is a production requestId in case you need that
π I'll be taking over for solanum here, who needed to step away
sounds good, thanks!
Do you have an example / reproduction where you don't detach the payment method after failing to pay the Invoice?
I'm not sure what you mean
we aren't doing that on purpose anywhere in the code
is there something with the way we're calling the stripe.invoice sdk that is causing that to happen?
No, you're explicitly detaching Payment Methods using the node sdk: https://dashboard.stripe.com/acct_1M9sx7LwZ4EBNBvA/test/logs/req_VqAVSjSVzXI0WI
oh, that's just us messing around with trying out different solutions
after the payment fails, we've been trying to re-attach the payment method to see if different approaches will get the mandate data to work properly
I can do a test transaction and then not detach the payment method after, if that's helpful
req_gsuyQJy9RVGkz0 here is a new one in sandbox!
I've told my team to not mess with that test customer anymore, so they won't attach or detach any payment methods for the time being
Okay, I think you need to explicitly provide the id of the mandate when hitting the invoice/pay endpoint: https://docs.stripe.com/api/invoices/pay?lang=node&api-version=2025-12-15.clover#pay_invoice-mandate
ah, intereseting. Let me give that a shot
the mandate is stored on the SetupIntent
We don't have a very explicit guide for this in the docs for Invoices, but it is essentially this: https://docs.stripe.com/payments/acss-debit/set-up-payment?payment-ui=direct-api#charge-later
well that's something π
You cannot provide both a mandate id and mandate information to payment_method_options
req_5uFBnpBb1tMt9a
here is the latest sandbox requestId
what the
Okay, I think this is just broken.
I've reached out to our product team about it. If you can create a support ticket, then we can keep you updated on the fix
I can send you instructions via dm on creating a support case
Hello @quaint knoll, we have sent you a direct message, please check it at https://discord.com/channels/@me/1473760800752668866
- πThe message has instructions on how to open a direct support case with our Developer Support team, in order to help you more effectively.
we do have a support ticket going already, but we weren't making much headway there, which is why I reached out here as well. Should we try to link to that existing ticket, or create a new one?
Ah; let me find that ticket
okay, I left a note explaining the situation in the support ticket, and I'll drop a note to the person who is handling it
ok awesome, thanks for looking into it for me!
Yeah, I'm sorry about that
no worries! I'm glad we're getting the right eyes on it