SDKs and CLI
Start with the workflow you need: inspect a workspace, send a file, replace a live revision, or move a directory. The clients use the same API as the dashboard.
Pick the right tool
Use TypeScript or Python in trusted server code. Use the CLI for a local folder or CI job. For a browser upload, your server creates the session and the browser only receives the temporary upload URL.
Before you start
assets:read to inspect and assets:write to upload or replace.STEADYLINK_API_KEY in your server environment. Do not send it to a browser, mobile app, repository, or build output.listBuckets(). The ID selects the destination for new files.@steadylink/sdk on npm, and the Python client is available as steadylink on PyPI.TypeScript
Use the TypeScript client in Node 20+ or another server runtime with fetch. It requires exactly one credential: an API key or a short-lived user access token.
npm install @steadylink/sdkimport { SteadyLink } from "@steadylink/sdk";
const steadylink = new SteadyLink({
apiKey: process.env.STEADYLINK_API_KEY!,
// workspaceId is optional for an API key. Keys already belong to one workspace.
timeoutMs: 30_000,
maxRetries: 2,
});
const { items: buckets } = await steadylink.listBuckets();
const bucket = buckets.find((item) => item.slug === "marketing");
if (!bucket) throw new Error("Marketing bucket not found");import { readFile } from "node:fs/promises";
const data = await readFile("./public/campaign-hero.webp");
const upload = await steadylink.uploadFile(bucket.id, {
filename: "campaign-hero.webp",
path: "campaign/",
size: data.byteLength,
contentType: "image/webp",
data,
});
console.log(upload); // finalization has started; follow its status until it is readyconst data = await readFile("./public/campaign-hero-v2.webp");
const result = await steadylink.replaceFile(
bucket.id,
"campaign/campaign-hero.webp",
{
filename: "campaign-hero-v2.webp",
size: data.byteLength,
contentType: "image/webp",
data,
},
);
console.log(result.version); // the new revision numberimport { SteadyLinkError, SteadyLinkNetworkError } from "@steadylink/sdk";
try {
await steadylink.listBuckets();
} catch (error) {
if (error instanceof SteadyLinkError) {
console.error(error.status, error.code, error.requestId, error.detail);
} else if (error instanceof SteadyLinkNetworkError) {
console.error(error.message);
}
}Python
The Python client is synchronous and has no runtime dependencies. Its upload and replacement helpers create the session, send bytes to the presigned URL, then finalize the session for you.
pip install steadylinkimport os
from pathlib import Path
from steadylink import SteadyLink
client = SteadyLink(
api_key=os.environ["STEADYLINK_API_KEY"],
max_retries=2,
)
buckets = client.list_buckets()["items"]
bucket = next(item for item in buckets if item.get("slug") == "marketing")
file_path = Path("campaign-hero.webp")
upload = client.upload_file(
bucket["id"],
filename=file_path.name,
body=file_path.read_bytes(),
content_type="image/webp",
path="campaign/",
)
print(upload)replacement = Path("campaign-hero-v2.webp")
result = client.replace_file(
bucket["id"],
"campaign/campaign-hero.webp",
filename=replacement.name,
body=replacement.read_bytes(),
content_type="image/webp",
)
print(result["version"])from steadylink import SteadyLinkError, SteadyLinkNetworkError
try:
client.list_buckets()
except SteadyLinkError as error:
print(error.status, error.code, error.request_id, error.detail)
except SteadyLinkNetworkError as error:
print(str(error))CLI
The CLI ships in the SteadyLink source workspace today. It is useful for a one-off migration or a deployment job. It accepts STEADYLINK_API_KEY, or --api-key for a temporary command.
steadylink help
# inspect | upload | replace | migrate | focalexport STEADYLINK_API_KEY="slk_..."
steadylink upload ./public/campaign-hero.webp --bucket "$BUCKET_ID"
steadylink migrate ./public/media --bucket "$BUCKET_ID"steadylink inspect "$ASSET_ID"
steadylink replace ./campaign-hero-v2.webp \
--bucket "$BUCKET_ID" \
--key "campaign/campaign-hero.webp"
steadylink focal "$ASSET_ID" --x 0.42 --y 0.31Retries and browser uploads
Both clients retry 429, 502, 503, and 504 for safe reads. A write retries only when it includes an idempotency key. The upload helpers do this for completion automatically.
For a browser upload, call Create upload batch from your server, return only the session's uploadUrl to the browser, then complete the session from your server. The presigned URL is specifically designed for that direct byte transfer.
Need another path?