#elias_connect-sct

1 messages Β· Page 1 of 1 (latest)

shell marlinBOT
#

πŸ‘‹ 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/1288160822262108181

πŸ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

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.

pallid radish
#

Creation of payment intent

#
import Stripe from "stripe";

import getCurrentUser from "@/app/actions/getCurrentUser";
import getListingById from "@/app/actions/getListingById";
import prisma from "../../../libs/prismadb";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
  apiVersion: "2024-06-20",
});

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const { listingId, totalPrice } = body;

    if (!listingId || !totalPrice) {
      return NextResponse.json(
        { message: "Missing required fields" },
        { status: 400 }
      );
    }

    const currentUser = await getCurrentUser();
    const listing = await getListingById({ listingId });

    if (!currentUser) {
      return NextResponse.json(
        { message: "User not authenticated" },
        { status: 401 }
      );
    }

    if (!listing?.user) {
      throw new Error("Owner not found")
    }

    if(!listing?.user.stripeId) {
      throw new Error("Owner has no stripe account")
    }
    
    const paymentIntent = await stripe.paymentIntents.create({
      amount: totalPrice * 100,
      currency: "usd",
      metadata: {
        listingId,
        userId: currentUser.id,
      },
      transfer_data: {
        destination: listing?.user.stripeId,
      },
    });

    if (!paymentIntent.client_secret) {
      return NextResponse.json(
        { message: "Failed to create payment intent" },
        { status: 500 }
      );
    }

    return NextResponse.json({
      paymentIntentId: paymentIntent.id,
      clientSecret: paymentIntent.client_secret,
      totalPrice,
    });
  } catch (error) {
    console.error("API error", error);
    return NextResponse.json(
      { message: "Server error occurred" },
      { status: 500 }
    );
  }
}
tame oakBOT
pallid radish
#

Capturing of payment intent

#
import prisma from "@/app/libs/prismadb";
import getCurrentUser from "@/app/actions/getCurrentUser";
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
  apiVersion: "2024-06-20",
});

export async function POST(request: Request) {
  const currentUser = await getCurrentUser();

  if (!currentUser) {
    return NextResponse.error();
  }

  const body = await request.json();
  const {
    listingId,
    startDate,
    endDate,
    totalPrice,
    paymentIntentId,
    firstName,
    lastName,
    email,
    phone,
  } = body;

  if (
    !listingId ||
    !startDate ||
    !endDate ||
    !totalPrice ||
    !paymentIntentId ||
    !firstName ||
    !lastName ||
    !email ||
    !phone
  ) {
    return NextResponse.error();
  }

  try {
    const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);

    console.log("paymentIntent", paymentIntent);

    if (paymentIntent) {
      NextResponse.error();
    }

    if (
      paymentIntent.metadata.listingId !== listingId ||
      paymentIntent.metadata.userId !== currentUser.id
    ) {
      return NextResponse.error();
    }

    if (paymentIntent.status !== "succeeded") {
      return NextResponse.error();
    }

    const listingAndReservation = await prisma.listing.update({
      where: { id: listingId },
      data: {
        reservations: {
          create: {
            userId: currentUser.id,
            firstName,
            lastName,
            email,
            phone,
            startDate,
            endDate,
            totalPrice,
          },
        },
      },
    });

    return NextResponse.json(listingAndReservation);
  } catch (error) {
    console.error("Error creating reservation:", error);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 }
    );
  }
}
#

Hi, I don't mean to be annoying but made a new submission because I never got a response to the previous one before it was closed for some weird reason. πŸ™‚

brazen mauve
#

Hi again πŸ‘‹ I closed it because I thought the solution I had shared was what you were looking for based on your response. Sorry for the misunderstanding. What did I leave unanswered?

pallid radish
#

No worries! My goal is to make the money sent over to the host account when the reservation is over, meaning the user pay when reserving, and the money is on hold until the end date of the reservation. I can therefore not make a transfer to the host at the same time as the user paid for the reservation. Does this make sense?

brazen mauve
#

Yup, that's why I sent you the guide for Separate Charges and Transfers where you integration controls when the funds are transferred to the Connected Account.

pallid radish
#

Does Stripe have any system for achieving this process or would I have to experiment with webhooks or cron jobs?

pallid radish
brazen mauve
#

Achieve what part of the process? If you're asking triggering the Transfer, you have to build the logic to trigger that. We don't have insights into your system to trigger the creation of a Transfer automatically.

I don't see any mention of limits on holding the funds in the linked guide. If there are limits I'd suspect they'd be region specific and something our Support team would be more familiar with.

pallid radish
#

I think that a solution would be to create a standard checkout session where the money would be sent to our platform (not the host), before creating the transfer to the Stripe connect account (host) after the reservation is made.

#
      amount: totalPrice * 100,
      currency: "usd",
      metadata: {
        listingId,
        userId: currentUser.id,
      },
      transfer_data: {
        destination: listing?.user.stripeId,
      },
    });```
shell marlinBOT
pallid radish
#

I used to create a paymentIntent with the owner of the listing as the direct destination, but if the solution is to make the payment to us (the platform) instead, that makes sense!

#

Creating a cron job to run at the listing endDate, creating a transfer sounds like a good idea!

pulsar lava
#

elias_connect-sct

#

You can also switch the connected account(s) to manual Payouts and build a balance in their Stripe account and onluy send the funds to them after the reservation ends

pallid radish
pulsar lava
#

Can you clarify what part is confusing? I'm happy to help answer a clear question

pallid radish
#

Thank you! Would you be able to send the documentation for building a balance and sending the funds? If I understood it correctly, I can build up their balance when a user reserve their listing and send the funds using a webhook triggered when the reservation is over

#

This sounds like a simple two step process that should be easy to implement πŸ™‚