Documentation

esc
    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.

    TypeScript
    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

    Terminal
    $ npm install @pantechdynamics/sdk

    Authenticate

    Make an API key and put it in PANTECH_API_KEY. The client reads it.

    Terminal
    $ export PANTECH_API_KEY=PAN_…

    Without a key, new Pantech() throws. Or pass options:

    TypeScript
    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

    create.ts
    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.

    TypeScript
    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:

    TypeScript
    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:

    TypeScript
    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:

    TypeScript
    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.

    Was this page helpful?

    Updated