Read the receipt of one request — its model, tokens and cost in DA — and send feedback on an answer.
Every model answer carries an X-Generation-Id header, and the same handle in its body's id. Pass it to /v1/generation to read what the request cost. All three routes are free.
The openai SDK has no generations resource, so call the endpoints directly with fetch.
The id is on the answer you already have:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://opendunes.com/v1",
apiKey: process.env.OPENDUNES_API_KEY,
});
const resp = await client.chat.completions.create({
model: "anthropic/claude-sonnet-5",
messages: [{ role: "user", content: "Marhba!" }],
});
const res = await fetch(`https://opendunes.com/v1/generation?id=${encodeURIComponent(resp.id)}`, {
headers: { Authorization: `Bearer ${process.env.OPENDUNES_API_KEY}` },
});
const { data: receipt } = await res.json();
console.log(receipt.model, receipt.tokens_prompt, receipt.tokens_completion, receipt.total_cost);
// total_cost is in DAYou read only your own account's receipts; any other id is a 404.
A request that made a file — a picture, a voice, a clip — names it at /v1/generation/content:
const kept = await fetch(
`https://opendunes.com/v1/generation/content?id=${encodeURIComponent(resp.id)}`,
{ headers: { Authorization: `Bearer ${process.env.OPENDUNES_API_KEY}` } },
);
// 200 → (await kept.json()).data.output.files — ids for GET /v1/files/{id}/content
// 404 → the request kept nothing (a text answer makes no file)Feedback takes a management key:
await fetch("https://opendunes.com/v1/generation/feedback", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENDUNES_MANAGEMENT_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
generation_id: resp.id,
category: "incorrect_response",
comment: "The model repeated the same paragraph three times.",
}),
});
// → { data: { success: true } }category is one of latency, incoherence, incorrect_response, formatting, billing, api_error, other.