> ## Documentation Index
> Fetch the complete documentation index at: https://crossmint-wallets-docs-2-5.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Client or Server

> Understand the reasons to use client-side or server-side API keys

The headless checkout supports both server-side and client-side API keys. It's important that you select the right key for your implementation.

## When to use a server-side API key

* Testing in the [API Playground](/api-reference/headless/create-order) of the documentation
* Testing with cURL requests or running scripts from your command line
* Building applications that make API calls to your own backend, which then make the actual API call to Crossmint

<Note>The key consideration here is if the API request is coming from a server environment.</Note>

### Server Side Example Code

<Note>
  The sample code below is from a NextJS application. The `component.tsx` file is simplified to only show the relevant
  logic. The client-side component sends an API request to the application's backend, which then proxies the request
  to Crossmint. This is because the example is using a server-side API key, which requires making requests from a
  server environment.
</Note>

<CodeGroup>
  ```tsx component.tsx (client-side) theme={null}
  const createOrder = async (orderInput: any) => {
      try {
          const res = await fetch(`/orders`, {
              method: "POST",
              headers: {
                  "Content-Type": "application/json",
              },
              body: JSON.stringify(orderInput),
          });

          const order = await res.json();

          setOrder(order.order);
      } catch (e) {
          console.error(e);
          throw new Error("Failed to create order");
      }
  };
  ```

  ```typescript route.ts (server-side) theme={null}
  import { callCrossmintAPI } from "@/app/utils/crossmint";
  import { NextRequest, NextResponse } from "next/server";

  export async function POST(req: NextRequest, res: NextResponse) {
      try {
          const body = await req.json();
          console.log("create order: ", body);

          const apiResponse = await callCrossmintAPI("/orders", {
              method: "POST",
              body,
          });

          return NextResponse.json(apiResponse, { status: 200 });
      } catch (error) {
          console.log("failed to create order");
          return NextResponse.json({ message: "Error creating order" }, { status: 500 });
      }
  }
  ```

  ```typescript crossmint.ts theme={null}
  const crossmintBaseUrl = process.env.CROSSMINT_API_URL;

  const crossmintAPIHeaders = {
      accept: "application/json",
      "content-type": "application/json",
      "x-api-key": process.env.CROSSMINT_API_KEY!,
  };

  const callCrossmintAPI = async (endpoint: string, options: { method: string; body?: any; params?: any }) => {
      const url = `${crossmintBaseUrl}/${endpoint}`;
      const { body, method } = options;

      const response = await fetch(url, {
          body: body ? JSON.stringify(body) : null,
          method,
          headers: crossmintAPIHeaders,
      });
      const json = await response.json();
      return json;
  };

  export { callCrossmintAPI };
  ```
</CodeGroup>

## When to use a client-side API key

* Your application will be making API requests to Crossmint directly from a broswer

<Note>
  When you create client-side API keys you must add the authorized origins that can use the key. For example, in
  testing you'll need to indicate `http://localhost:3000` (or similar local dev URLs) as authorized origins, or the
  request will be denied.
</Note>

There is one additional step when using a client-side API key in your application with headless checkout. The first call will be to create the order. The response will include a `clientSecret` property that you must persist in state and then pass as an additional header in subsequent API requests to the [update-order](/api-reference/headless/edit-order) or [get-order](/api-reference/headless/get-order) routes.

### Client Side Example Code

<CodeGroup>
  ```tsx create-order theme={null}
  // note the end of try block where the clientSecret is saved to local state

  const createOrder = async (orderInput: any) => {
      try {
          const res = await fetch(`https://staging.crossmint.com/api/2022-06-09/orders`, {
              method: "POST",
              headers: {
                  "Content-Type": "application/json",
                  "x-api-key": process.env.NEXT_PUBLIC_CLIENT_SIDE_KEY,
              },
              body: JSON.stringify(orderInput),
          });

          const order = await res.json();

          setOrder(order.order);
          setClientSecret(order.clientSecret);
      } catch (e) {
          console.error(e);
          throw new Error("Failed to create order");
      }
  };
  ```

  ```tsx update-order theme={null}
  // note the `authorization` header, which contains previously saved clientSecret

  const updateOrder = async (orderInput: any) => {
      try {
          const res = await fetch(`https://staging.crossmint.com/api/2022-06-09/orders/${order.orderId}`, {
              method: "PATCH",
              headers: {
                  "Content-Type": "application/json",
                  "x-api-key": process.env.NEXT_PUBLIC_CLIENT_SIDE_KEY,
                  authorization: clientSecret,
              },
              body: JSON.stringify(orderInput),
          });

          const updatedOrder = await res.json();

          setOrder(updatedOrder);
      } catch (e) {
          console.error(e);
          throw new Error("Failed to update order");
      }
  };
  ```

  ```tsx get-order theme={null}
  // note the `authorization` header, which contains previously saved clientSecret

  const getOrder = async () => {
      try {
          const res = await fetch(`https://staging.crossmint.com/api/2022-06-09/orders/${order.orderId}`, {
              method: "GET",
              headers: {
                  "Content-Type": "application/json",
                  "x-api-key": process.env.NEXT_PUBLIC_CLIENT_SIDE_KEY,
                  authorization: clientSecret,
              },
          });

          const refreshedOrder = await res.json();

          setOrder(refreshedOrder);

          return refreshedOrder.lineItems[0].delivery.status;
      } catch (e) {
          console.error(e);
          throw new Error("Failed to fetch order");
      }
  };
  ```
</CodeGroup>
