Daily spend cap in Python from a monthly Sume budget

Turn a $300 monthly budget into a $10 daily cap and enforce it with a short Python check against GET /v1/balance. Daily-cap table for $100 to $1,000.

5 min readSume
All posts

A $300 monthly budget is a $10.00 daily cap in a 30-day month and $9.68 in a 31-day month, which is 20 five-second H3 Max clips at $0.50 a day. You can enforce it from outside Sume by snapshotting available_amount_usd_micros from GET /v1/balance at the start of each day and refusing to submit once the day's drop reaches the cap.

The script below is a gate, not a limit. It exits with status 1 when today's cap is reached, so your scheduler or queue worker can stop submitting. It cannot cancel jobs already in flight.

What daily cap does each monthly budget give?

Divide by the days in the month, not by 30, if the budget must hold in October (31 days). The clip column prices the cap in five-second H3 Max clips at 768p, $0.50 each, the catalog estimate for Sume Auto on the Sume API pricing page.

Daily caps from a monthly budget, computed (read 2026-10-03)
Monthly budgetDaily cap, 30 daysDaily cap, 31 days5 s H3 Max clips per day at the 30-day cap
$100$3.33$3.236
$300$10.00$9.6820
$500$16.67$16.1333
$1,000$33.33$32.2666

How does the balance-delta gate work?

The Usage docs describe the balance as USD-denominated and read through GET /v1/balance. The script stores the first balance it sees each day, then computes how far the balance has fallen. A top-up during the day raises the balance, so the script ratchets the start value up; that keeps a top-up from hiding earlier spend.

import json
import os
import sys
import urllib.request
from datetime import date

CAP_MICROS = int(float(os.environ.get("DAILY_CAP_USD", "10")) * 1_000_000)
STATE = os.environ.get("GOVERNOR_STATE", "governor.json")


def balance_micros() -> int:
    req = urllib.request.Request(
        "https://api.sume.com/v1/balance",
        headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"]},
    )
    with urllib.request.urlopen(req, timeout=15) as resp:
        body = json.load(resp)
    return int(body["data"]["balance"]["available_amount_usd_micros"])


def main() -> int:
    today = date.today().isoformat()
    now = balance_micros()
    try:
        with open(STATE) as f:
            state = json.load(f)
    except FileNotFoundError:
        state = {}
    if state.get("day") != today:
        state = {"day": today, "start": now}
    if now > state["start"]:
        state["start"] = now
    with open(STATE, "w") as f:
        json.dump(state, f)
    spent = state["start"] - now
    print(f"spent {spent / 1e6:.4f} of {CAP_MICROS / 1e6:.2f} USD today")
    return 1 if spent >= CAP_MICROS else 0


sys.exit(main())

What does the gate measure, and what does it miss?

The drop in available balance counts captured spend and, depending on how holds are applied to the balance, may include open reservations. Treat it as a conservative proxy. For an exact figure of what a thread, run or job cost, use the run-scoped GET /v1/usage summary and quote debited_usd_micros, as the Usage page recommends.

  • It is checked when you run it. Call it before each submit, or on a one-minute timer in a worker.
  • It reads money in micros, so sub-cent items such as speech to text do not vanish in rounding.
  • It does not know about jobs you submitted before the cap was reached; those reserve their estimates and finish normally.
  • A balance read is a normal authenticated request, so it falls under the usual rate limits; do not poll it in a tight loop.

How do you set the cap number?

Start from the monthly budget, divide by the days in the month, and leave a margin for the busy days. A flat cap wastes money on slow days and blocks you on launch days, so consider a daily cap of 1.5 times the average with the monthly number as the real limit. Add a retry buffer on top; the retry-buffer post has the math for how much slack a batch needs.

When the gate trips, queue the work for tomorrow instead of dropping it. A refused submit costs nothing, and the work will be priced identically later. If you also need a hard stop on the Sume side, see the existing guide on workspace spend limits in api-spend-limit-monthly-budget.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume