#flocky-flocky_api

1 messages ¡ Page 1 of 1 (latest)

quasi vortexBOT
#

👋 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/1358929953290322062

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

hexed oak
#

hello! can you explain what you mean by "without explicitly using stripe products"? do you just mean using the APIs, rather than the dashboard?

#

also can you share an example invoice ID from when you were testing the APIs?

#

it sounds like you're just struggling with getting the invoice to automatically pay, is that correct or am i misunderstanding the issue?

kindred portal
#

Yes I am strugging to get my invoice items to link to my invoice. Here is some golang code that achieves my goal using payment intents:

func (p *Provider) RegisterAndPay(stripeCusID string) (string, error) {
    price, err := plan.NewPrice(1000, "CAD")
    if err != nil {
        return "", err
    }

    piParams := &stripe.PaymentIntentParams{
        Amount:     stripe.Int64(price.Amount()),
        Currency:   stripe.String(price.Currency().String()),
        Customer:   stripe.String(stripeCusID),
        OffSession: stripe.Bool(true),
        Confirm:    stripe.Bool(true),
        PaymentMethod: stripe.String("pm_1RAmdKEyi4RBfpBazqCBKl3l"),
    }

    pi, err := paymentintent.New(piParams)
    if err != nil {
        return "", fmt.Errorf("failed to create and confirm PaymentIntent: %w", err)
    }

    return pi.ID, nil
}

Essentially, I want to achieve the same outcomes, using and invoice so that I can send the customer a receipt.

hexed oak
#

can you share the example invoice from your test? or generate a new one real quick so i can take a look at how you're creating it

kindred portal
# hexed oak hello! can you explain what you mean by "without explicitly using stripe product...

By "without explicitly using stripe products", I mean that I want to avoid doing something like this:

func (p *Provider) RegisterProduct(plan *plan.Plan) (payment.PlanReference, error) {
    productParams := &stripe.ProductParams{
        Name:        stripe.String(plan.Name()),
        Description: stripe.String(plan.Description()),
        Active:      stripe.Bool(plan.IsActive()),
        Metadata:    createPlanMetaData(plan),
    }

    prod, err := stripeproduct.New(productParams)
    if err != nil {
        return payment.PlanReference{}, err
    }

    priceParams := &stripe.PriceParams{
        Product:    stripe.String(prod.ID),
        Currency:   stripe.String(plan.Price().Currency().String()),
        UnitAmount: stripe.Int64(plan.Price().Amount()),
        Active:     stripe.Bool(plan.IsActive()),
        Recurring: &stripe.PriceRecurringParams{
            Interval:      stripe.String(string(mapPlanBillingInterval(plan.BillingInterval()))),
            IntervalCount: stripe.Int64(1),
        },
        Metadata: createPlanMetaData(plan),
    }

    pr, err := stripeprice.New(priceParams)
    if err != nil {
        return payment.PlanReference{}, err
    }

    return payment.PlanReference{
        ProductID: prod.ID,
        PriceID:   pr.ID,
    }, nil
}
hexed oak
#

it's possible that you still need to call finalize and / or pay on the invoice

kindred portal
#

Ok, I had a test using invoice, but I removed it. I will quickly revert the change and run it and provide some screenshots

hexed oak
#

gotcha, you want to avoid creating a Product in stripe

#

i vaguely remember this being possible, but let me poke around in the docs before i get your hopes up

kindred portal
#

I think that this is possible because Anthropic uses Stripe and can do this

hexed oak
#

have you already looked into that feature? it might work for you based on what you're describing

#

FYI it looks like you just posted your test secret key - even though this is a test mode key i would strongly recommend rolling your secret key now

hearty salmon
hexed oak
#

i just deleted the comment so you might need to repost it

kindred portal
#

Yes, I reset my test key on Stripe dashboard

