Home Uncategorized

Node SDK

Last updated on Apr 27, 2026

Node SDK reference

Pair this with the Node.js setup tutorial. The SDK exposes a typed LinkMeClient for creating and managing links programmatically.

Package: @li-nk.me/node-sdk

Installation

npm install @li-nk.me/node-sdk
import LinkMeClient from '@li-nk.me/node-sdk';

CommonJS usage

const LinkMeClient = require('@li-nk.me/node-sdk').default;

Client options

const linkme = new LinkMeClient({
  apiKey: process.env.LINKME_SERVER_KEY, // Optional for read-only usage
  fetch: customFetchImplementation,      // Required only in Node < 18
});
Option Type Description
apiKey string Server/API key with can_write scope for link management.
fetch typeof fetch Provide your own fetch when running on Node versions without global fetch.

Models

The package re-exports its TypeScript models:

  • Link — the full link entity returned by the API.
  • CreateLinkInput — camelCase input for creating links.
  • UpdateLinkInput — snake_case partial update payload matching the API schema.
  • NodeSDKOptions — constructor options for LinkMeClient.

Link

interface Link {
  id: string;
  app_id: string;
  domain_id?: string | null;
  slug: string;
  deep_link_path?: string | null;
  deep_link_params?: string | null;
  ios_custom_url?: string | null;
  android_custom_url?: string | null;
  web_fallback_url?: string | null;
  allow_param_passthrough: 0 | 1;
  force_redirect_web: 0 | 1;
  og_title?: string | null;
  og_description?: string | null;
  og_image_url?: string | null;
  utm?: string | null;
  utm_override?: string | null;
  internal?: 0 | 1;
  enabled: 0 | 1;
  click_count: number;
  last_click_at?: string | null;
  created_at?: string;
}

CreateLinkInput

type CreateLinkInput = {
  appId: string;
  slug?: string;
  deepLink?: string | null;
  redirects?: {
    ios?: string | null;
    android?: string | null;
    web?: string | null;
    forceWeb?: boolean;
  };
  utm?: Partial<Record<UTMField, string>>;
  utmPresetId?: string;
  utmOverrides?: Partial<Record<UTMField, boolean>>;
  allowParamPassthrough?: boolean;
  displayInPortal?: boolean;
  customData?: Record<string, string | number | boolean | null | undefined>;
  og?: { title?: string; description?: string; imageUrl?: string };
};

Where UTMField is 'utm_source' | 'utm_medium' | 'utm_campaign' | 'utm_term' | 'utm_content' | 'utm_id' | 'utm_source_platform' | 'utm_creative_format' | 'utm_marketing_tactic' | 'tags'.

UpdateLinkInput

Uses snake_case field names and 0 | 1 for boolean flags, matching the API schema directly:

type UpdateLinkInput = Partial<Pick<Link,
  'deep_link_path' | 'ios_custom_url' | 'android_custom_url' | 'web_fallback_url' |
  'allow_param_passthrough' | 'force_redirect_web' | 'og_title' | 'og_description' |
  'og_image_url' | 'utm' | 'utm_override' | 'enabled'
>>;

Zod Schemas

The SDK also exports Zod schemas and their inferred types for runtime validation:

Schema Inferred type Description
LinkSchema LinkParsed Core link entity.
ExtendedLinkSchema ExtendedLinkParsed Link with computed fields (hostname, idUrl, slugUrl, clicks, installs).
CreateLinkInputSchema CreateLinkInputParsed Validates createLink input.
UpdateLinkInputSchema UpdateLinkInputParsed Validates updateLink payload.
CreateLinkResponseSchema CreateLinkResponseParsed Shape returned by createLink.
LinkMeWebhookEnvelopeSchema LinkMeWebhookEnvelopeParsed Webhook envelope structure.
import { LinkSchema, CreateLinkInputSchema } from '@li-nk.me/node-sdk';

Webhook Helper Functions

The SDK includes generic helper functions for webhook receivers:

  • parseLinkMeWebhookEnvelope(payload) — validates the webhook JSON envelope using LinkMeWebhookEnvelopeSchema.
  • verifyLinkMeWebhookSignature(rawBody, signatureHeader, secret) — verifies X-LinkMe-Signature using HMAC-SHA256.
import {
  parseLinkMeWebhookEnvelope,
  verifyLinkMeWebhookSignature,
} from '@li-nk.me/node-sdk';

const rawBody = req.rawBody.toString('utf8');
if (!verifyLinkMeWebhookSignature(rawBody, req.get('X-LinkMe-Signature'), process.env.LINKME_WEBHOOK_SIGNING_SECRET!)) {
  res.status(401).json({ ok: false, error: 'Invalid signature' });
  return;
}

const envelope = parseLinkMeWebhookEnvelope(JSON.parse(rawBody));
// forward `envelope` to your own destination (queue, analytics provider, warehouse, etc.)

Methods

createLink(input: CreateLinkInput)

Creates a new short link under an app.

displayInPortal behavior:

  • false hides the link from /portal/app/<appId>/links (still works as a universal link).
  • true keeps it visible in the portal list.
  • In current Node SDK versions, if omitted, displayInPortal defaults to false.
  • For older SDK/API clients that omit this field, server compatibility keeps links visible.

Returns: Promise<{ id: string; app_id: string; domain_id: string | null; slug: string; slugUrl: string }>

await linkme.createLink({
  appId: 'app_123',
  slug: 'spring',
  displayInPortal: true,
  redirects: {
    ios: 'https://apps.apple.com/...',
    android: 'https://play.google.com/...',
    web: 'https://example.com/spring',
  },
});

getLink(id: string)

Fetches a single link by slug or ID.

Returns: Promise<Link>

listLinks(appId: string)

Returns every link under the given app with computed extras.

Returns: Promise<Array<Link & { hostname?: string | null; idUrl?: string; slugUrl?: string; clicks?: number; installs?: number }>>

updateLink(id: string, updates: UpdateLinkInput)

Applies a partial update using snake_case field names and 0 | 1 for boolean flags.

Returns: Promise<Link>

await linkme.updateLink('spring', {
  web_fallback_url: 'https://example.com/spring-2025',
  force_redirect_web: 1,
});

deleteLink(id: string)

Deletes a link. Use with caution—deletions are permanent.

await linkme.deleteLink('spring');

HTTP behavior

  • LinkMeClient uses fetch under the hood. Supply your own implementation if you run on Node < 18.
  • Requests are sent to /api/... on https://li-nk.me and automatically include Authorization: Bearer <apiKey> when provided.
  • Input/output payloads are validated with Zod before being returned, so runtime errors surface early when a shape is wrong.

For lower-level access (custom routes beyond link management) call the REST endpoints directly using the REST Endpoints & OpenAPI reference as a guide.