SDKs / JavaScript
JavaScript and TypeScript SDK
Install @pantechdynamics/sdk, create a client, make a machine and wait for it, and handle errors, pages and retries.
import { Pantech } from "@pantechdynamics/sdk";
const pantech = new Pantech();
const me = await pantech.me.get();
console.log(me.organization_id);@pantechdynamics/sdk is the official JavaScript library, with TypeScript types generated from the API's OpenAPI spec. It has no runtime dependencies and uses the built-in fetch and Web Crypto, so it runs on Node 18 or later, Bun, Deno and edge runtimes. It ships as ESM and CommonJS.
Request and response fields are exactly as the API sends them (plan_slug, next_cursor); method names are camelCase.
Install
$ npm install @pantechdynamics/sdkAuthenticate
Make an API key and put it in PANTECH_API_KEY. The client reads it.
$ export PANTECH_API_KEY=PAN_…Without a key, new Pantech() throws. Or pass options:
const pantech = new Pantech({
apiKey: process.env.MY_PANTECH_KEY,
baseURL: "https://api.pantechdynamics.com/public/v1", // or PANTECH_API_URL
maxRetries: 3, // the default
timeout: 60_000, // per attempt, in milliseconds (the default)
});The other options are fetch (your own fetch), defaultHeaders and userAgent. Every method also takes per-call options last: { signal, timeout, maxRetries, idempotencyKey, headers }.
Create a machine and wait for it
import { Pantech } from "@pantechdynamics/sdk";
const pantech = new Pantech();
const order = await pantech.instances.create({
name: "web-01",
plan_slug: "starter",
image_slug: "ubuntu-24-04",
ssh_key_id: "sshk_…",
});
// Creating a machine places an order: payment, then provisioning.
// wait() resolves once it is provisioned and its create operation is done.
await pantech.instanceOrders.wait(order);
const instance = await pantech.instances.get(order.instance_id);
console.log(instance.name, instance.public_ipv4);A failed or unpaid order rejects with OrderFailedError. Read real slugs from the catalogue first: pantech.plans.list(), pantech.images.list() and pantech.regions.list(). Databases work the same way, with pantech.databaseOrders.wait(order).
Resources
Each part of the API is a property on the client: me, regions, plans, images, diskOfferings, databaseEngines, kubernetesVersions, pricing, usage, billing, instances, instanceOrders, networks (with subnets and firewallRules), publicIps (with portForwardingRules), loadBalancers, kubernetes (with nodePools and addons), securityGroups, volumes, snapshots, databases, databaseOrders, sshKeys, webhooks and operations.
pantech.me.get() describes the key; pantech.me.revoke() revokes it.
Errors
Every error the SDK throws is a PantechError, with status, code, title, detail, requestId and errors (the field errors of a 422). Each status has its own subclass: BadRequestError (400), AuthenticationError (401), PaymentRequiredError (402), PermissionDeniedError (403), NotFoundError (404), ConflictError (409), ValidationError (422), RateLimitError (429), InternalServerError (5xx), and APIConnectionError and APITimeoutError when there is no answer. isPantechError(err, code) checks the code.
import { isPantechError, NotFoundError, PantechError } from "@pantechdynamics/sdk";
try {
await pantech.instances.get("vm_…");
} catch (err) {
if (err instanceof NotFoundError) console.log("no such machine");
else if (isPantechError(err, "INSUFFICIENT_SCOPE")) console.log("the key lacks a scope");
else if (err instanceof PantechError) console.log(err.code, err.detail, err.requestId);
else throw err;
}Act on code, never the wording. Every code.
Pages
list() returns one page ({ data, next_cursor }). listAll() is an async iterator that follows next_cursor for you:
for await (const instance of pantech.instances.listAll()) {
console.log(instance.name);
}Operations
Most changes return an operation. Wait for it before you rely on the result:
import { OperationFailedError } from "@pantechdynamics/sdk";
const accepted = await pantech.instances.stop("vm_…");
try {
const op = await pantech.operations.wait(accepted); // an id, or the 202 body
console.log(op.status); // "succeeded"
} catch (err) {
if (err instanceof OperationFailedError) console.log(err.code, err.detail);
else throw err;
}wait polls GET /operations/{id} every 2 seconds. It resolves when the operation has succeeded, rejects with OperationFailedError when it has failed, and with WaitTimeoutError after 20 minutes. Options: { timeoutMs, pollIntervalMs, signal, onUpdate }. pantech.operations.stream(id) follows it with Server-Sent Events instead.
Idempotency and retries
Every POST, PUT, PATCH and DELETE gets an Idempotency-Key automatically. The same key is sent on every retry, so the change happens once.
The client retries network errors, timeouts, 429 (after Retry-After), 500, 502, 503 and 504, up to 3 times (maxRetries) with a growing, random wait. It sends once the calls the API does not replay by key: creating and deleting SSH keys, opening an instance console, issuing a volume key credential, testing, deleting, rotating the secret of and redelivering a webhook, and me.revoke(). A 429 is still retried, since nothing ran. The list.
Calling any endpoint
request calls a path directly, with the same auth, retries and errors:
const page = await pantech.request({ method: "GET", path: "/instances", query: { limit: 10 } });Webhooks
verifyWebhook({ secret, header, body }) checks a delivery's signature with Web Crypto, so it is async: it resolves when the signature is valid and rejects with WebhookVerificationError when it is not. Verify webhooks with the SDKs.