CI guard: fail the build when a new Sume pricing_skus key appears
A node:test file fetches GET /v1/videos/models and fails when a model uses a pricing_skus key your cost code cannot total. Wan, Omni and H3 rates in the table.

Your cost estimator knows three pricing_skus key shapes today, and a model added next month may bring a fourth. A 15-line node:test file that fetches GET /v1/videos/models and fails on any unknown key turns a silent wrong total into a red build.
What the guard must recognise
The docs example shows a per-1000-video-tokens key, and the catalog also serves per-second keys with a resolution suffix. Your guard is an allow-list of those shapes; anything else should stop the pipeline and make a person read the new key.
The table lists rates the estimator must reproduce exactly. If a CI run prints a different total for the same inputs, a rate moved.
| Model | Key | Rate per second | Length | Expected total |
|---|---|---|---|---|
| wan-3.0 | per-video-second-480p | $0.0625 | 30 s | $1.875 |
| wan-3.0 | per-video-second-1080p | $0.25 | 30 s | $7.50 |
| gemini-omni-flash-1.1 | per-video-second-4K | $0.375 | 10 s | $3.75 |
| minimax-h3 | per-video-second-768p | $0.075 | 15 s | $1.125 |
The test
Run it with node --test. It needs SUME_API_KEY in the CI secrets and makes one read request.
import test from "node:test";
import assert from "node:assert/strict";
const KNOWN = /^(per-1000-video-tokens|per-video-second|per-video-second-audio|per-video-second-(360p|480p|720p|768p|1080p|1K|2K|4K))$/;
test("every pricing_skus key is one we can total", async () => {
const res = await fetch("https://api.sume.com/v1/videos/models", {
headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` },
});
assert.equal(res.status, 200);
const { data } = await res.json();
for (const m of data) {
for (const key of Object.keys(m.pricing_skus)) {
assert.match(key, KNOWN, `${m.id} has unknown sku key ${key}`);
}
}
});Gotchas
The resolution suffix list mirrors the resolution enum in the OpenAPI request schema: 360p, 480p, 720p, 768p, 1080p, 1K, 2K and 4K. If the enum grows, widen the regex deliberately rather than with a wildcard, or the guard stops guarding.
A model missing from the response is not a failure here: the catalog lists a model only when its provider is configured. Pin the models you rely on in a second test, and keep this one for key shapes.
Sources
Related posts
More in Developers
- Run an Agent Completion nightly from CI with curl and a spend cap
A 25-line bash job that starts a Sume Agent Completion with a cap and an idempotency key, polls the receipt, and fails the build unless the run completed.
- Egress firewall for a Claude agent in CI: Sume hosts to allow
Claude Agent SDK v0.2.164 hardens CI egress firewalls. Which Sume hosts a render job needs: api.sume.com, mcp.sume.com and media.sume.com, and what each is for.
- Claude Code 2.1.295 MCP changes: a checklist for Sume
Three MCP changes in Claude Code 2.1.295 (Oct 8) and what each means for a connection to Sume's hosted server. A short table to run through after upgrading.
- Claude Code hooks on Sume tool calls: check the top-level guards
A Claude Code hook that gates paid Sume MCP calls should read the top-level idempotency_key, dry_run and max_spend_usd, and deny when input is unreadable.
Written by Sume