ChottuLink deep links

Create a ChottuLink dynamic deep link from your server.

Set credentials

Pass apiKey and domain directly, or set them as environment variables. Use env vars in production to keep secrets out of code.

The key is read from BDK_CHOTTULINK_API_KEY, then CHOTTULINK_API_KEY. The domain is read from BDK_CHOTTULINK_DOMAIN, then CHOTTULINK_DOMAIN, then CHOTTULINK_LINK_DOMAIN. An explicit value always wins over the environment.

The API key is a secret. Never ship it to the browser or commit it to source control.

// Reads BDK_CHOTTULINK_API_KEY / CHOTTULINK_API_KEY for the key,
// and BDK_CHOTTULINK_DOMAIN / CHOTTULINK_DOMAIN / CHOTTULINK_LINK_DOMAIN for the domain.
import { createChottuLink } from "@bdk/native/server/chottulink";

const result = await createChottuLink({
  destinationUrl: "https://example.com/invite/abc"
});

Input options

Every field you can pass to createChottuLink. Only destinationUrl is required; apiKey and domain are required either here or via the environment.

  • destinationUrl: string — where the link resolves to. Gets https:// added if no scheme is present.
  • apiKey?: string — ChottuLink API key. Falls back to env vars.
  • domain?: string — the link domain. Falls back to env vars; protocol and trailing slashes are stripped.
  • linkName?: string — a human-readable name. Defaults to selectedPath, then to "BDK Native Deeplink".
  • selectedPath?: string — custom path segment; a leading / is removed and the value trimmed.
  • iosBehavior?: 1 | 2 — iOS open behavior. Defaults to 2.
  • androidBehavior?: 1 | 2 — Android open behavior. Defaults to 2.
  • utm?: ChottuLinkUtm — UTM attribution (source, medium, campaign, term, content), all optional.
  • social?: ChottuLinkSocial — social preview (title, description, imageUrl), all optional.
  • urlParams?: Record<string, string | number | boolean | undefined | null> — query params appended onto destinationUrl (empty/null/undefined values are skipped).
  • extraParams?: Record<string, unknown> — raw fields merged into the request body for options not modeled here.
  • baseUrl?: string — override the API base. Defaults to https://api2.chottulink.com/chotuCore/pa/v1.
  • fetch?: FetchLike — a custom fetch (for testing or non-Node runtimes).
import { createChottuLink } from "@bdk/native/server/chottulink";

const result = await createChottuLink({
  apiKey: process.env.CHOTTULINK_API_KEY,
  domain: "links.example.com",
  destinationUrl: "https://example.com/products/42",
  linkName: "summer-promo",
  selectedPath: "/promo/summer",
  iosBehavior: 2,
  androidBehavior: 1,
  urlParams: { ref: "newsletter", discount: 20 },
  utm: {
    source: "newsletter",
    medium: "email",
    campaign: "summer_sale"
  },
  social: {
    title: "Summer Sale",
    description: "Up to 50% off",
    imageUrl: "https://cdn.example.com/sale.png"
  }
});

Add UTM, social preview, and custom params

Use utm and social to attach attribution and rich link previews. Empty values are dropped, so you only send what you set.

Use urlParams to append query parameters onto the destination URL itself. For any request-body field not modeled here, use extraParams.

const result = await createChottuLink({
  destinationUrl: "https://example.com/landing",
  // appended to the destination URL: ...?ref=app&v=3
  urlParams: { ref: "app", v: 3 },
  // merged into the raw request body for unmodeled options
  extraParams: { custom_field: "value" }
});

Read the result

The resolved value is a ChottuLinkResult with three fields:

  • dynamicLink: string | null — the generated link (the API's short_url, falling back to long_url), or null.
  • errorMessage: string | null — an error message from the API response, or null.
  • raw: unknown — the full, unmodified parsed response.

Check dynamicLink for null and inspect errorMessage before using the link.

const { dynamicLink, errorMessage, raw } = await createChottuLink({
  destinationUrl: "https://example.com/share"
});

if (errorMessage || !dynamicLink) {
  console.error("ChottuLink failed", errorMessage, raw);
} else {
  console.log("Deep link:", dynamicLink);
}

Handle errors

createChottuLink throws a BdkError (importable from @bdk/native) when a required field is missing (BDK_VALIDATION_ERROR) or the request fails (BDK_PROVIDER_ERROR). For failed requests, details carries the HTTP status and response body.

A transport or validation failure throws; an application error inside a successful response surfaces as result.errorMessage instead.

import { createChottuLink } from "@bdk/native/server/chottulink";
import { BdkError } from "@bdk/native";

try {
  const result = await createChottuLink({
    destinationUrl: "https://example.com/share"
  });
  // ...use result.dynamicLink
} catch (err) {
  if (err instanceof BdkError) {
    // err.code === "BDK_VALIDATION_ERROR" | "BDK_PROVIDER_ERROR"
    console.error(err.code, err.message, err.details);
  }
  throw err;
}