---
title: "Go SDK"
url: "https://docs.caracal.run/v1.0/sdks/go/"
markdown_url: "https://docs.caracal.run/markdown/v1.0/sdks/go.md"
description: "Public API reference for the Go Caracal SDK."
page_type: "page"
concepts: []
requires: []
---

# Go SDK

Canonical URL: https://docs.caracal.run/v1.0/sdks/go/
Markdown URL: https://docs.caracal.run/markdown/v1.0/sdks/go.md
Description: Public API reference for the Go Caracal SDK.
Page type: page
Concepts: none
Requires: none

---

The Go SDK provides Session lifecycle, Delegation, Gateway routing, and context propagation for Go services.

Use it for application authority, not management CRUD. Use [Admin Package](/v1.0/sdks/admin/) for control-plane automation.

## Install

```bash
go get github.com/garudex-labs/caracal/packages/sdk/go
```

## Connect and Configure

```go
import caracal "github.com/garudex-labs/caracal/packages/sdk/go"

client, err := caracal.New()
if err != nil {
	return err
}
```

`New()` loads exactly `CARACAL_CONFIG` when set; otherwise it loads `CARACAL_*` environment variables. It never searches home directories or default profile paths. Multiple credential modes fail at startup.

| Constructor                                             | Use it when                                                       |
| ------------------------------------------------------- | ----------------------------------------------------------------- |
| `New()`                                                | Use normal deployment configuration.                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `FromClientSecret(options)`                            | Supply one complete static client-secret configuration directly.                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `FromEnv()`, `FromConfig(path)`, `FromCredentials(...)` | Advanced explicit loading, profile, and dynamic credential paths.                                                                                                                                                                                                                                                                                                                                                                                                                                         |

## Make Your First Protected Call

The smallest complete integration pins a transport to one resource and sends a request through the Gateway:

```go
package main

import (
	"fmt"
	"io"

	caracal "github.com/garudex-labs/caracal/packages/sdk/go"
)

func main() {
	client, err := caracal.New()
	if err != nil {
		panic(err)
	}
	defer client.Close()

	governed, err := client.ApplicationTransport(nil, "resource://pipernet", caracal.ApplicationTransportOptions{
		Scopes: []string{"pipernet:read"},
	})
	if err != nil {
		panic(err)
	}
	target, err := client.GatewayRequest("resource://pipernet", "/reports")
	if err != nil {
		panic(err)
	}

	resp, err := governed.Get(target.URL)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		panic(fmt.Sprintf("protected call failed: %s", resp.Status))
	}
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
```

The zone, application, and resource behind this call come from your runtime profile; [Add SDK to Your App](/v1.0/get-started/add-sdk-to-your-app/) walks that setup end to end. The sections below group the client API by task.

## Run Work in Sessions

