This tutorial shows a production-friendly pattern for interactive apps:
- Your server creates a Mynth task.
- Mynth returns a task ID and a short-lived
publicAccessToken.
- Your browser polls task status and task results without ever seeing your API key.
Why this pattern exists
GET /tasks/:id/status and GET /tasks/:id/results accept a Public Access Token, but task creation does not. That lets you keep generation on the server and still build responsive browser UIs.
Step 1. Create the task on your server
import Mynth from "@mynthio/sdk";
const mynth = new Mynth({
apiKey: process.env.MYNTH_API_KEY,
});
export async function createGeneration() {
const task = await mynth.generate(
{
prompt: "A clean landing page hero illustration for a fintech startup",
model: "google/gemini-3.1-flash-image",
},
{ mode: "async" },
);
return {
taskId: task.id,
publicAccessToken: task.access.publicAccessToken,
};
}
The publicAccessToken is returned by default in async mode. You can disable it with access: { pat: { enabled: false } } if you only plan to poll from the server with your API key.
Keep task creation on the server. Return only the task ID and publicAccessToken to the browser.
Step 2. Return only safe data to the browser
Your API response should include:
Do not return your Mynth API key.
Step 3. Poll task status from the browser
async function getTaskStatus(taskId: string, publicAccessToken: string) {
const response = await fetch(`https://api.mynth.io/tasks/${taskId}/status`, {
headers: {
Authorization: `Bearer ${publicAccessToken}`,
},
});
if (!response.ok) {
throw new Error(`Status request failed: ${response.status}`);
}
return response.json() as Promise<{ status: "pending" | "completed" | "failed" }>;
}
Poll until the task reaches completed or failed.
Step 4. Fetch the images
async function getTaskResults(taskId: string, publicAccessToken: string) {
const response = await fetch(`https://api.mynth.io/tasks/${taskId}/results`, {
headers: {
Authorization: `Bearer ${publicAccessToken}`,
},
});
if (!response.ok) {
throw new Error(`Results request failed: ${response.status}`);
}
return response.json() as Promise<{
images: Array<
| { status: "succeeded"; id: string; url: string; cost: string; size?: string }
| { status: "failed"; error: string }
>;
}>;
}
Step 5. Show progress in the UI
Use these states in your interface:
pending: show a loading state
completed: fetch and render images
failed: show retry guidance
If you need richer state for internal operators, your backend can also fetch GET /tasks/:id with the original API key.
When to use webhooks instead
Polling is a strong fit for:
- interactive product flows
- browser previews
- short-lived user sessions
Webhooks are a better fit for:
- backend processing
- durable pipelines
- cross-system integrations
Read Use webhooks when the result should trigger server-side work.