Turning gating on
Setentitlement in the stiggContext to what the call is checked against: a credit currency or a metered feature, not both.
customerId on the call. You can model plans and pricing once metering works.
Without entitlement, the wrapper only meters: every call goes through and its usage is reported to Stigg, but nothing is checked and access is never denied. If you wrap a client with a customer but no entitlement as its default, the SDK logs this once, so it is never a surprise.
The check and the reporting are set up separately, so make sure they point at the same balance.
entitlement sets which balance the check looks at, for example your credits currency. The SDK reports token metrics by default, and those only reduce the balance if their features are mapped to the currency in its Credit consumption settings in Stigg. If they are not, the balance never goes down and every check passes. Alternatively, convert usage into credits in your code with weighted credits, which deducts from the balance directly. If you check a metered feature instead, the metric you report must feed that feature’s meter. See The credit balance does not go down.Handling denied access
When access is denied, the call is not sent to the provider. A wrapped call has to return the vendor’s own response type, so denied access is raised as anAccessDeniedError. stigg.denial(err) turns it back into a decision you can act on, and returns undefined for any other error:
stigg.check(), for example anthropic.stigg.check(), or, with no client, stigg.check(context). Both return the decision rather than throwing. For example, check that an agent has enough credits before it starts a multi-step task, so it does not stop halfway. In a user-facing feature, you can also use it to disable a button before the user clicks it.
The decision object
stigg.check() returns a decision object, and stigg.denial(err) returns the same object for a call where access was denied. Its type is AccessDecision. It has these fields:
Remedies are product decisions
Different reasons for denied access call for different responses, and the SDK keeps them apart all the way tomessage:
Gating actions that are not model calls
Wrapped clients check and report model calls for you. Other actions can cost you money too, such as an agent’s calls to a paid web-search API, retrievals, or whole workflow steps. Check and report those yourself withstigg.check() and stigg.report(), using the same context as your model calls, so they count against the same customer, agent and team budgets:
Caching and accuracy
The Agent SDK does not keep a cache of its own. How a check is answered depends on whether it names an agent:- A check that names an agent, or other dimensions, is never cached. Only Governance can work out the agent’s budgets and every level above it, so each of these checks goes to Stigg. The decision always reflects the latest usage, and two servers can never both approve the same budget.
- A check for a customer only is answered from the Node server SDK’s entitlement cache, so it does not add a network round trip.
- Usage you report is written back into it, so the next check already includes it.
- It is updated in real time when an entitlement changes, for example a plan change, a cancelled subscription or a credit purchase.
- Usage resets are applied when the period ends.
- It can be shared by all your servers through Redis, instead of each server keeping its own.
cache:
client instead, so both share one cache. See the SDK reference.
Requested usage
Like an entitlement check, each check is made against a requested usage: the amount the call is about to consume. By default the requested usage is 1, which asks “is there anything left?”. The real usage is reported after the call, so the call that uses up a balance is allowed to finish. So a balance or budget can end up above its limit by the cost of the last call. With agents, one call can be a large share of a budget: a long generation can cost thousands of credits. Inasync mode the overshoot can be larger, because usage is counted only after Stigg processes the events, and calls made in the meantime are checked against the earlier balance. This adds up when one turn makes several calls in a row, such as an orchestrator and its sub-agents. To keep usage close to a hard limit, use the sync ingest mode, so each call is counted before the next check, together with an estimate of each call’s usage, described below.
To check against an estimate of the call’s usage instead, add an estimate to the recipe. The SDK includes one for Anthropic, estimateFromMaxTokens(tokensPerUnit), one for Gemini, estimateFromMaxOutputTokens(tokensPerUnit), and one for TypeSafe, estimateFromState(tokensPerUnit). For example, the Anthropic one sets the requested usage from the call’s max_tokens, the longest response it could produce:
estimate option instead, a function that receives the call’s parameters and returns the requested usage, for example openrouterRecipe({ estimate: (params) => params.max_tokens ?? 1 }).
A requested usage that is too high denies calls the customer could have afforded, so start with the default and add an estimate only where going over the limit matters.
Fallback strategy
If a check cannot complete, for example because of a network error, the SDK falls back to the behavior you choose withcheckErrorAction, the same idea as the fallback strategy in Stigg’s other SDKs:
allow(default): calls go through without a check, so your users are never blocked. Usage from that time is not reported, so it is not counted against any balance.deny: access is denied withremedy: 'retry'. Use this when enforcing a hard budget matters more than letting every call through.
Observe before you enforce
Gating a production AI feature is a big change, so roll it out in stages. Set everything up once at the start, so turning on enforcement later is a configuration change in Stigg, not a code change:- Grant the entitlement with a soft limit. In Stigg, add the metered feature or credit currency to the customer’s plan, and set it to a soft limit: for a metered feature, turn off limit enforcement; for credits, turn off the hard limit. Usage is only metered for customers who are granted an entitlement, so always grant one, even before you enforce anything.
- Set the same
entitlementin yourstiggContext. Every call is checked and its usage is metered, but because the limit is soft, access is never denied when usage passes it. - Register agents with
budget: { entitlement, limit: null }. Per-agent usage is tracked and visible, but agent budgets never block. See Agent governance. - Turn on enforcement in Stigg once the numbers look right: switch the entitlement to a hard limit, and set real per-agent limits. Your wrapped clients do not change.