| API                                                    | Purpose                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client.Session(ctx, fn, opts...)`                     | Run `fn` inside a governed Session with a bound `context.Context`; set `SessionOptions.Authority` to bound its authority and `Task` to record what the Session is for. Retry protection is automatic; ordinary code should leave `IdempotencyKey` empty. See [Safe Retries and Idempotency](/v1.0/guides/idempotency/) for durable-source redelivery.                                                                                                                                                         |
| `client.StartSession(ctx, opts...)`                    | Start a governed Session that outlives a block; auto-renews its generation-fenced lease and returns a `*SessionHandle` with `Heartbeat`, `DeadlineAt`, `LeaseGeneration`, and `Close`. Retry protection is automatic.                                                                                                                                                                                                                                                                                    |
| `client.AttachSession(ctx, sessionID, opts...)`        | Re-attach to an active persisted long-lived Session after a restart: atomically acquires a new generation, fences older holders, and returns the same handle `StartSession` does.                                                                                                                                                                                                                                                                                                                         |

Session patterns for long-lived services and restart recovery are walked through in [Integrate the Go SDK](/v1.0/guides/sdk-go/).

## Hand Off Authority Between Agents

| API | Purpose |
| --- | --- |
| `client.Delegate(ctx, opts)`                           | Delegate a slice of the current Session's authority to a peer Session; returns the Delegation for the receiver to accept. A transient Coordinator failure is retried once under an idempotency key, so no duplicate Delegation is issued.                                                                                                                                                                                                                                                                 |
| `client.RevokeDelegation(ctx, delegationID)`           | Revoke a Delegation issued by this application.                                                                                                                                                                                                                                                                                                                                                                                           |
| `client.AcceptDelegation(ctx, delegationID, opts...)`  | Present a received Delegation: derive a context carrying it. Pass `AcceptDelegationOptions{Validate: true}` to confirm with the Coordinator that the Delegation is live for the bound Session first.                                                                                                                                                                                                                                                                                                    |

The full hand-off workflow, including safe constraint choices, lives in [Implement Multi-Agent Delegation](/v1.0/guides/delegation/).

## Propagate Context Across Services

| API | Purpose |
| --- | --- |
| `client.Headers(ctx, opts...)`                         | Project the bound context to `http.Header`.                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `client.BindFromRequest(ctx, req, opts...)`            | Bind inbound Caracal envelope headers.                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

## Call Protected Resources

| API | Purpose |
| --- | --- |
| `client.Transport(base, opts...)`                      | Return an `*http.Client` that mints the `use=gateway` mandate from `CallOptions.Scopes` and applies Gateway routing. Set `CallOptions.ApprovalID` to consume an approved hold. |
| `client.ApplicationTransport(base, resourceID, opts)`  | Return an `*http.Client` pinned to one resource, calling as the application's own identity; provisions its own Session pair and Delegation. Set `ApplicationTransportOptions.ApprovalID` to consume an approved hold. |
| `client.MintMandate(ctx, resourceID, scopes, opts...)` | Mint a cached resource mandate carrying the bound Session and Delegation; returns an `oauth.MintedMandate` with `Token` and `ExpiresInSeconds`. Requires client-secret credentials. |

Use `ApplicationTransport()` when your service calls as itself; use `Transport()` inside a Session when work already runs under session or delegated authority. Propagation defaults to `PropagationGatewayOnly`; use `PropagationAlways` only for a known Caracal-aware direct service chain, and note that Gateway redirects are surfaced without automatically replaying the mandate. Application-transport provisioning starts one source/target Session pair and one narrowed Delegation per cache key: a cold call costs four provisioning calls plus the final SDK mint and Gateway STS exchange, a warm call still performs both per-request STS exchanges, and `Close()` retires backing Sessions best-effort. Wiring these transports into OpenAI, Anthropic, and other provider clients is covered in [Provider Recipes](/v1.0/guides/provider-recipes/#wire-the-transport-into-provider-clients).

## Act for Federated Users and Approvals

| API | Purpose |
| --- | --- |
| `client.FederateSubject(ctx, idToken, opts...)`        | Exchange a Federated user's identity token for an Authority record and return a `FederatedSubject` with `SubjectAuthorityRecordID`, `Token`, and `ExpiresInSeconds`. Start attributed work with both `SubjectAuthorityRecordID` and `SubjectAuthorityRecordToken: Token`; Coordinator verifies the signed proof before binding the record. This does not by itself propagate the Federated user's `sub` into later resource mandates. The returned mandate also remains the Federated user's credential for supported approval and exchange paths. |
| `client.WaitForApproval(ctx, approvalID, timeout)`    | Long-poll an approval raised by an approval-gated mint; returns the final `oauth.ApprovalState` (`ApprovalApproved`, `ApprovalRejected`, `ApprovalExpired`, `ApprovalConsumed`, or `ApprovalPending`).                                                                                                                                                                                                                                                                                         |
| `sdk.WithApproval(ctx, client, timeout, fn)`           | Run an approval-gated operation end to end: on `*oauth.ApprovalRequiredError` the client waits for the decision and, once approved, invokes `fn` again with the approval id.                                                                                                                                                                                                                                                                                                                             |

Approval gating is a policy feature; [Human Approval](/v1.0/guides/human-approval/) covers the tiers and the operator decision path.

## Build Requests and Manage the Client

| API | Purpose |
| --- | --- |
| `client.GatewayRequest(resourceID, path)`              | Build explicit Gateway routing metadata.                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `client.Identity(ctx)`                                 | The zone and application the client acts as, for logging and metric labels.                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `client.Current(ctx)`                                  | Inspect the current Caracal context.                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `client.Close()`                                       | Terminally close the client and application-transport Sessions best-effort. Repeated close is safe; later operations fail.                                                                                                                                                                                                                                                                                                                                                                                |

## Context Propagation

```go
constraints := &caracal.DelegationConstraints{
	MaxHops:        1,
	PolicyApproved: true,
}
```

Available fields are `Resources`, `MaxDepth`, `MaxHops`, `TTLSeconds`, `PolicyApproved`, `ExpiresAt`, and `BroadReason`.

`PolicyApproved` and `BroadReason` are audit/display metadata, not authorization decisions. Delegation constraints do not implement usage accounting; enforce consumable quotas in a durable domain transaction.

## Protect Inbound Requests

Use `BindFromRequest()` to propagate a Caracal context after an upstream Gateway, adapter, or verify-engine verifier has accepted the inbound mandate. Set `CallOptions.Verify` to enforce the bearer token at the boundary itself. The callback receives the inbound token, returns an error on failure, and must return a non-nil complete `*VerifiedClaims` projection on success. `ZoneID`, `ApplicationID`, and `Hop` are authoritative. Empty optional authority fields are authoritatively absent and never fall back to unsigned caller baggage. In production propagation-only mode, set `TrustedPropagation: true` to state that an upstream boundary already enforced the request; omitting both modes fails closed. Use [Verification Layer Overview](/v1.0/sdks/verification-layer/) when the Go service must enforce mandate signatures, scopes, targets, Session identity, Delegation, or revocation at its own boundary.

Trace context and non-Caracal baggage remain propagation data. `Headers` and `Transport` require a bound Caracal context by default. Pass `caracal.CallOptions{AsApplication: true}` only when the call should intentionally use the application subject token; inbound application binding discards caller-supplied Caracal authority baggage.

## Errors and Observability

STS denials return `*oauth.CaracalError` carrying `Code`, `HTTPStatus`, and `RequestID`, so callers branch with `errors.As` instead of matching message text. Approval-gated exchanges return `*oauth.ApprovalRequiredError` with the approval fields, and coordinator failures return `*caracal.CoordinatorError` with `StatusCode`, `Method`, and `Path`.

```go
import oauth "github.com/garudex-labs/caracal/packages/oauth/go"

