TanStack Start
Receive signed Mynth webhooks in a TanStack Start server route, generate from a server function, and use the TanStack AI image adapter.
@mynthio/sdk/tanstack-start exports mynthWebhookHandler for a Start server
route. Generation from a server function uses the normal SDK. If the app
already uses TanStack AI's generateImage(), the separate
@mynthio/tanstack-ai-adapter package plugs Mynth into it.
npm install @mynthio/sdkPut MYNTH_WEBHOOK_SECRET, the whsec_ secret from registering the endpoint,
in the server environment.
// src/routes/api/mynth-webhook.ts
import { createFileRoute } from "@tanstack/react-router";
import { mynthWebhookHandler } from "@mynthio/sdk/tanstack-start";
export const Route = createFileRoute("/api/mynth-webhook")({
server: {
handlers: {
POST: mynthWebhookHandler({
imageTaskCompleted: async (result, { request }) => {
console.log(result.taskId, result.images, request.url);
},
imageTaskFailed: async (result) => {
console.error(result.taskId, result.errors);
},
}),
},
},
});The handler verifies the Standard Webhooks webhook-signature against
webhook-id, webhook-timestamp and the raw body, and requires the body's
id to be the webhook-id. A missing or wrong signature, or a timestamp more
than five minutes off, answers 400. An event with no handler, or one it does
not know, answers 200. It reads the secret on each request, from
MYNTH_WEBHOOK_SECRET or from { webhookSecret } as the second argument, and
throws if neither is set.
It reads a clone of the request, so the route's request stays unread. Each
callback receives a mapped result or task failure and the route context: request, params, and
middleware context, plus the verified event. event.id is the
webhook-id, the same on every retry, so store it to skip events you have
already handled. The handler names are the same as in every SDK helper. See
the table on webhooks.
Unsigned per-request webhook.custom deliveries are rejected unless you pass
{ unsigned: { verify } }. See
per-request webhooks.
Keep MYNTH_API_KEY on the server and call the SDK from a server function:
import Mynth from "@mynthio/sdk";
const mynth = new Mynth();
const pending = await mynth.image.generateAsync({
model: "black-forest-labs/flux.2-pro",
prompt: "A lighthouse at dusk, film grain",
generate_public_access_token: true,
});
return { taskId: pending.id, token: pending.access.publicAccessToken };generate() waits for the task. generateAsync() returns the id right away,
plus a browser token when the request sets generate_public_access_token,
for when the caller cannot wait.
Tasks and polling covers both.
@mynthio/tanstack-ai-adapter is for apps that already call generateImage()
from @tanstack/ai. It calls the Mynth API itself, so it needs no other
package: only @tanstack/ai 0.61.0 or newer as a peer. It does not verify
webhooks. The route above still does that.
npm install @mynthio/tanstack-ai-adapter @tanstack/aiimport { generateImage } from "@tanstack/ai";
import { mynthImage } from "@mynthio/tanstack-ai-adapter";
const result = await generateImage({
adapter: mynthImage("black-forest-labs/flux.2-pro"),
prompt: "A lighthouse at dusk, film grain",
});
console.log(result.images[0]?.url);mynthImage(model, config?) binds one model. The key comes from
MYNTH_API_KEY or config.apiKey.createMynthImage({ apiKey, baseURL, defaultHeaders, destination }) returns a
function that takes a model, for several adapters sharing one config.inputs on models listed in
MYNTH_IMAGE_INPUT_MODELS. Other Mynth fields go in modelOptions.MYNTH_IMAGE_MODELS is the id list built into the package version, and it
includes auto. Pass an explicit id. The live list is
GET https://api.mynth.io/models.MynthError subclasses with a code that TanStack AI reports on
RUN_ERROR: the API's own code (such as insufficient_balance) for
MynthAPIError, or MYNTH_TASK_FAILED, MYNTH_NO_IMAGES and
MYNTH_TASK_TIMEOUT.The adapter creates the task, polls it until it settles, and returns the finished images. tanstack-start-ai-mynth-adapter is a complete Start app that streams the TanStack call.