#zeke_ios-paymentsheet

1 messages · Page 1 of 1 (latest)

bronze havenBOT
reef hawkBOT
#

Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.

bronze havenBOT
#

👋 Welcome to your new thread!

⏲️ We'll be here soon! We typically respond in a few minutes, but in some cases we might need a bit more time (e.g., server's busy, you've got a complex question, etc.).

⏱️ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can 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/1260352757211201648

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

sand bear
#

import { Button } from "@/components/ui/button";

export default function CheckoutScreen() {
const { initPaymentSheet, presentPaymentSheet } = useStripe();
const [loading, setLoading] = useState(false);

const fetchPaymentSheetParams = async () => {
  const response = await fetch(`${API_URL}/payment-sheet`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
  });
  const { paymentIntent, ephemeralKey, customer} = await response.json();
#

return {
paymentIntent,
ephemeralKey,
customer,
};
};

const initializePaymentSheet = async () => {
  const {
    paymentIntent,
    ephemeralKey,
    customer,
    publishableKey,
  } = await fetchPaymentSheetParams();

  const { error } = await initPaymentSheet({
    merchantDisplayName: "Example, Inc.",
    customerId: customer,
    customerEphemeralKeySecret: ephemeralKey,
    paymentIntentClientSecret: paymentIntent,
    // Set `allowsDelayedPaymentMethods` to true if your business can handle payment
    //methods that complete payment after a delay, like SEPA Debit and Sofort.
    allowsDelayedPaymentMethods: true,
    defaultBillingDetails: {
      name: 'Jane Doe',
    }
  });
  if (!error) {
    setLoading(true);
  }
};

const openPaymentSheet = async () => {
  // see below
  const openPaymentSheet = async () => {
    const { error } = await presentPaymentSheet();

    if (error) {
      Alert.alert(`Error code: ${error.code}`, error.message);
    } else {
      Alert.alert('Success', 'Your order is confirmed!');
    }
  };

  return (
    <Screen>
      <Button
        variant="primary"
        disabled={!loading}
        title="Checkout"
        onPress={openPaymentSheet}
      />
    </Screen>
  )
};

useEffect(() => {
  initializePaymentSheet();
}, []);

return (
  <Screen>
    <Button
      variant="primary"
      disabled={!loading}
      title="Checkout"
      onPress={openPaymentSheet}
    />
  </Screen>
);

}

}

#

function useStripe(): { initPaymentSheet: any; presentPaymentSheet: any; } {
throw new Error("Function not implemented.");
}

function useState(arg0: boolean): [any, any] {
throw new Error("Function not implemented.");
}

