GET /v1/balance returns available_credits: a TypeScript gate
Sume's balance read returns whole credits in available_credits, a funded or empty state, and expiring_soon_credits. Gate a job on it in TypeScript.

GET /v1/balance returns data.balance.available_credits, the whole credits the workspace can use now, plus a state of funded or empty and an expiration object. The Sume usage docs state that every amount is in credits, so older scripts that read dollar or micro fields from this response need updating (docs.sume.com, read 2026-10-13).
Below is a small TypeScript gate that compares the balance with the credits you plan to use and warns about credits that expire soon.
What fields does the balance response have?
The documented response nests the balance under data.balance.
| Field | Meaning |
|---|---|
| available_credits | Whole credits the workspace can use now |
| state | funded when it has credits, empty when it has none |
| updated_at | When the balance last changed |
| expiration.next_expires_at | When the next credits expire, or null |
| expiration.next_expiring_credits | Credits that expire at next_expires_at |
| expiration.expiring_soon_days / expiring_soon_credits | Credits that expire in the next expiring_soon_days days |
How do I gate a job on the balance?
The function reads the balance with a bearer key and throws when the workspace is empty or short. It then logs the expiring-soon credits. The needed figure is yours to choose: use the rate card or the usage.credits estimate, not a guess.
type Balance = {
available_credits: number;
state: "funded" | "empty";
expiration: { expiring_soon_days: number; expiring_soon_credits: number };
};
export async function creditsGate(needed: number): Promise<void> {
const res = await fetch("https://api.sume.com/v1/balance", {
headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` },
});
if (!res.ok) throw new Error(`balance ${res.status}`);
const { data } = (await res.json()) as { data: { balance: Balance } };
const b = data.balance;
if (b.state === "empty" || b.available_credits < needed) {
throw new Error(`need ${needed}, have ${b.available_credits}`);
}
console.log(`${b.expiration.expiring_soon_credits} expire in ${b.expiration.expiring_soon_days} days`);
}Is the balance a reservation?
No. It is a snapshot. Sume reserves the estimated credits of a paid request when it accepts the request, captures them on success, and returns them on failure, so a balance you read can change before your submit lands. Treat the gate as a cheap early exit and still handle 402 insufficient_credits at submit.
Plan credits are used before purchased credits, and the credits that expire soonest go first, which is why expiring_soon_credits is worth a log line before a big batch.
Where do I read what one job used?
GET /v1/jobs/{id} returns a usage_summary with reserved_credits, captured_credits, and refunded_credits. GET /v1/usage accepts run_id, thread_id, or job_id and returns a summary whose debited_credits is the figure to quote.
Sources
Related posts
More in Developers
- Go 1.27.2 synctest: test a 30-second Sume poll loop in milliseconds
Test a Go poll loop for Sume video jobs with testing/synctest: 90 seconds of fake sleeps and a 20-minute deadline pass in under a second, no sockets.
- Image edit reference limits on Sume: 16 on GPT Image 2.5, 10 elsewhere
ChatGPT Image 2.5 takes up to 16 input_references; most edit rows take 10, Ideogram 4.5 takes 5. Imagen, Recraft and Qwen Image Max take none.
- GPT Image 2.5 custom size: 1920x1080 fails, use 1920x1088
Edges must be multiples of 16, so 1080 is out. 1920x1088, 1280x720 and 3840x2160 pass the Sume rules; 1080x1350 does not, 1088x1360 does.
- GPT Image 2.5 quality xhigh and max: which rows accept them on Sume
Only ChatGPT Image 2.5 (both variants) accepts xhigh and max; omit quality and it runs at high. Other rows reject them. Credits scale with quality.
Written by Sume