Easy Labs
SDKsReact

Quickstart

Go from zero to a working React integration in five minutes.

This walkthrough wires @easylabs/react into a fresh app, mounts a card element, and runs a one-shot checkout that creates a customer, tokenizes a card, and charges it — all from the browser, with the card number never touching your server.

1. Get your API keys

Open the Easy Labs dashboard and copy your publishable API key from the Developers tab.

  • Test keys start with sk_test_ and automatically point the SDK at https://sandbox-api.itseasy.co/v1/api.
  • Live keys point at https://api.itseasy.co/v1/api.

There is no separate "publishable" vs. "secret" key for the React SDK — the key you paste into EasyProvider is the one used for both API calls and Basis Theory session creation, so use a test key in development.

Store it as an environment variable. For Vite, that's VITE_EASY_API_KEY; for Next.js, NEXT_PUBLIC_EASY_API_KEY.

2. Initialize the SDK

Mount EasyProvider once at the top of your tree.

src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { EasyProvider } from "@easylabs/react";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <EasyProvider apiKey={import.meta.env.VITE_EASY_API_KEY}>
      <App />
    </EasyProvider>
  </StrictMode>,
);

EasyProvider validates the key, opens a Basis Theory session, and exposes the entire API surface through useEasy(). See EasyProvider for the full prop and hook reference.

3. Make your first call

Render a CardElement and call checkout from useEasy(). The cardElement ref is passed straight into the source — the SDK handles tokenization and charge creation in a single call.

src/App.tsx
import { CardElement, useEasy, type ICardElement } from "@easylabs/react";
import { useRef, useState } from "react";

export default function App() {
  const { checkout } = useEasy();
  const cardRef = useRef<ICardElement>(null);
  const [status, setStatus] = useState<"idle" | "loading" | "ok" | "err">("idle");
  const [orderId, setOrderId] = useState<string>();

  async function onSubmit(e: React.FormEvent) {
    e.preventDefault();
    setStatus("loading");
    try {
      const res = await checkout({
        customer_creation: true,
        customer_details: {
          first_name: "Ada",
          last_name: "Lovelace",
          email: "ada@example.com",
        },
        line_items: [{ price_id: "price_123", quantity: 1 }],
        source: {
          type: "PAYMENT_CARD",
          name: "Ada Lovelace",
          cardElement: cardRef,
        },
      });
      if (res.success) {
        setOrderId(res.data.orderId);
        setStatus("ok");
      } else {
        setStatus("err");
      }
    } catch {
      setStatus("err");
    }
  }

  return (
    <form onSubmit={onSubmit}>
      <CardElement ref={cardRef} id="card" />
      <button type="submit" disabled={status === "loading"}>
        {status === "loading" ? "Processing…" : "Pay"}
      </button>
      {status === "ok" && <p>Order {orderId} created.</p>}
      {status === "err" && <p>Payment failed.</p>}
    </form>
  );
}

Replace price_123 with a real price ID from your dashboard.

4. Handle the response

checkout returns an ApiResponse<CheckoutResult>:

  • Successres.success === true. res.data contains orderId (the new order's id), an optional transfer for one-shot payments, and subscriptions (an array of created subscription rows when the line items include recurring prices). The customer and payment-instrument records are not echoed back here — fetch them with getCustomer(...) or getCustomerPaymentInstruments(...) if you need them.
  • API errorres.success === false with a message field. Surface it to the user.
  • Tokenization or network errorcheckout throws. Wrap the call in try/catch; the example above does this.

Test cards live in the Easy Labs dashboard under Developers → Test data. Use 4111 1111 1111 1111 with any future expiry and any 3-digit CVC for an approved test charge.

What's next

  • EasyProvider — every method you can pull off useEasy().
  • Elements — split-field cards, bank accounts, and styling.
  • Embedded Checkout — skip the form-building entirely with the hosted iframe.
  • Examples — full Vite SPA and Next.js apps you can clone and run.

On this page