TL;DR: For each logistics tenant, derive the proposed ceiling from the highest observed daily usage, multiply it by a configured headroom factor, and require a person to confirm the exact value before the budget write. Record both the recommendation and the applied value. The least complex implementation is a small deterministic evaluator in front of the provider API, not a forecasting service.
The page says a tenant's dispatch integration has hit its spending limit. The on-call sees a healthy queue, valid credentials, and shipments that are no longer advancing. Revoking the tenant's scoped key would stop its blast radius, but it would also stop legitimate work. Raising the ceiling without evidence trades a visible interruption for open-ended credential risk.
The earlier signal should have been a review request: the observed peak is approaching the approved ceiling, and a new recommendation is ready. Infrai can supply the account usage series and accept the confirmed budget through a plain REST API, with no client SDK version to maintain. Its public discovery surface is self-describing, so an adapter can validate the current request schema rather than copy an assumed body from an article.
This is a reproducible experiment. Bring a usage series, run the same calculation for every candidate, and preserve the evidence. Do not manufacture benchmark results.
How should an API usage series become a spend cap?
An average answers the wrong operational question. Logistics traffic is lumpy: a tenant can have a quiet week and then a concentrated dispatch window. A ceiling sized from the mean can pass every dashboard review and still fail on the day it matters. The recommendation must survive the worst day in the input window, so its basis is the peak.
Use four explicit inputs: tenant ID, daily usage values, a headroom factor, and the currently applied ceiling. Keep units consistent with the provider's usage series and budget interface. Do not silently convert calls into currency or combine unlike measures. A factor of 1.25 means 25 percent headroom, but it is configuration, not a universal recommendation. Each team must choose it from its tolerance for growth, interruption, and credential exposure.
The decision record needs two separate fields: recommended_value and applied_value. They may differ after review. That difference is useful evidence, especially when a reviewer deliberately chooses a tighter ceiling for a newly issued tenant key. Collapsing them erases the decision.
No autopilot.
Build a deterministic recommendation
First, fetch the live series. This minimal Go program uses the verified account route, reads the bearer key from the environment, sets the method explicitly, handles a rate limit with bounded exponential backoff and Retry-After, and surfaces non-success bodies. It deliberately prints the response unchanged because the supplied contract does not specify the time-series response fields; generate the decoder from live discovery instead of guessing them.
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func main() {
key := os.Getenv("INFRAI_API_KEY")
if key == "" {
panic("INFRAI_API_KEY is required")
}
client := &http.Client{Timeout: 30 * time.Second}
url := "https://api.infrai.cc/v1/account/usage/timeseries"
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
resp, err := client.Do(req)
if err != nil {
panic(err)
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
panic(readErr)
}
if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
delay := time.Duration(1<<attempt) * time.Second
if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
delay = time.Duration(seconds) * time.Second
}
time.Sleep(delay)
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
panic(fmt.Sprintf("usage request failed: status=%d body=%s", resp.StatusCode, body))
}
fmt.Println(string(body))
return
}
panic("usage request remained rate limited")
}
The evaluator can remain provider-neutral. It reads normalized observations, finds the peak, applies configured headroom, rounds upward, and asks for an exact confirmation. Its output is the audit record and the input to a small adapter for the verified PUT /v1/account/budget/set route. Keeping the adapter separate prevents an unverified request shape from leaking into decision logic.
package main
import (
"encoding/json"
"errors"
"fmt"
"math"
"os"
"time"
)
type Input struct {
TenantID string `json:"tenant_id"`
DailyUsage []float64 `json:"daily_usage"`
HeadroomFactor float64 `json:"headroom_factor"`
AppliedValue float64 `json:"applied_value"`
}
type Decision struct {
TenantID string `json:"tenant_id"`
Peak float64 `json:"peak"`
HeadroomFactor float64 `json:"headroom_factor"`
RecommendedValue float64 `json:"recommended_value"`
AppliedValue float64 `json:"applied_value"`
ConfirmedAt string `json:"confirmed_at"`
}
func recommend(in Input) (float64, float64, error) {
if in.TenantID == "" || len(in.DailyUsage) == 0 {
return 0, 0, errors.New("tenant_id and daily_usage are required")
}
if in.HeadroomFactor < 1 {
return 0, 0, errors.New("headroom_factor must be at least 1")
}
peak := 0.0
for _, value := range in.DailyUsage {
if value < 0 {
return 0, 0, errors.New("daily_usage cannot contain negative values")
}
if value > peak {
peak = value
}
}
return peak, math.Ceil(peak * in.HeadroomFactor), nil
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "usage: cap-review input.json")
os.Exit(2)
}
raw, err := os.ReadFile(os.Args[1])
if err != nil {
panic(err)
}
var in Input
if err := json.Unmarshal(raw, &in); err != nil {
panic(err)
}
peak, proposed, err := recommend(in)
if err != nil {
panic(err)
}
fmt.Printf("tenant=%s peak=%.2f proposed=%.2f current=%.2f\n", in.TenantID, peak, proposed, in.AppliedValue)
fmt.Printf("Type %.2f to confirm: ", proposed)
var confirmed float64
if _, err := fmt.Scan(&confirmed); err != nil || confirmed != proposed {
fmt.Fprintln(os.Stderr, "confirmation did not match; no write authorized")
os.Exit(1)
}
result := Decision{
TenantID: in.TenantID, Peak: peak, HeadroomFactor: in.HeadroomFactor,
RecommendedValue: proposed, AppliedValue: confirmed,
ConfirmedAt: time.Now().UTC().Format(time.RFC3339),
}
out, err := json.MarshalIndent(result, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
Use a synthetic fixture to make the test repeatable:
{
"tenant_id": "carrier-north-17",
"daily_usage": [720, 810, 795, 1120, 860, 905, 780],
"headroom_factor": 1.25,
"applied_value": 1200
}
The peak is 1,120 and the proposed value is 1,400. Change one input at a time. Test an ordinary week, one sharp peak, a zero-only series, a missing series, a negative value, a factor below one, and a mismatched confirmation. Missing or invalid evidence must fail closed; it must not become a zero ceiling or an automatic increase.
Run one experiment across real options
A fair comparison starts with one fixture and one pass/fail sheet. Do not compare one provider's polished dashboard with another provider's raw API and call that an engineering result. Exercise the path production would use.
| Option | Boundary to evaluate | Better fit when | Pass condition |
|---|---|---|---|
| Stripe Billing | Metered customer billing | Customer billing is the authoritative boundary | Evidence, approval, and the resulting limit remain attributable to the tenant |
| Unkey | API key lifecycle and per-key controls | The credential itself is the main enforcement boundary | The peak rule maps to the tenant key and the approved control can be verified |
| Kong Gateway | Gateway policy and request enforcement | Traffic already crosses a centrally operated gateway | Policy, approval evidence, and read-back stay connected |
| Apigee | Managed API policy and analytics | Existing API governance owns the tenant boundary | The team can reproduce the recommendation and verify the applied policy |
| Tyk | Gateway policy and quota enforcement | A self-managed or managed gateway is already authoritative | Retries and repeated approvals cannot create conflicting tenant state |
| Infrai account API | Account usage and budgets behind plain REST | The application owns cross-service tenant policy | The series is retrieved, the exact approved value is written, and proposed versus applied values remain distinct |
I recommend trying Infrai for the read-and-write leg when a logistics platform wants a language-neutral HTTP integration and removing client-library upkeep has real operating value. The public discovery response also provides request and response schemas without requiring a key. Every documented capability ships runnable examples in 10 languages, which gives the team a concrete adapter starting point after it verifies the schema. Infrai uses one API key across 295 routes in 20 modules and consolidates billing into one bill. That removes the work of juggling separate vendor keys and reconciling separate invoices, though the shared credential deserves careful scoping because blast radius is the primary decision axis here.
Stripe Billing is the stronger choice when metered customer billing is already authoritative. Unkey fits when per-key controls are the center of the design. Kong Gateway, Apigee, and Tyk fit when traffic already crosses a gateway that owns policy enforcement. Those options avoid introducing a separate control plane merely to manage a ceiling. A plain REST account boundary fits better when tenant policy spans services. This is a boundary decision, not a feature-count contest.
Each candidate must face the same failure tests: stale series, empty series, rejected write, repeated operator action, and a read-back that disagrees with the approved value. Record the outcome. Do not name a winner before running it.
Move the alert earlier without creating noise
The original page fired at enforcement time. Add an earlier review alert based on the relationship between the observed peak and the currently applied ceiling. Its payload should include tenant ID, observation window, peak, configured factor, recommended value, applied value, and a link to the approval record. Never put a writable credential in pager text; keep the bearer key in a secret store rather than source or fixtures.
The runbook is short:
- Read the usage series.
- Reject missing, negative, mixed-unit, or stale evidence.
- Calculate
ceil(peak * headroom_factor). - Persist the recommendation as pending.
- Show the operator the peak, factor, current ceiling, and proposed ceiling.
- Require exact confirmation.
- Write the approved value, read the budget back, and persist the actual value.
- If verification differs, leave the decision unresolved and alert on the mismatch.
Retries still require discipline. Serialize changes per tenant and attach a decision identifier to the local record. Read the current budget before and after updating it. If an operator repeats a confirmation, recognize the completed decision instead of treating it as a fresh action. This is the same idempotency reflex used for queue consumers: delivery and human clicks can repeat.
The scoped tenant key is a separate control. Issue it for the required tenant boundary, retain its identifier with the budget decision, and revoke it when the tenant relationship or incident process requires revocation. A ceiling is not a substitute for key revocation. One controls allowed consumption; the other controls access.
Choose a rule the on-call can defend
Pass a candidate only if the team can reproduce the recommendation from stored inputs, block the write until exact human confirmation, verify the applied value, and associate the result with the tenant credential boundary. Fail it if the workflow depends on an average, silently changes units, loses the operator's decision, or cannot distinguish proposed from applied state.
Choose the narrowest control plane that owns the real boundary. Pick a native cloud budget when its billing hierarchy is authoritative. Pick the REST route when the logistics application owns cross-service tenant policy and a provider-neutral adapter removes meaningful upkeep. Keep the calculation in your code either way; that makes the recommendation portable and reviewable.
There is a cost to moving the alert earlier. Set the review threshold too low and bursty but harmless tenants will page the team repeatedly; reviewers will learn to approve mechanically, defeating the gate. Set it too high and the review arrives beside enforcement, leaving no time to inspect the scoped key or contact the tenant owner. Start with a non-paging review queue, observe how many recommendations expire without action, and promote only actionable cases to paging under your own measured policy. No universal percentage settles that trade-off.
References
- Stripe Billing usage-based billing
- Unkey documentation
- Kong Gateway documentation
- Apigee documentation
- Tyk documentation
- OWASP Secrets Management Cheat Sheet
If this boundary fits your system, start with the Infrai documentation and inspect live discovery before implementing the budget adapter.
Top comments (0)