TurboJet
API

Use API in frontend

Typed Hono client, handle(), TanStack Query, and storefront checkout exceptions.

Marketing talks to the product API through a typed Hono client plus TanStack Query. There is no serverApi() helper and no oRPC client.

Client setup

apps/marketing/src/lib/api.ts
import { createApiClient, handle } from "@repo/api/client";
import { clientEnv } from "@repo/env/client";

export const api = createApiClient(
	`${clientEnv.NEXT_PUBLIC_MARKETING_URL}/api`,
);
export { handle };

createApiClient wraps hc<AppRouter> with credentials: "include" so session cookies are sent on same-site / CORS-credentialed requests.

handle() awaits the response, parses JSON, and throws Error with the API message when !res.ok.

Client component + TanStack Query

Wrap typed calls in mutations (or queries) under apps/marketing/src/mutations/:

apps/marketing/src/mutations/use-create-feedback.ts
"use client";

import { useMutation } from "@tanstack/react-query";
import { api, handle } from "@/lib/api";
import type { CreateFeedbackData } from "@repo/validations/feedback";

export const useCreateFeedback = () => {
	return useMutation({
		mutationFn: (data: CreateFeedbackData) =>
			handle<{
				success: true;
				feedback: { id: string; type: string; createdAt: string };
			}>(api.feedback.$post({ json: data })),
	});
};

Call sites use the hook from client components. Keep product mutations on this path — do not use the Better Auth client for them, and do not add "use server" actions for product features.

Server Components / RSC

There is no serverApi(). For RSC, prefer not calling the product API unless you need it; today marketing product mutations are client-side. If you must call from the server, use a same-origin fetch to /api/… (or call a service function directly from a trusted server context) — do not invent a parallel typed helper.

Storefront checkout exception

Mayar storefront checkout uses a dedicated Next route, not the Hono billing module:

await fetch("/api/checkout", {
	method: "POST",
	headers: { "Content-Type": "application/json" },
	body: JSON.stringify({ plan }),
});

See apps/marketing/src/app/api/checkout/route.ts and use-create-checkout.ts.

On this page