For AI agents: the complete documentation index is available at https://docs.clickmax.io/en/llms.txt, the full documentation bundle is available at https://docs.clickmax.io/en/llms-full.txt, and this page is available as Markdown at https://docs.clickmax.io/en/reference/api/sdk.md.
  • English
  • How to use the Clickmax TypeScript SDK

    The @clickmax/public-sdk package calls the Clickmax API from JavaScript or TypeScript code. Each endpoint has a typed method, and each call returns a result that holds either the value or the error.

    Before you start, you need:

    • a workspace API key, created by an owner or admin under Settings > Connections > API (details in Clickmax API authentication);
    • a runtime with fetch and AbortSignal.any, such as Node.js 22 or later, Deno, Bun, or Cloudflare Workers;
    • a project that uses ES modules, because the package has no CommonJS build.
    Keep the key on the server

    The key acts on behalf of the whole workspace. Use the SDK only on a server and load the key from an environment variable or a secret manager. Never include the key in code that runs in a browser or a mobile app.

    Make your first call

    Install the package

    npm
    yarn
    pnpm
    bun
    deno
    npm install @clickmax/public-sdk

    Create the client

    import { Clickmax } from '@clickmax/public-sdk'
    
    const clickmax = new Clickmax(process.env.CLICKMAX_API_KEY!)

    The second constructor argument takes options that apply to every call made through the instance:

    const clickmax = new Clickmax(process.env.CLICKMAX_API_KEY!, {
      headers: { 'x-request-source': 'tag-sync' }, // sent with every request
      timeout: 60_000, // milliseconds; default 60000, 0 disables it
      fetch: globalThis.fetch, // default
    })

    The constructor is the only part of the SDK that throws. It throws a TypeError when the key is empty or malformed or when an option is invalid.

    Call an endpoint

    Methods follow the endpoint path: /tags/list becomes clickmax.tags.list() and /tags/manual-list becomes clickmax.tags.manualList(). Endpoints without a resource are methods of the client itself, such as /whoami, which becomes clickmax.whoami().

    The first argument is the endpoint input, with the same fields as the interactive reference:

    const created = await clickmax.tags.create({ name: 'VIP', color: 'ff8800' })

    Endpoints without input, such as clickmax.tags.list(), do not take that argument.

    Handle the result

    Methods never throw and never reject. Read the result as an object:

    const result = await clickmax.tags.list()
    
    if (!result.ok) {
      const { type, code, requestId } = result.error
      console.error('tags.list failed', { type, code, requestId })
    } else {
      console.log(result.value.data)
    }

    Or destructure it as an [ok, error, value] tuple:

    const [ok, error, tags] = await clickmax.tags.list()
    
    if (!ok) {
      console.error('tags.list failed', {
        type: error.type,
        code: error.code,
        requestId: error.requestId,
      })
    } else {
      console.log(tags.data)
    }

    In both forms, TypeScript knows that value is set when ok is true and that error is set when ok is false.

    Handle each error type

    The error of a failed result is a ClickmaxError, which extends Error:

    const result = await clickmax.tags.create({ name: 'VIP' })
    
    if (!result.ok) {
      const { error } = result
    
      switch (error.type) {
        case 'invalid_request':
          console.error('Input rejected', {
            op: 'tags.create',
            code: error.code,
            issues: error.issues,
          })
          break
        case 'authentication':
          console.error('Check the key, its environment, and its allowed IP list', {
            op: 'tags.create',
            code: error.code,
            requestId: error.requestId,
          })
          break
        case 'rate_limit':
          console.error('Rate limit reached', {
            op: 'tags.create',
            retryAfterSeconds: error.retryAfter ?? 10,
          })
          break
        default:
          console.error('tags.create failed', {
            op: 'tags.create',
            type: error.type,
            code: error.code,
            message: error.message,
            requestId: error.requestId,
          })
      }
    }

    The type, code, requestId, and issues fields come from the API error body, and their possible values are listed in Clickmax API errors. The error also has status (the HTTP status, or 0 when no response arrived), message (text for logs that can change between versions), retryAfter (the seconds from the Retry-After header, when the API sends it), and raw (the response body as received). When an error response is not JSON, the SDK derives the type from the HTTP status.

    When a request gets no usable response, the SDK uses its own types:

    typeWhen it happens
    networkfetch failed before a response arrived, for example with no connection or a DNS failure.
    timeoutThe call took longer than the configured timeout.
    abortedThe signal you passed was aborted.
    parseThe response was successful, but its body is not valid JSON.

    When the SDK rejects an argument before sending the request, such as a negative timeout or a body that cannot be converted to JSON, the result fails with type invalid_request, code invalid_argument, and status 0.

    When you ask support for help, include the error.requestId.

    Retry after the request limit

    All keys of a workspace share the limit of 100 requests every 10 seconds. When it is exceeded, the result fails with type rate_limit, and retryAfter says how many seconds to wait:

    async function listTags() {
      for (let attempt = 0; attempt < 3; attempt++) {
        const result = await clickmax.tags.list()
    
        if (result.ok || result.error.type !== 'rate_limit') return result
    
        await new Promise((resolve) => setTimeout(resolve, (result.error.retryAfter ?? 10) * 1000))
      }
    
      return clickmax.tags.list()
    }

    Retry automatically on rate_limit errors. On api, network, and timeout errors, retry with backoff only when repeating the call is safe. An invalid_request, authentication, or permission error comes back the same until the request or the account changes.

    Change the options of a single call

    The last argument of every method accepts signal, timeout, headers, and fetch. Each option replaces the instance value for that call only:

    const controller = new AbortController()
    
    await clickmax.tags.list({ signal: controller.signal, timeout: 5_000 })
    
    await clickmax.tags.create(
      { name: 'VIP' },
      { headers: { 'x-request-id': crypto.randomUUID() } },
    )

    Per-call headers are applied over the instance headers. The Authorization header always uses the instance key and cannot be changed per call.

    Use several workspaces

    Each instance keeps its own key and options, and instances share no state. Create one instance per workspace:

    const storeA = new Clickmax(process.env.STORE_A_API_KEY!)
    const storeB = new Clickmax(process.env.STORE_B_API_KEY!)
    
    const [resultA, resultB] = await Promise.all([storeA.tags.list(), storeB.tags.list()])

    Validate data with zod

    The @clickmax/public-sdk/zod subpath exports zod schemas for the input and the successful response of each endpoint. Using them is optional: the client does not import these schemas and does not validate input before sending the request. To use them, install zod 4 (4.1.13 or a later 4.x) in your project:

    npm
    yarn
    pnpm
    bun
    deno
    npm install zod

    A schema name joins the resource and the method in PascalCase, followed by a suffix:

    SchemaContentsExample
    <Name>BodyRequest body of a POST or DELETE endpoint, including reads with nested input, which use POSTTagsCreateBody for clickmax.tags.create()
    <Name>QueryParamsQuery parameters of a GET endpointTagsManualListQueryParams for clickmax.tags.manualList()
    <Name>ResponseSuccessful responseTagsListResponse for clickmax.tags.list()

    The interactive reference shows the HTTP method of each endpoint. Methods of the client itself use only the method name, such as WhoamiResponse for clickmax.whoami().

    import { TagsCreateBody } from '@clickmax/public-sdk/zod'
    
    const input = TagsCreateBody.safeParse(formData)
    
    if (!input.success) {
      console.error('Invalid tag', { op: 'tags.create', issues: input.error.issues })
    } else {
      await clickmax.tags.create(input.data)
    }

    The schemas are written with zod/mini, and your bundler includes only the schemas you import in your build.

    Update the package

    Each package version matches the v0 API at the time it was published. Because v0 can still change, pin the version you tested and test your integration before upgrading.