Skip to content

Tracking Job Costs

The /v2/job and /v2/job/async endpoints accept an optional ?price=true query parameter that returns the dollar cost of each completed job alongside the result. This lets you pass through the exact cost to your end users, log spend to a database, or enforce per-token budgets without maintaining your own copy of the price sheet.

This guide shows the full pattern for a single job and a small loop that accumulates total spend across multiple generations.

A single red apple on a white background — the example image generated below

Terminal window
# Create a project directory.
mkdir prodia-tracking-costs
cd prodia-tracking-costs

Install Node (if not already installed):

Terminal window
brew install node
# Close the current terminal and open a new one so that node is available.

Create project skeleton:

Terminal window
# Requires node --version >= 18
# Initialize the project with npm.
npm init -y
# Install the prodia-js library.
npm install prodia --save
Terminal window
# Export your token so it can be used by the main code.
export PRODIA_TOKEN=your-token-here

Your token is exported to an environment variable. If you close or switch your shell you’ll need to run export PRODIA_TOKEN=your-token-here again.

Create a main file for your project:

main.js
const { createProdia } = require("prodia/v2");
const prodia = createProdia({
token: process.env.PRODIA_TOKEN // get it from environment
});

You’re now ready to make some API calls!

Add ?price=true to the request URL. The job result will include a price object with the billing product code and the dollars cost. The prodia-js SDK doesn’t expose query parameters on prodia.job(...) directly, so we use fetch to read the multipart response and pull out both the price field and the image.

main.js
const fs = require("node:fs/promises");
(async () => {
const res = await fetch(
"https://inference.prodia.com/v2/job?price=true",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PRODIA_TOKEN}`,
"Content-Type": "application/json",
Accept: "multipart/form-data",
},
body: JSON.stringify({
type: "inference.flux-fast.schnell.txt2img.v2",
config: {
prompt: "a single red apple on a white background, 4k photo",
seed: 42,
},
}),
},
);
if (!res.ok) {
console.error(`Status: ${res.status}`);
console.error(await res.text());
process.exit(1);
}
const formData = await res.formData();
const job = JSON.parse(await formData.get("job").text());
const output = formData.get("output");
console.log(`product: ${job.price.product}`);
console.log(`dollars: ${job.price.dollars}`);
await fs.writeFile(
"apple.jpg",
new Uint8Array(await output.arrayBuffer()),
);
})();
Terminal window
node main.js

You’ll see output like:

product: inference-flux-schnell-large-steps-4
dollars: 0.0025

The product is the billing line item — it’s how this job will appear on your invoice and in usage exports. The dollars value is the exact amount charged for this single call.

The dollars value is per-job, so totalling spend is just a sum. This snippet generates several thumbnails in a loop and prints the running total — useful when you’re batching for a customer and want to charge them at the end.

batch.js
const fs = require("node:fs/promises");
const prompts = [
"a single red apple on a white background, 4k photo",
"a single yellow lemon on a white background, 4k photo",
"a single green pear on a white background, 4k photo",
];
(async () => {
let total = 0;
for (const [i, prompt] of prompts.entries()) {
const res = await fetch(
"https://inference.prodia.com/v2/job?price=true",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PRODIA_TOKEN}`,
"Content-Type": "application/json",
Accept: "multipart/form-data",
},
body: JSON.stringify({
type: "inference.flux-fast.schnell.txt2img.v2",
config: { prompt, seed: 42 },
}),
},
);
if (!res.ok) {
console.error(`Job ${i} failed: ${res.status}`);
continue;
}
const formData = await res.formData();
const job = JSON.parse(await formData.get("job").text());
const output = formData.get("output");
total += job.price.dollars;
console.log(`#${i} ${job.price.product} $${job.price.dollars.toFixed(4)}`);
await fs.writeFile(
`out-${i}.jpg`,
new Uint8Array(await output.arrayBuffer()),
);
}
console.log(`---`);
console.log(`Total: $${total.toFixed(4)}`);
})();
Terminal window
node batch.js

A typical run prints something like:

#0 inference-flux-schnell-large-steps-4 $0.0025
#1 inference-flux-schnell-large-steps-4 $0.0025
#2 inference-flux-schnell-large-steps-4 $0.0025
---
Total: $0.0075
  • The price field is only present when ?price=true is set and the job completes successfully. Failed jobs do not return a price.
  • Different config values can resolve to different product codes — for example, FLUX with 4 steps versus 28 steps, or a 720p Wan video versus 1080p — so always read dollars from the response rather than hard-coding it client-side.
  • For a deeper reference on the response shape, see the Job Pricing reference.