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.

5 min readSume
All posts

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.

GET /v1/balance fields, read 2026-10-13
FieldMeaning
available_creditsWhole credits the workspace can use now
statefunded when it has credits, empty when it has none
updated_atWhen the balance last changed
expiration.next_expires_atWhen the next credits expire, or null
expiration.next_expiring_creditsCredits that expire at next_expires_at
expiration.expiring_soon_days / expiring_soon_creditsCredits 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

All Developers posts

Written by Sume