Skip to main content

Configuration

Everything the clients can be told at construction time and per request, in both SDKs.

Authentication

Both clients take one credential: an org service-account sk_ key, which requires the API plan — personal seat keys and browser sessions are not supported. Pass it as apiKey / api_key or let the client read SLOTHBOX_API_KEY; either way it is sent verbatim in the Authorization header. The SDKs also send an x-slothbox-sdk header on every request, naming the SDK and its version — it carries no secrets and exists so SDK traffic can be identified, for support diagnostics.

Constructor options

import { Slothbox } from "@slothbox/sdk";

const slothbox = new Slothbox({
apiKey: "sk_…", // default: SLOTHBOX_API_KEY env var
baseUrl: "https://api.slothbox.dev", // default: the spec's server
maxRetries: 3, // default: 3; 0 disables retries
fetch: myFetch, // default: the global fetch
});
OptionDefaultWhat it does
apiKeySLOTHBOX_API_KEY env varThe sk_ key, sent verbatim in Authorization (no Bearer prefix). The constructor throws if neither is set.
baseUrlhttps://api.slothbox.devTarget a different stack; trailing slashes are stripped.
maxRetries3Retries after the initial attempt — see Errors, retries & rate limits. 0 disables.
fetchglobal fetchAny (url, init) => Promise<Response> — your seam for middleware, proxying, and testing. Runtimes without a global fetch require this.

There is no constructor-level timeout — bound requests with an AbortSignal per request instead.

Environment variables

VariableRead byMeaning
SLOTHBOX_API_KEYboth SDKsThe service-account sk_ key used when the constructor gets no explicit key. In the TypeScript SDK this requires a Node-style process.env — in runtimes without one (e.g. Cloudflare Workers), pass apiKey explicitly.

SLOTHBOX_WEBHOOK_SECRET, SLOTHBOX_ORG_ID, and friends appear throughout these docs and the examples — those are conventions of the sample code, not variables the SDKs read themselves.

Sync and async Python

Both Python clients expose the same resource surface; AsyncSlothbox is the await-able twin, with async for pagination and async waiters. Both are context managers — use with / async with (or call close() / aclose()) so the underlying httpx client is released:

from slothbox import AsyncSlothbox

async with AsyncSlothbox() as client:
box = await client.environments.launch_and_wait(
org_id, {"templateId": template_id}
)
async for event in await client.audit.list_org_events(org_id):
...

In TypeScript there is nothing to choose — the client is async by nature and holds no connection state, so there is no close().

Per-request options

Every resource method takes options after its arguments:

const env = await slothbox.environments.get(
{ orgId, envId },
{
signal: AbortSignal.timeout(10_000), // cancellation / timeout
headers: { "x-trace-id": traceId }, // merged over the SDK's defaults
maxRetries: 0, // override the client's setting
},
);

Operations that accept an idempotency key (environments.launch, launchAndWait) additionally take idempotencyKey — see below.

Cancellation & timeouts

Pass an AbortSignal as options.signal to any method. The signal reaches the underlying fetch, cancels the backoff sleeps between retries, stops for await auto-pagination, and aborts a waiter mid-poll:

// A hard deadline on one call:
await slothbox.environments.get({ orgId, envId }, { signal: AbortSignal.timeout(10_000) });

// One controller cancelling a whole workflow:
const controller = new AbortController();
const ready = slothbox.environments.waitUntilReady(
{ orgId, envId },
{ signal: controller.signal },
);
// elsewhere: controller.abort();

Aborting rejects with the signal's reason (an AbortError by default) — never a SlothboxError — so your cancellation handling stays separate from your failure handling.

Idempotency keys

The launch operations accept an idempotency key, sent as the Idempotency-Key header. Retrying the request with the same key returns the original box instead of provisioning a duplicate — and carrying the header is what makes a POST eligible for the SDK's automatic retries at all:

await slothbox.environments.launch(
{ orgId, body: { templateId } },
{ idempotencyKey: `task-${taskId}` },
);
// launchAndWait always sends one (yours, or an auto-generated UUID).

Use a key that is stable across retries of the same logical launch (a task id, a CI run id) and fresh for each new box you actually intend. The launch walkthrough shows the full pattern.

Waiter tuning

The lifecycle waiters take the same three knobs in both SDKs — only the units differ:

KnobTypeScriptPythonDefault
Overall deadlinetimeoutMstimeout (seconds)10 min (environments), 20 min (bakes)
First poll intervalpollIntervalMspoll_interval (seconds)7s
Poll-interval ceilingmaxPollIntervalMsmax_poll_interval (seconds)30s

The defaults are deliberately gentle — status polls do real work against your connected AWS account and share the org's compute rate tier. Tune them down only if you know why.

Escape hatches

When you need a route the typed surface doesn't cover (or doesn't cover yet), both clients expose a low-level request method that keeps the client's auth, retry policy, and typed error mapping:

const result = await slothbox.request("GET", "/organizations/{orgId}/environments", {
pathParams: { orgId },
query: { someNewParam: "value" }, // undefined/null entries are skipped
});

There is also slothbox.call(operationId, args, options) — the typed dispatch the resource methods are thin wrappers over.

In both SDKs, JSON responses parse to plain data, 204s resolve to nothing (undefined / None), and the API's one non-JSON success — the CloudFormation template YAML — comes back as a raw string.