Easy Labs
SDKsNode.js

Authentication

How to authenticate requests from your server.

@easylabs/node authenticates with a single secret API key. The SDK attaches it to every outbound request as the x-easy-api-key header. There is no JWT flow, no OAuth, and no per-request key — createClient takes the key once and the resolved client carries it for its lifetime.

Keep keys server-side. @easylabs/node is a server-side package — createClient performs a startup GET /validate-key against your secret API key, so it must never run in a browser bundle. Two methods on the client (validateEmbeddedCheckoutSession and confirmEmbeddedCheckoutSession) authenticate with the embedded session's client_secret instead of the API key and have the x-easy-api-key header suppressed automatically — but you still call them from server code, then forward the result to the iframe over your own endpoint. If you want the iframe to talk straight to the Easy API, hit POST /embedded-checkout/validate and POST /embedded-checkout/confirm with fetch — the SDK isn't in that path.

Initializing with an API key

import { createClient } from "@easylabs/node";

const easy = await createClient({
  apiKey: process.env.EASY_API_KEY!,
});

The SDK picks the API base URL from the key prefix:

Key prefixEnvironmentBase URL
sk_test_…Sandboxhttps://sandbox-api.itseasy.co/v1/api
anything elseLivehttps://api.itseasy.co/v1/api

createClient calls GET /validate-key before returning, so a missing or revoked key throws synchronously at startup rather than later from a real request.

Rotating keys

The SDK doesn't hot-swap keys — createClient resolves once. To rotate without downtime:

  1. Generate a new key in the dashboard.
  2. Roll your deployment with the new value in EASY_API_KEY. New processes pick up the new key on next createClient call.
  3. Once the old fleet has drained, revoke the previous key from the dashboard.

If you need to swap keys at runtime (rare — usually only in tests), discard the old client object and call createClient again.

Multi-tenant authentication

For platforms that act on behalf of multiple merchants, each merchant has its own API key. Keep one client per merchant and cache it for the lifetime of the request, the worker, or — if memory allows — the process:

import { createClient } from "@easylabs/node";

const cache = new Map<string, ReturnType<typeof createClient>>();

export function clientFor(merchantId: string, apiKey: string) {
  let pending = cache.get(merchantId);
  if (!pending) {
    pending = createClient({ apiKey }).catch((err) => {
      // A rejected promise would otherwise poison the cache forever —
      // evict so the next call re-runs key validation.
      cache.delete(merchantId);
      throw err;
    });
    cache.set(merchantId, pending);
  }
  return pending; // Promise<EasyClient>
}

Because createClient validates the key on construction, the .catch above evicts the entry on a transient validation failure (network blip, brief 5xx) so a single bad startup doesn't permanently lock the merchant out. If you also want to evict when a later request returns 401, drop the entry from cache in your own error handler.

The __internal_api_url option exists only for internal Easy Labs testing and is intentionally undocumented in the public API surface — production code should never set it.

On this page