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.