_, err := client.MintMandate(ctx, "resource://pipernet", []string{"pipernet:read"})
var denied *oauth.CaracalError
if errors.As(err, &denied) && denied.Code == "access_denied" {
	log.Printf("denied by policy (request %s)", denied.RequestID)
}

client.OnEvent(func(event oauth.Event) {
	metrics.Timing("caracal."+event.Type, event.Duration, event.Ok)
})
```

`OnEvent(hook)` reports every control-plane operation: `token.exchange` (with `Resources`, `Scopes`, and `Cached` for cache hits), `approval.wait` (with `ApprovalID` and the final `State`), `coordinator.call` (with `Method`, `Path`, and `Status`), and `delegation.accept` (with `DelegationID` and `SessionID`, so delegation presentations are auditable client-side). Each event carries `Ok` and `Duration`, ready to bridge into any metrics or tracing system. A hook that panics is recovered and never disturbs the operation that emitted the event, and the call returns a disposer that removes the hook. Errors the platform reports carry `Retryable()`, a hint that transport-level congestion and availability failures are worth retrying while policy denials are not.

Bridging into Prometheus takes one hook; the same shape feeds an OpenTelemetry meter:

```go
operations := prometheus.NewCounterVec(prometheus.CounterOpts{
	Name: "caracal_operations_total",
	Help: "Caracal control-plane operations",
}, []string{"type", "ok"})
latency := prometheus.NewHistogramVec(prometheus.HistogramOpts{
	Name: "caracal_operation_duration_ms",
	Help: "Caracal control-plane operation latency",
}, []string{"type"})

client.OnEvent(func(event oauth.Event) {
	operations.WithLabelValues(event.Type, strconv.FormatBool(event.Ok)).Inc()
	latency.WithLabelValues(event.Type).Observe(float64(event.Duration.Milliseconds()))
})
```

The Go module ships as a single flat package: the envelope codec, context plumbing, Coordinator functions (`StartCoordinatorSession`, `AcquireSessionLease`, `CreateDelegation`, `HeartbeatSession`, `ListInboundDelegations`, `TerminateSession`), and Session primitives (`Session`, `StartSession`, `AttachSession`, `Delegate`) sit beside the `Caracal` client rather than behind a separate advanced entrypoint.

## Retries and Cleanup

Session creation retries transient Coordinator failures twice under one generated idempotency key; Delegation creation retries once. STS exchange and Gateway requests are not automatically replayed. Always use the callback context passed to `Session`, close long-lived handles, and call `Close()` during shutdown. `Close()` is idempotent and terminal.

## Transport Security and Credential Handling

Every control-plane client accepts a custom `*http.Client` - `HTTPClient` on `CoordinatorClient` and `ClientSecretOptions`, and the `base` argument of `Transport` - so deployments that require mutual TLS or a private CA toward the STS and coordinator inject a client with a `tls.Config` carrying certificates instead of patching defaults. Production configuration refuses plaintext `http` control-plane URLs outside loopback; `CARACAL_ALLOW_INSECURE_CONFIG_URLS=true` overrides that gate and logs a warning banner at startup so the exception stays visible until TLS is in place.

Tokens, client secrets, and minted mandates live in ordinary process memory for their lifetime: Go strings are immutable and garbage-collected, so the SDK cannot zeroize them, and anything able to read the process heap (a debugger, a core dump, a compromised dependency) can read them. Keep secrets out of logs and error trackers - the SDK never logs them and caps error bodies for the same reason - rely on short token lifetimes and the credentials resolver for rotation, and treat heap access as full credential compromise in your threat model.

## Related Pages

* [Integrate the Go SDK](/v1.0/guides/sdk-go/)
* [Verification Layer Overview](/v1.0/sdks/verification-layer/)
* [Enforce, propagate, or attribute](/v1.0/concepts/authority-model/#enforce-propagate-or-attribute)
* [Protect a Go net/http Service](/v1.0/guides/protect-nethttp/)
* [Session Delegation](/v1.0/concepts/delegation/)
