Skip to content

Add SDK to Your App

In First Protected Call a throwaway script proved the enforcement path with three environment variables. This page turns that into the shape real applications use: a durable configuration profile instead of pasted variables, and an example parameterized so the same code reaches any resource you protect. Pick one language; the three examples are equivalent.

  • Complete First Protected Call.
  • Keep Caracal running.
  • Install one supported runtime from the table below.

Inline environment variables work for a script; an application needs configuration it can deploy. The SDK reads a small TOML file called a profile, named by the CARACAL_CONFIG environment variable. You write this file yourself, using the values from First Protected Call - the zone ID, the application ID, and the application client secret you copied during guided setup:

zone_id = "<Pied Piper Production zone ID>"
application_id = "<Anton application ID>"
app_client_secret_file = "/path/to/anton-client-secret"
[[credentials]]
resource = "resource://openai"
upstream_prefix = "https://api.openai.com"

Reading it line by line:

  • zone_id and application_id identify your program: it acts as the Anton application inside your zone.
  • app_client_secret_file points to a file containing the client secret, readable only by your user. The SDK never searches for credentials on its own; the path must be explicit. If you lost the secret, reveal it again from the application’s detail panel in the console (each reveal is audited).
  • The [[credentials]] entry declares which resource this program uses. Its key is the resource identifier, not the upstream URL.

On the local stack the SDK’s built-in defaults already point at the right service URLs, so this is the whole file. For cloud or custom deployments you would add sts_url, coordinator_url, and gateway_url; the full schema is in Configure Workloads.

Point the examples at the profile and choose what they call. When CARACAL_CONFIG is set, the SDK reads exactly that profile - the identity variables from the previous page are no longer needed:

Terminal window
export CARACAL_CONFIG=/path/to/caracal.toml
export CARACAL_RESOURCE_ID=resource://openai
export CARACAL_RESOURCE_PATH=/v1/models
export CARACAL_RESOURCE_SCOPE=openai:models

Install the package for your application language.

LanguageInstall commandRuntime requirement
TypeScriptnpm install @caracalai/sdk or pnpm add @caracalai/sdkNode.js 22+
Pythonpip install caracalai-sdkPython 3.12+
Gogo get github.com/garudex-labs/caracal/packages/sdk/goGo 1.26+
import { Caracal } from '@caracalai/sdk'
const caracal = new Caracal()
const resourceId = process.env.CARACAL_RESOURCE_ID
const resourcePath = process.env.CARACAL_RESOURCE_PATH
const resourceScope = process.env.CARACAL_RESOURCE_SCOPE
if (!resourceId) throw new Error('CARACAL_RESOURCE_ID is required')
if (!resourcePath) throw new Error('CARACAL_RESOURCE_PATH is required')
if (!resourceScope) throw new Error('CARACAL_RESOURCE_SCOPE is required')
const governedFetch = caracal.applicationTransport(resourceId, {
scopes: [resourceScope],
})
const target = caracal.gatewayRequest(resourceId, resourcePath)
try {
const response = await governedFetch(target.url, {
method: 'GET',
})
if (!response.ok) throw new Error(`protected call failed: ${response.status}`)
console.log(await response.text())
} finally {
await caracal.close()
}

Run the example in your selected language. It should print the provider’s JSON model list - the same response your first script returned - and create matching authorization and Gateway action-result events in Audit. A constructor or profile error means no request reached Caracal; a policy denial appears in Audit with a request ID.

All three examples follow the same four calls; only the naming convention changes per language:

  • new Caracal() / Caracal() / New() loads the profile named by CARACAL_CONFIG (or, without one, CARACAL_* environment variables, as in First Protected Call). It fails immediately if the configuration is missing or unreadable.
  • applicationTransport() / application_transport() / ApplicationTransport() returns an HTTP transport pinned to one resource. Each call asks Caracal’s token service (the STS, the component that evaluates policy and issues mandates) for authority with exactly the scopes you list and gets a fresh, short-lived, replay-protected mandate for the request. To do this it opens a session - Caracal’s record of one governed run of your program - and narrows the requested scope through a delegation, a hand-off that can only ever shrink permissions, never grow them. The SDK manages both for you; you will meet them properly in Concepts.
  • gatewayRequest() / gateway_request() / GatewayRequest() builds the Gateway URL and the X-Caracal-Resource routing header that names the resource.
  • close() / aclose() / Close() ends SDK-owned sessions and background work cleanly.

applicationTransport() is the smallest application-owned call path and the right starting point. Agent frameworks that already run under delegated authority use session() with a scoped transport instead; read your language’s SDK guide (TypeScript, Python, Go) before switching paths.

If policy denies the exchange, the SDK surfaces the error from the STS. Open Audit in the web console with the request ID to see the determining policy and diagnostics.

  • Use the resource identifier (resource://openai), not the upstream URL, as the [[credentials]] entry key.
  • Give gatewayRequest a relative path; it rejects absolute URLs and dot segments.
  • Request at least one scope, and keep every scope within what the active policy allows.
  • Close the client on shutdown so sessions and background work terminate cleanly.

If anything failed - the profile would not load, the exchange was denied, the Gateway refused the call, or audit shows nothing - walk First-Run Troubleshooting. Otherwise you have completed Get Started: continue to Tutorials to protect a real API, or read Concepts for the full model behind what you just built.