Examples
Charge users for Higgsfield AI images and video
Updated Oct 25, 2026
These examples charge your users for image and video generation on Higgsfield with its @higgsfield/client SDK. Use meter() to pass on Higgsfield’s own price plus your markup for each image, or charge() for a price per second of video. You set the prices; Payfer takes them from the person’s balance and pays you what’s left after its fee.
You’ll need a connected user’s paymentUserId from the quickstart, and both SDKs on your server.
npm install payfer @higgsfield/clientimport { config, higgsfield } from "@higgsfield/client/v2";
import { Payfer } from "payfer/server";
config({
credentials: process.env.HF_CREDENTIALS, // "api-key-id:api-key-secret"
maxPollTime: 15 * 60 * 1000, // video can take minutes
});
const payfer = new Payfer({ secretKey: process.env.PAYFER_SECRET_KEY! });Charge cost plus markup for Higgsfield images
Higgsfield quotes the price of a request before you submit it, and charges only for requests that complete. Reserve that quote plus your markup, generate, and collect only when the image completes, so your users pay exactly when you do. Images finish in seconds, well inside a reservation’s 5-minute lifetime.
const SOUL = "higgsfield-ai/soul/v2/standard";
// Your price as a multiple of Higgsfield's.
const MARKUP = 1.5;
// Payfer amounts are dollar strings with up to 6 decimal places
// (whole microdollars), and at least $0.005.
const toAmount = (micros: number) =>
(Math.max(Math.ceil(micros), 5000) / 1e6).toFixed(6);
// Higgsfield's price for a request, in microdollars. The estimate
// endpoint takes the same body as the generation itself.
async function estimate(endpoint: string, input: object): Promise<number> {
const res = await fetch("https://api.higgsfield.ai/estimate/" + endpoint, {
method: "POST",
headers: {
Authorization: "Key " + process.env.HF_CREDENTIALS,
"Content-Type": "application/json",
},
body: JSON.stringify(input),
});
if (!res.ok) throw new Error("Higgsfield estimate failed: " + res.status);
const { usd } = (await res.json()) as { usd: string };
return Math.round(Number(usd) * 1e6);
}
export async function portrait(
paymentUserId: string,
prompt: string,
operationId: string,
) {
const input = { prompt };
const maxAmount = toAmount((await estimate(SOUL, input)) * MARKUP);
const reservation = { paymentUserId, maxAmount, idempotencyKey: operationId };
return payfer.meter(reservation, async () => {
const result = await higgsfield.subscribe(SOUL, {
input,
withPolling: true,
});
// Higgsfield doesn't charge for failed or moderated (nsfw) requests,
// so neither do you: throwing releases the reservation.
const url = result.images?.[0]?.url;
if (result.status !== "completed" || !url) {
throw new Error("Higgsfield request " + result.status);
}
return { amount: maxAmount, value: url };
});
}subscribe() returns failed and nsfw results instead of throwing, so always check status before charging. If the person can’t cover the reservation, meter() throws funding_required or allowance_exceeded before Higgsfield is called.
Bill Higgsfield video generation per second
A video can take longer than a reservation lasts, so charge for the clip up front and refund it if Higgsfield doesn’t deliver. This example sets a price per second of Kling 2.5 Turbo video, which comes in 5 and 10 second clips. Reusing the operation’s idempotency key on a retry returns the same payment instead of charging twice.
const KLING = "kling-video/v2.5-turbo/pro/text-to-video";
// A flat price per second of video.
const PRICE_PER_SECOND = 0.1;
export async function video(
paymentUserId: string,
prompt: string,
duration: 5 | 10,
operationId: string,
) {
// Charge first, so a user without funds never costs you a generation.
const payment = await payfer.charge({
paymentUserId,
amount: (duration * PRICE_PER_SECOND).toFixed(2),
idempotencyKey: operationId,
});
try {
const result = await higgsfield.subscribe(KLING, {
input: { prompt, duration },
withPolling: true,
});
if (result.status !== "completed" || !result.video) {
throw new Error("Higgsfield request " + result.status);
}
return result.video.url;
} catch (err) {
// No video, so give the money back.
await payfer.refund({
paymentId: payment.id,
idempotencyKey: operationId + ":refund",
});
throw err;
}
}Higgsfield keeps output files for seven days, so copy each video to your own storage before you hand out its URL.