Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Jason-AML/MonzaSport-Nextjs/llms.txt

Use this file to discover all available pages before exploring further.

Purchasing a vehicle on Monza Motors is handled entirely through Stripe’s hosted Checkout page. When an authenticated user clicks “Buy Now” on a vehicle detail page, the client sends a request to the Next.js API route at POST /api/checkout, which creates a Stripe Checkout session and returns the session URL. The browser then redirects the user to Stripe’s secure, PCI-compliant payment page. After the transaction the user is returned to either /success (payment completed) or /cancel (payment abandoned).

Purchase Flow

1

User clicks Buy Now

On the /collection/[carId] detail page, the user clicks the “Buy Now” button inside the sticky pricing card. This calls handleStripe(vehicle) with the current vehicle object.
2

POST to /api/checkout

handleStripe sends a POST request to /api/checkout with the vehicle’s id in the JSON body:
{ "id": "vehicle-uuid" }
3

Auth check — 401 redirects to /error

The API route calls getUser() first. If the user is not signed in, it returns HTTP 401. The client checks for this status code and calls router.push('/error') instead of proceeding to Stripe.
4

Redirect to Stripe Checkout

For an authenticated request, the API route creates a Stripe session and returns it as JSON. The client reads session.url and sets window.location.href to navigate the browser to Stripe’s hosted payment page.
5

Post-payment redirect

After the user completes or abandons the payment, Stripe redirects back to the configured return URLs: /success for a completed payment, or /cancel if the user exits without paying.

Client-side Trigger

The handleStripe function lives in src/app/collection/[carId]/Detail.jsx. It uses the native fetch API and the Next.js useRouter hook for navigation.
const handleStripe = async (vehicle) => {
  const response = await fetch('/api/checkout', {
    method: 'POST',
    body: JSON.stringify({ id: vehicle.id }),
    headers: { 'Content-Type': 'application/json' },
  });
  if (response.status === 401) {
    router.push('/error');
    return;
  }
  const session = await response.json();
  window.location.href = session.url;
};
window.location.href is used for the final Stripe redirect (rather than router.push) because the destination is an external Stripe domain — Next.js client-side routing only handles same-origin navigation.

Stripe Session Configuration

The API route at src/app/api/checkout/route.js builds the Stripe session with the following parameters:
ParameterValue
payment_method_types['card']
currencyusd
mode'payment' (one-time charge)
metadata.vehicleIdThe vehicle’s UUID from the vehiculos table
metadata.userIdThe authenticated user’s Supabase UUID
line_items[0].price_data.product_data.namevehicle.nombre_vehiculo
line_items[0].price_data.unit_amountvehicle.precio * 100
line_items[0].quantity1
The vehicle data used to populate the session is fetched server-side via getCollectionById(id), which also benefits from React’s cache() deduplication if the same ID was already loaded during the render.

Redirect URLs

After the payment flow, Stripe redirects the user back to the application using the URLs configured on the session:
  • Success{baseUrl}/success when payment is completed.
  • Cancel{baseUrl}/cancel when the user abandons Stripe Checkout.
The baseUrl is resolved at runtime from environment variables:
const baseUrl =
  process.env.NODE_ENV === "production"
    ? `https://${process.env.VERCEL_URL}`
    : process.env.NEXT_PUBLIC_BASE_URL;
In production, Vercel automatically populates VERCEL_URL with the deployment’s canonical hostname. For local development, set NEXT_PUBLIC_BASE_URL=http://localhost:3000 in your .env.local file.
Only authenticated users can initiate a checkout. Unauthenticated POST requests to /api/checkout are rejected with HTTP 401 Unauthorized before any Stripe API call is made. Users who hit this endpoint without a valid session are redirected to /error by the client.
Vehicle prices in the vehiculos table are stored as integers in USD (e.g., 250000 represents 250,000).TheunitamountpassedtoStripeisvehicle.precio100becauseStripeexpectsamountsinthesmallestcurrencyunit(cents).Avehiclepricedat250000inthedatabasebecomes25000000cents250,000). The `unit_amount` passed to Stripe is `vehicle.precio * 100` because Stripe expects amounts in the **smallest currency unit** (cents). A vehicle priced at `250000` in the database becomes `25000000` cents — 250,000.00 — on the Stripe session.

Build docs developers (and LLMs) love