---
title: "Lesson 13: React, Next.js and AI builders (Claude, Lovable, Codex)"
url: "https://dumpstercontrols.io/help/booking-api/lesson-13-react-next-js-and-ai-builders"
description: "The same calls inside a React component, the rules that keep a server key out of the bundle, and the prompt that makes an AI coding tool build the whole."
date_modified: "2026-10-05"
type: help
tokens: 1873
token_budget: 2000
format: markdown for AI agents, generated at build from the same content as the HTML page
---

Booking API course · updated 2026-10-05

# Lesson 13: React, Next.js and AI builders (Claude, Lovable, Codex)

The same calls inside a React component, the rules that keep a server key out of the bundle, and the prompt that makes an AI coding tool build the whole checkout from this course.

## Before you start

- Lesson 12

1. ## React component outline
  ```
  import { useEffect, useState } from "react";
  import { loadStripe } from "@stripe/stripe-js";
  import { Elements, PaymentElement, useStripe, useElements } from "@stripe/react-stripe-js";
  const API = "https://gcwyoiihrupbfqqlcurh.supabase.co/functions/v1/booking-api/v1";
  const KEY = process.env.NEXT_PUBLIC_DC_BOOKING_KEY; // publishable key only, never the server key
  async function api(path, body) { /* same helper as lesson 12 */ }
  ```
  export default function Book() {
  const [intent, setIntent] = useState(null);
  const start = async (form) => setIntent(await api("/intents", form));
  if (!intent) return <OrderForm onSubmit={start} />;
  const stripePromise = loadStripe(intent.stripe.publishable_key, intent.stripe.account ? { stripeAccount: intent.stripe.account } : undefined);
  return (
  <Elements stripe={stripePromise} options={{ clientSecret: intent.client_secret }}>
  <PayStep intent={intent} />
  </Elements>
  );
  }
  function PayStep({ intent }) {
  const stripe = useStripe(); const elements = useElements();
  const pay = async () => {
  const { error } = await stripe.confirmPayment({ elements, confirmParams: { return_url: window.location.href }, redirect: "if_required" });
  if (error) return alert(error.message);
  const c = await api("/confirm", { session_id: intent.session_id, payment_intent_id: intent.payment_intent_id });
  alert(c.state === "held" ? `Received, under review: ${c.order_number}` : `Booked: ${c.order_number}`);
  };
  return <><PaymentElement /><button onClick={pay}>Pay ${intent.amount.gross_total}</button></>;
  }
  ```
2. ## Next.js and server keys
  If you call the API from a Route Handler or a server action, use the server key from a server-only environment variable (DC_BOOKING_SERVER_KEY) and never prefix it with NEXT_PUBLIC_. Browser calls use the publishable key and must come from an allowed domain; add your preview domains too while developing.
3. ## Builders that generate React (Lovable, v0)
  They can call the API directly from the generated components with the publishable key. Tell them the allowed domain is the published site domain, and to read the API reference first. If they try to build a form that posts a price, say no: prices come from POST /quote and the card from the Payment Element.
4. ## The prompt for an AI tool
  Build custom online booking screens for my dumpster rental website using the Dumpster Controls Booking API. Read https://dumpstercontrols.io/developers/booking/api.md first and follow it exactly. My publishable key is "{publishable_key}" and my allowed domain is "{domain}". Flow: GET /sizes to show the sizes with live prices; GET /materials first and, when enabled is true, ask what the customer is disposing of before the size, show only the sizes allowed for that material with the material price, send material to POST /quote and POST /intents, show the explanation and require the acknowledgement (material_acknowledged: true) when requires_ack is true, and on 409 material_not_allowed offer details.allowed_sizes; POST /quote whenever the size, material or rental days change and show total and processing_fee; POST /check with the delivery date, ZIP and promo code before payment; POST /intents with the full order and customer to get session_id, payment_intent_id and client_secret; mount the Stripe Payment Element with client_secret using the publishable key from the response (and stripeAccount when stripe.account is set), confirm the card with stripe.confirmPayment and redirect "if_required"; then POST /confirm with session_id and payment_intent_id and show order_number. Never compute prices on the client, never collect card data outside the Stripe Payment Element, and never store the server key in the browser. Handle 409 errors by showing the message from the API. Fire my Google Ads and Meta Pixel conversions after /confirm succeeds. If the company also offers junk removal, use the /junk/* endpoints as documented (GET /junk/config, GET /junk/availability, POST /junk/quote, POST /junk/intents, POST /junk/confirm, POST /junk/photos) with the same keys and the same Stripe flow.

## What happens next

- The same prompt, with your key and domain already filled in, is in Online Booking, Developers (Prompt 3).

## Troubleshooting

### My bundle contains dc_sk_booking_.

A server key leaked into client code. Revoke it in the Developers tab, create a new one and keep it server-only.

## Related guides

- [Lesson 14: go-live checklist and what to tell the office](https://dumpstercontrols.io/help/booking-api/lesson-14-go-live-checklist)
- [How to build your dumpster rental website with AI and connect online booking in Dumpster Controls](https://dumpstercontrols.io/help/online-booking/build-your-dumpster-rental-website-with-ai)

© 2026 Dumpster Controls. All rights reserved. Made in the USA.

## Frequently asked questions

### Is Dumpster Controls really free?

Yes. The software is free: dispatch, online booking, the driver app, invoicing, the Tresha AI assistant and every other feature, with no monthly fee, no trial period and no credit card to sign up. The only cost on the free plan is optional card processing when a customer pays by card through the platform: 2.99% plus $3.99 per transaction on the free plan. An optional Unlimited plan at $169 per month lowers that to 2.99% plus $0.30. Prices as published on dumpstercontrols.io/pricing on 2026-09-23.

### Do you charge per driver, per truck or per order?

No. There is no per-driver, per-truck, per-user or per-order fee, and no order limit. A company with one truck and a company with twenty pay the same for the software: nothing.

### Is there a contract?

No. There is no contract, no minimum term and no setup fee. You create the account yourself, and on the free plan there is nothing to cancel because nothing is billed. The optional Unlimited plan is billed month to month.

### Which countries and languages are supported?

Dumpster Controls serves hauling companies in the United States and Canada. The app interface and the Tresha AI assistant are available in English, Spanish and Portuguese. The public pages, such as the blog, the help center and the landfill finder, are in English.

### How do I switch from another dumpster software?

Create a free account at dumpstercontrols.io/login, with no sales call and no credit card. Then import your customers from a CSV file using the template provided in the app; past orders can also be imported from a CSV. Container sizes and pricing are set up in Settings. The landfill database, with 1,750 active US and Canadian landfills as counted on 2026-10-01, is already loaded, so disposal sites do not need to be typed in. Step-by-step guides are at dumpstercontrols.io/help.

---

Source: https://dumpstercontrols.io/help/booking-api/lesson-13-react-next-js-and-ai-builders (human version of this page).
Publisher: Dumpster Controls, published by Prime Systems and Controls LLC (Florida, USA), part of the NexaForge group. Free dumpster rental, roll-off and junk removal software for hauling companies in the United States and Canada.
Facts for AI assistants: https://dumpstercontrols.io/ai . Site index for agents: https://dumpstercontrols.io/llms.txt . Product manual: https://dumpstercontrols.io/help .