#
func (p *Provider) RegisterAndPay(stripeCusID string) (string, error) {
    price, err := plan.NewPrice(5000, "CAD")
    if err != nil {
        return "", err
    }

    // Invoice Item
    invoiceItemParams := &stripe.InvoiceItemParams{
        Customer:    stripe.String(stripeCusID),
        Amount:      stripe.Int64(price.Amount()),
        Currency:    stripe.String(price.Currency().String()),
        Description: stripe.String("Charge for your purchase"),
    }

    if _, err := invoiceitem.New(invoiceItemParams); err != nil {
        return "", fmt.Errorf("failed to create invoice item: %w", err)
    }

    // Invoice
    invoiceParams := &stripe.InvoiceParams{
        Customer:         stripe.String(stripeCusID),
        AutoAdvance:      stripe.Bool(true),
        CollectionMethod: stripe.String("charge_automatically"),
    }

    inv, err := invoice.New(invoiceParams)
    if err != nil {
        return "", fmt.Errorf("failed to create invoice: %w", err)
    }

    finalizedInv, err := invoice.FinalizeInvoice(inv.ID, nil)
    if err != nil {
        return "", fmt.Errorf("failed to finalize invoice: %w", err)
    }

    paidInv, err := invoice.Pay(finalizedInv.ID, nil)
    if err != nil {
        return "", fmt.Errorf("failed to pay invoice: %w", err)
    }

    return paidInv.ID, nil
}


func TestChargeCustomerWithInvoice(t *testing.T) {
    provider := stripe.NewProvider("sk_test_xxx")
    provider.RegisterAndPay("cus_S5ZWU2YDcMxbk6")
}
#

This causes me to get an error:
Request error from Stripe (status 400): {"status":400,"message":"Invoice is already paid","request_id":"req_miLp1BX4hPd6jA","request_log_url":"https://dashboard.stripe.com/test/logs/req_miLp1BX4hPd6jA?t=1744065900","type":"invalid_request_error"}

#

And this is how the stripe dashboard reflects my request:

#

The resources that I have read say that the invoice and invoice items are tied to the customer. However, it seems like I need to link the items to the invoices themselves.

#

I believe that I get the "invoice already paid" because stripe automatically updates the status invoices of $0 to "paid"

hexed oak
#

ok wait, i was being dense - i forget there's the invoice_item amount property.

and yes, those are being created with $0. what you probably need to do is create the invoice, then create an invoice_item with amount set to the amount you want to charge and invoice populated with your invoice id

#

also for the record an example invoice ID would still be far more helpful than code or screenshots - this lets me see exactly what you're doing using our backend tools

kindred portal
kindred portal
#

The most recent invoice in my screen shot has ID in_1RBOPXEyi4RBfpBahDlV3JB9

#

The $50 invoice item has ID ii_1RBOPXEyi4RBfpBafUPTpZp4

kindred portal
# hexed oak ok wait, i was being dense - i forget there's the invoice_item `amount` property...

I see what you mean. Checking the stripe doc, it tells that an invoice item has the param:

invoice: string

The ID of an existing invoice to add this invoice item to. When left blank, the invoice item will be added to the next upcoming scheduled invoice. This is useful when adding invoice items in response to an invoice.created webhook. You can only add invoice items to draft invoices and there is a maximum of 250 items per invoice.

#

However, I assumed that this clause

#

"the invoice item will be added to the next upcoming scheduled invoice."

Would link the pending items to the invoice I created. I will retry by creating the invoice first.

#

My friend, thank you very much! This detail made all the difference.

hexed oak
#

happy to help!

kindred portal
#

I have a follow up question if you don't mind?

#

My customer should always authenticate using 3D Secure. Is it possible have the user save a payment method, pre-authorized with 3DS? My goal is to avoid the customer from performing charge-backs on these kinds of payments.

hexed oak
#

i know how to do that with a PaymentIntent, let me double check how you do it with invoices...

kindred portal
#

Thank you for this resource, I will use it to test my use cases.

hexed oak
#

any will tell us to do a 3DS check of some kind with a preference for frictionless, and challenge tells us to prefer the challenge flow. note that these will still only trigger on cards where 3DS is supported

kindred portal
#

Ok, I see that the bank will assess risk level and attempt a frictionless flow, otherwise it will initiate a challenge flow. However I notice that you mention the 3DS check will only trigger for cards that support 3DS. This brings me a followup: is there a way to block cards that do not support 3DS?

#

Additionally, if the card does not support 3DS secure, can Stripe block them for transactions over specific amount?

hexed oak
#

my team doesn't work with radar very much, but that's the best tool for creating custom fraud prevention tools like you're thinking about

kindred portal
#

Ah, this is perfect! Thank you very much for you time, our conversation has helped me a lot.