Skip to content

Handle runtime failures

The SDK protects previously confirmed paid access by default. Every check derives from a saved list: a list that confirms the check is reused for less than 5 minutes. If Strent later times out, has a network error, returns HTTP 5xx or 429, or sends an invalid successful response, the SDK can answer from a saved list less than 1 hour old. You do not need to implement fallback in a catch.

Negative checks and whole-list requests always call Strent. A saved list can answer true for a value it contains, but never false for one it lacks. HTTP 400, 401, 403, 409, other non-429 4xx, and caller abort still throw; so do availability failures without an eligible saved answer. customers.retrieveBillingState and customers.refresh never use fallback.

For ordinary paid-access checks, the default may fit. Removing access can take up to 5 minutes to appear while Strent is healthy, or until the saved value’s 1-hour limit during an outage. Admin changes remain visible immediately. For sensitive paths such as fraud or immediate revocation, use a client with cache: false and choose how your app handles errors.

import { Strent } from "@strent-dev/node";
const strictStrent = new Strent({
apiKey: process.env.STRENT_API_KEY!,
cache: false,
entitlements: {
defaults: { advancedExports: false },
products: { [process.env.PRO_PRODUCT_ID!]: { advancedExports: true } },
},
});
export async function canUseAdvancedExports(customer: string) {
return strictStrent.entitlements.has({
customer,
entitlement: "advancedExports",
});
}

When a call throws, preserve the operational error or turn it into your application’s temporary-unavailable response. Catching every error and returning false hides a service failure behind an apparently valid billing fact.

Every fallback writes a server warning with the customer, operation, age, and original error. An onFallback handler on the client replaces that warning; it receives { operation, customer, ageMs, error }. The handler runs synchronously, and a thrown exception is ignored so the saved answer still returns. Fresh positive reuse is silent.

Create one client per API key and base URL and reuse it. The client retains at most 10,000 customers in memory, evicting the least recently used. Serverless instances do not share memory and lose saved facts when replaced. Coverage is partial: a cold instance or a value aged 1 hour or more can still fail during an outage.

A successful customers.refresh clears that customer’s saved facts in the same client, including reads started before refresh finished. A failed refresh leaves them intact. Other clients are independent.

Runtime read endpoints are read-only POST operations and are semantically safe to retry. The SDK intentionally does not retry automatically. If your application retries:

  • Retry transient network errors, timeouts, 429, and selected 5xx responses only.
  • Use a small attempt limit with exponential backoff and jitter.
  • Honor retryAfterSeconds on StrentRateLimitError when present.
  • Keep the total time inside the caller’s latency budget.
  • Do not retry validation, authentication, revocation, or not-ready errors in a tight request loop.

Log the error class, API code, status, and requestId without logging the project API key or customer billing payload. Return an application-owned message to the end user.

For operational investigation, use customers.retrieveBillingState. It provides the last refresh time, subscriptions with derived cancellation and pending-change facts, and items, but is outside the hot-path performance class.