function useEffect(arg0: () => void, arg1: never[]) {
throw new Error("Function not implemented.");

#

Im getting this error for {API_URL}/payment-sheet

Cannot find name 'API_URL'(2304)

austere field
#

Hi there

#

Have you logged the value of ${API_URL} ?

sand bear
#

Hi!

#

do you mean in stripe or in my env! im guesing you mean env?

austere field
#

Yep, your env variable

sand bear
#

do i need to create another one with stripe or can I use one of pk_ sk_?

austere field
#

You can also try to hardcode that value to see if you're able to get past that error

#

Hold on a second. I don't think your API keys go on this line:
Im getting this error for {API_URL}/payment-sheet

What is ${API_URL} at the moment?

sand bear
#

Nothing thats why there is an error🤔 I pulled this code from the guide I offered above! I was wondering how to put it in my env is it just my sk code and or pk code

#

heres what the surrounding code looks like

export default function CheckoutScreen() {
const { initPaymentSheet, presentPaymentSheet } = useStripe();
const [loading, setLoading] = useState(false);

const fetchPaymentSheetParams = async () => {
  const response = await fetch(`${API_URL}/payment-sheet`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
  });
  const { paymentIntent, ephemeralKey, customer} = await response.json();

  return {
    paymentIntent,
    ephemeralKey,
    customer,
  };
};
#

Or do I need to make another restricted key?!

austere field
#

Got it. No, no keys go in that section. I believe this is just a placeholder in our docs, give me a few minutes

sand bear
#

All good take your time!

#

I also may have thought it was just asking me to replace it with my NEXT_PUBLIC_SERVER_URL

#

but I belive that was not the case

austere field
#

Okay, yep, this is just a placeholder. Further up in your code you can define API_URL=http://[insert your local test server address here] or you can hard code that line to const response = await fetch(`http://[insert your local test server address here]/payment-sheet`, {

sand bear
#

Ok ill go test it Thanks!

bronze havenBOT
agile stag
#

zeke_ios-paymentsheet

sand bear
#

@agile stag could you explain a little more one what roadrunner was saying?

agile stag
#

not really sorry, I skimmed the thread but didn't really follow what you were asking or what was blocking you

#

Like right now your client-side code in your mobile app has to make a call to your server and as the developer you control both sides (the mobile app and the server) and you need to configure the code to hit the right URL for your server

sand bear
#

@agile stag I need some help with somethin!

#

I get an ERR 400 on {{CONNECTED_ACCOUNT_ID}}

#

here the REQ

req_u6zdLpJbX7EMGi

agile stag
#

this is just a placeholder, you're supposed to put a real account id

sand bear
#

can I just use my own?

agile stag
#

not really no. You are supposed to pass the id of a connected account, assuming you are a Connect platform. If you're not then you're reading the wrong docs

sand bear
#

No im testing!

agile stag
#

then you need to make sure you have a real connected account in Test mode and pass that id.

sand bear
#

I just did how does it work when Im not on test mode and need to pass multible users?

agile stag
#

I have no idea what that means I'm sorry

sand bear
#

Ok another question for you @agile stag So I got it to work now were do I see the application fee in my dashboard?

#

req_SVpFDH9l7640Vq

agile stag
sand bear
#

Hmmm

#

No results found
There aren't any results for that query.

agile stag
#

query of what? Please try to be crisp and provide actionable details, right now it looks more like thinking out loud 😦

sand bear
#

O I just copied and pasted that msg

#

Thats what came up when I searched for fees in the dashboard sorry!

agile stag
#

The example request you shared is associated with a Checkout Session creating in your platform without anything related to Connect
So there's no ApplicationFee that would be taken.

sand bear
#

Interesting when I talked with some of the other helpers earlier they said to read this (zeke_best-practices) for connect so thats what I did

#

If you go to that thread you can see!

agile stag
#

Hard to say, you have many threads spanning hours unfortunately but I think you got many things likely mixed up

#

What exact end to end documentation page are you following? What in your code makes you think you are using Stripe Connect and taking an ApplicationFee?

sand bear
#

Sorry I dont mean to spam. I am just trying to accomplish something that is very important to me.

#

The file I am following is

bronze havenBOT
agile stag
#

okay so you aren't doing that. Or you have a bug in your code where you did not pass the id of a connected account. You also never passed parameters to configure an ApplicationFee

#

Also I'm... super confused. The example request you shared created a Checkout Session which has nothing to do with the doc you shared right? ReactNative doesn't support Checkout at all

sand bear
#

im as confused as you are man😂

#

I think what is happening is I have two create checkout pages

#

and my checkout is still connected to the old one

#

not the new one

#

I just made of the doc I sent you

#

if that makes sense.

agile stag
#

possibly! I highly recommend taking a step back, carefully reading the doc and your codem, adding clear logs around every call you make client-side and server-side to understand what you are doing
I get this matters a lot to you but you are rushing through so many things and I can see you don't really grasp a lot of those concepts yet

#

Like if you can use Checkout, just do that. It's fine to show Checkout in a webview/browser on mobile, you don't need an entire ReactNative integration for this.

#

I have to run but @narrow holly can help if you have follow up questions but after having taking some time to read your own code and the docs first

sand bear
#

Ok. If you could just help me figure out how to take 10% from every product thats sold on my marketplace ill leave you guys alone for a few days😂

#

Bye!

#

Thats whats started all of this

narrow holly
#

👋 here in case you need more help!

sand bear
#

Yes I do!

#

So ive been stuck on this problem were I cant take 10% away from every product sold on my marketplace and Ive read every file to the point I think Im getting them mixed up. is it ok if I show you my code?

#

give me one second

#

Here is my Payment-router.ts:

#

import { TRPCError } from "@trpc/server";
import { getPayloadClient } from "../get-payload";
import { stripe } from "../lib/stripe";
import type Stripe from "stripe";
import { z } from "zod";
import { privateProcedure, router } from "./trpc";

// Define the Product type
type Product = {
id: string;
priceId: string | null | undefined;
// other properties...
};

export const paymentRouter = router({
createSession: privateProcedure
.input(z.object({ productIds: z.array(z.string()) }))
.mutation(async ({ ctx, input }) => {
const { user } = ctx;
const { productIds } = input;

  if (productIds.length === 0) {
    throw new TRPCError({ code: "BAD_REQUEST" });
  }

  const payload = await getPayloadClient();

  try {
    const { docs: products } = await payload.find({
      collection: "products",
      where: {
        id: {
          in: productIds,
        },
      },
    });

    // Cast products to the Product type
    const typedProducts: Product[] = products as Product[];
#

// Filter products that have priceId defined
const filteredProducts = typedProducts.filter((prod: Product) =>
Boolean(prod.priceId)
);

    const order = await payload.create({
      collection: "orders",
      data: {
        _isPaid: false,
        products: filteredProducts.map((prod: Product) => prod.id), // Map to array of string IDs
        user: user.id,
      },
    });

    const line_items: Stripe.Checkout.SessionCreateParams.LineItem[] = [];

    filteredProducts.forEach((product: Product) => {
      line_items.push({
        price: product.priceId!,
        quantity: 1,
      });
    });

    line_items.push({
      price: "price_1PVJAM05fNcBdPQgDEu0sfqT",
      quantity: 1,
      adjustable_quantity: {
        enabled: false,
      },
    });

    const stripeSession = await stripe.checkout.sessions.create({
      success_url: `${process.env.NEXT_PUBLIC_SERVER_URL}/thank-you?orderId=${order.id}`,
      cancel_url: `${process.env.NEXT_PUBLIC_SERVER_URL}/cart`,
      payment_method_types: ["card"],
      mode: "payment",
      metadata: {
        userId: user.id,
        orderId: order.id,
      },
      line_items,
    });

    console.log("Stripe session created successfully:", stripeSession);

    return { url: stripeSession.url };
  } catch (err) {
    console.error("Error creating Stripe session:", err);
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Failed to create Stripe session.",
    });
  }
}),
#

pollOrderStatus: privateProcedure
.input(z.object({ orderId: z.string() }))
.query(async ({ input }) => {
const { orderId } = input;

  const payload = await getPayloadClient();

  try {
    const { docs: orders } = await payload.find({
      collection: "orders",
      where: {
        id: {
          equals: orderId,
        },
      },
    });

    if (!orders.length) {
      throw new TRPCError({ code: "NOT_FOUND" });
    }

    const [order] = orders;

    return { isPaid: order._isPaid };
  } catch (err) {
    console.error("Error polling order status:", err);
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Failed to poll order status.",
    });
  }
}),

});

#

I think that the application fee should go right here under the line_items:

const stripeSession = await stripe.checkout.sessions.create({
success_url: ${process.env.NEXT_PUBLIC_SERVER_URL}/thank-you?orderId=${order.id},
cancel_url: ${process.env.NEXT_PUBLIC_SERVER_URL}/cart,
payment_method_types: ["card"],
mode: "payment",
metadata: {
userId: user.id,
orderId: order.id,
},
line_items,
});

#

I did not mean to post all the code sorry😂

narrow holly
sand bear
#

No direct

narrow holly
#

okay, if that's the case, then when you create the Checkout Session, you should include a StripeAccount header : https://docs.stripe.com/connect/authentication#stripe-account-header. To be clear, Direct Charges mean creating the payment on the connected account, so you should start off with making sure that the Checkout Session is being successfully created on the connected account first. This also means that the Product and Prices used to create the Checkout Session need to also exist on the connected account

Learn how to add the right information to your API calls so you can make calls for your connected accounts.