> ## Documentation Index
> Fetch the complete documentation index at: https://whalescorp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration instruction

> This guide is intended for implementing the technical Holders WebView integration into the partner’s product.

# Integration Architecture Flowchart

<img src="https://mintcdn.com/whalescorp/sYcwF1WqD1mDpark/images/Screenshot2026-01-26at18.50.25(1).png?fit=max&auto=format&n=sYcwF1WqD1mDpark&q=85&s=361edaa262f2422e975ef7fc85303181" alt="Screenshot2026 01 26at18 50 25(1)" width="673" height="775" data-path="images/Screenshot2026-01-26at18.50.25(1).png" />

# API endpoints

### Backend API

| Environment | Endpoint |
| :- | :- |
| **Production** | `https://card-prod.whales-api.com` |
| **Staging/Testnet** | `https://card-staging.whales-api.com` |

### Web Application URLs

| Environment | URL\* |
| :- | :- |
| **Production** | `https://yourwallet.holders.io` |
| **Staging/Testnet** | `https://yourwallet-stage.holders.io` |

\*Instead of yourwallet - URLs with your wallet name will be implemented.

# Authentication process

## General authentication flow

<img src="https://mintcdn.com/whalescorp/sYcwF1WqD1mDpark/images/Screenshot2026-01-26at19.10.25.png?fit=max&auto=format&n=sYcwF1WqD1mDpark&q=85&s=9aefade0a7d013625b9e87e9ed01cbda" alt="Screenshot2026 01 26at19 10 25" width="629" height="903" data-path="images/Screenshot2026-01-26at19.10.25.png" />

## Proof Structure

For authentication, the [TonConnect v2](https://github.com/ton-connect) protocol is used. It is necessary to create proof (proof of wallet ownership) for TON and optionally for Solana.

### **TON Proof Structure**

```
interface TonProof {
  timestamp: number;           // Unix timestamp in seconds
  domain: {
    lengthBytes: number;       // Domain length in bytes
    value: string;             // Domain (for example, "holders.io")
  };
  signature: string;           // Base64 signature
  payload: string;             // Arbitrary payload from the server
  walletStateInit: string;     // Wallet StateInit in base64
  publicKey: string;           // Public key in hex
}
```

### **TON Proof Creation Algorithm**

```
// 1. Construct the message to sign
const messageBuffer = Buffer.concat([
  Buffer.from('ton-proof-item-v2/'),
  addressBuffer,           // workchain (4 bytes BE) + hash (32 bytes)
  domainLengthBuffer,      // 4 bytes LE
  domainBuffer,            // domain string
  timestampBuffer,         // 8 bytes LE (Int64)
  Buffer.from(payload)     // payload string
]);

// 2. Hash it
const message = sha256(messageBuffer);

// 3. Add prefix
const bufferToSign = Buffer.concat([
  Buffer.from('ffff', 'hex'),
  Buffer.from('ton-connect'),
  message
]);

// 4. Sign
const signature = nacl.sign.detached(sha256(bufferToSign), secretKey);
```

**Solana Proof Structure**

```
interface SolanaProof {
  timestamp: number;
  domain: {
    lengthBytes: number;
    value: string;
  };
  signature: string;        // Base58 encoded signature
  payload: string;
  publicKey: string;        // Base58 public key
}
```

### Authentication request format

```
// Request for TON + Solana
type TonSolanaAuthRequest = [
  {
    stack: 'ton';
    network: 'ton-mainnet' | 'ton-testnet';
    key: {
      kind: 'tonconnect-v2';
      wallet: 'yourwallet';
      config: {
        address: string;          // Raw address format
        proof: TonProof;
      };
    };
    inviteId?: string;            // Optional invite code
    invitationId?: string;        // Optional invitation ID
    appsflyerId?: string;         // AppsFlyer UID for analytics
  },
  {
    stack: 'solana';
    network: 'solana-mainnet' | 'solana-devnet';
    key: {
      kind: 'tonconnect-v2';
      wallet: 'yourwallet';
      config: {
        address: string;          // Base58 address
        proof: SolanaProof;
      };
    };
  }
];
```

# API methods

## Wallet connection (Enrollment)

**Endpoint:**`POST /v2/user/wallet/connect`\
**Request:**

```
[
  {
    "stack": "ton",
    "network": "ton-mainnet",
    "key": {
      "kind": "tonconnect-v2",
      "wallet": "yourwallet",
      "config": {
        "address": "0:...",
        "proof": {
          "timestamp": 1706284800,
          "domain": { "lengthBytes": 10, "value": "holders.io" },
          "signature": "base64...",
          "payload": "ton-proof-any",
          "walletStateInit": "base64...",
          "publicKey": "hex..."
        }
      }
    },
    "inviteId": "optional-invite-code"
  },
  {
    "stack": "solana",
    "network": "solana-mainnet",
    "key": {
      "kind": "tonconnect-v2",
      "wallet": "yourwallet",
      "config": {
        "address": "base58...",
        "proof": {
          "timestamp": 1706284800,
          "domain": { "lengthBytes": 10, "value": "holders.io" },
          "signature": "base58...",
          "payload": "solana-proof-any",
          "publicKey": "base58..."
        }
      }
    }
  }
]
```

**Response:**

```
{
  "ok": true,
  "token": "jwt-token-string"
}
```

## Getting User State

**Endpoint:**`POST /account/state`\
**Request:**

```
{
  "token": "jwt-token"
}
```

**Response:**

```
{
  "ok": true,
  "state": {
    "state": "ok",
    "notificationSettings": { "enabled": true },
    "suspended": false
  }
}
```

## Accounts list (Private)

**Endpoint:**`POST /v2/account/list`\
**Request:**

```
{
  "token": "jwt-token"
}
```

**Response:**

```
{
  "ok": true,
  "list": [
    {
      "id": "account-id",
      "type": "crypto",
      "accountIndex": 0,
      "address": "EQ...",
      "state": "ACTIVE",
      "balance": "1000000000",
      "network": "ton-mainnet",
      "cards": [
        {
          "id": "card-id",
          "status": "ACTIVE",
          "lastFourDigits": "1234",
          "productId": "product-id"
        }
      ],
      "limits": {
        "daily": "100000000",
        "monthly": "1000000000",
        "onetime": "50000000"
      }
    }
  ],
  "prepaidCards": []
}
```

## Public account data (no authorization required)

**Endpoint:**`POST /v2/public/accounts`\
**Request:**

```
{
  "walletKind": "yourwallet",
  "wallets": [
    {
      "network": "ton-mainnet",
      "address": "EQ..."
    },
    {
      "network": "solana",
      "address": "base58..."
    }
  ]
}
```

**Response:**

```
{
  "ok": true,
  "accounts": [
    {
      "id": "account-id",
      "accountIndex": 0,
      "address": "EQ...",
      "state": "ACTIVE",
      "balance": "1000000000",
      "network": "ton-mainnet",
      "cards": [
        {
          "lastFourDigits": "1234",
          "productId": "product-id"
        }
      ]
    }
  ]
}
```

## Access Check (Invite Check)

**Endpoint:**`POST /v2/invite/wallet/check/v2`\
**Request:**

```
{
  "wallet": "EQ...",
  "network": "ton-mainnet",
  "region": {
    "countryCode": "US",
    "storeFrontCode": "usa"
  },
  "campaignId": "optional-campaign",
  "campaignParams": {}
}
```

**Response:**

```
{
  "allowed": true,
  "banner": {
    "id": 1,
    "content": {
      "action": { "en": "Get Card", "ru": "Получить карту" },
      "title": { "en": "Welcome!", "ru": "Добро пожаловать!" },
      "subtitle": { "en": "...", "ru": "..." }
    }
  }
}
```

## User Profile

**Endpoint:**`POST /v2/profile/get`\
**Request:**

```
{
  "token": "jwt-token"
}
```

**Response:**

```
{
  "ok": true,
  "data": {
    "userId": "user-id",
    "email": "user@example.com",
    "emailVerified": true,
    "phone": "+1234567890",
    "country": "US",
    "firstName": "John",
    "lastName": "Doe"
  }
}
```

## Card Transaction List

**Endpoint:**`POST /v2/card/events`\
**Request:**

```
{
  "token": "jwt-token",
  "cardId": "card-id",
  "limit": 40,
  "cursor": "optional-cursor",
  "order": "desc"
}
```

**Response:**

```
{
  "ok": true,
  "data": {
    "events": [
      {
        "type": "charge",
        "id": "event-id",
        "cardId": "card-id",
        "time": 1706284800,
        "data": {
          "accountId": "account-id",
          "amount": "1000000000",
          "currency": "USD",
          "currencyAmount": "10.00"
        }
      }
    ],
    "cursor": "next-cursor",
    "more": true
  }
}
```

## Apple Pay Credentials

**Endpoint:**`POST /v2/card/provisioning/list`\
**Request:**

```
{
  "token": "jwt-token"
}
```

**Response:**

```
{
  "ok": true,
  "cards": [
    {
      "id": "card-id",
      "lastFourDigits": "1234",
      "title": "Holders Card",
      "cardholderName": "JOHN DOE",
      "assetName": "card-asset",
      "assetUrl": "https://..."
    }
  ]
}
```

# WebView integration

## WebView architecture flowchart

<img src="https://mintcdn.com/whalescorp/sYcwF1WqD1mDpark/images/Screenshot2026-01-26at19.22.37.png?fit=max&auto=format&n=sYcwF1WqD1mDpark&q=85&s=57888614dcabe98ae550222eb7c7acac" alt="Screenshot2026 01 26at19 22 37" width="561" height="863" data-path="images/Screenshot2026-01-26at19.22.37.png" />

You can find a detailed description of the Injected bridge and all its APIs on the [WebView Bridge APIs](/inegration-gides/web-view-bridge-apis) page.

# URL parameters

When loading the Holders WebApp, you need to pass the following query parameters:

```
const queryParams = new URLSearchParams({
  lang: 'en',                    // Language: 'en' | 'ru'
  currency: 'USD',               // Display currency
  theme: 'holders',              // Theme
  'theme-style': 'dark',         // 'dark' | 'light'
  bounceable: 'false',           // Address format
  'initial-route': '/accounts'   // Initial route
});

const url = `https://tonhub.holders.io?${queryParams.toString()}`;
```

### Types

| **Param name** | **Value** |
| :- | :- |
| lang | en |
| currency | currency code |
| theme | theme code |
| theme-style | dark |

**Supported currencies:**

```
const supportedCurrencies = [
  { code: 'USD', symbol: '$', label: 'U.S. Dollar' },
  { code: 'EUR', symbol: '€', label: 'Euro' },
  { code: 'RUB', symbol: '₽', label: 'Russian Ruble' },
  { code: 'GBP', symbol: '£', label: 'British Pound' },
  { code: 'CHF', symbol: '₣', label: 'Swiss Franc' },
  { code: 'CNY', symbol: '¥', label: 'Chinese Yuan' },
  { code: 'KRW', symbol: '₩', label: 'South Korean Won' },
  { code: 'IDR', symbol: 'Rp', label: 'Indonesian Rupiah' },
  { code: 'INR', symbol: '₹', label: 'Indian Rupee' },
  { code: 'JPY', symbol: '¥', label: 'Japanese Yen' }
];
```

## Initial state injection

```
const initialState = {
  user: {
    status: {
      state: 'ok',
      kycStatus: null,
      suspended: false
    },
    token: 'jwt-token'
  },
  accountsList: [...],
  prepaidCards: [...]
};

const injectedJS = `
  window.initialState = ${JSON.stringify(initialState)};
`;
```

### TonConnect Bridge for WebView

```
interface TonConnectInjectedBridge {
  deviceInfo: DeviceInfo;
  protocolVersion: number;
  isWalletBrowser: boolean;
  
  // Connect a new app
  connect(
    protocolVersion: number,
    request: ConnectRequest
  ): Promise<ConnectEvent>;
  
  // Restore an existing connection
  restoreConnection(): Promise<ConnectEvent>;
  
  // Disconnect
  disconnect(): Promise<void>;
  
  // Send requests (transactions, data signing)
  send<T extends RpcMethod>(request: AppRequest<T>): Promise<WalletResponse<T>>;
}
```

## Query API

WebView can control the native application via URL parameters:

| **Parameter** | **Values** | **Description** |
| :- | :- | :- |
| `closeApp` | `true` | Close WebView |
| `openEnrollment` | `true` | Start the registration process |
| `openUrl` | URL | Open a URL in the browser |
| `backPolicy` | `back` / `close` / `lock` | “Back” button behavior |
| `lockScroll` | `true` / `false` | Scroll locking |
| `showKAV` | `true` / `false` | Show keyboard accessory view |

# User states

### User state transition flowchart

<img src="https://mintcdn.com/whalescorp/sYcwF1WqD1mDpark/images/Screenshot2026-01-27at12.43.50.png?fit=max&auto=format&n=sYcwF1WqD1mDpark&q=85&s=ac17b8c8bf0237cdadf0d51bb51ff4e3" alt="Screenshot2026 01 27at12 43 50" width="701" height="885" data-path="images/Screenshot2026-01-27at12.43.50.png" />

## State handling

```
enum HoldersUserState {
  NeedEnrollment = 'need-enrollment',
  NeedPhone = 'need-phone',
  NoRef = 'no-ref',
  NeedKyc = 'need-kyc',
  NeedEmail = 'need-email',
  Ok = 'ok',
}

async function handleUserState(token: string): Promise<void> {
  const state = await fetchUserState(token);
  
  switch (state.state) {
    case HoldersUserState.NeedEnrollment:
      // Show the registration screen
      navigateToEnrollment();
      break;
      
    case HoldersUserState.NoRef:
      // Show the waiting/waitlist screen
      showWaitlistScreen();
      break;
      
    case HoldersUserState.NeedPhone:
      // Redirect to phone verification in WebView
      openHoldersWebView('/phone-verification');
      break;
      
    case HoldersUserState.NeedKyc:
      // Redirect to KYC in WebView
      openHoldersWebView('/kyc');
      break;
      
    case HoldersUserState.NeedEmail:
      // Redirect to email verification in WebView
      openHoldersWebView('/email-verification');
      break;
      
    case HoldersUserState.Ok:
      // Full access
      openHoldersWebView('/accounts');
      break;
  }
}
```

# Code examples

## TypeScript: Full authentication flow

```
import { Address, beginCell, storeStateInit } from '@ton/core';
import { sha256_sync } from '@ton/crypto';
import nacl from 'tweetnacl';
import { Int64LE } from 'int64-buffer';

interface WalletKeys {
  publicKey: Buffer;
  secretKey: Buffer;
}

interface EnrollmentResult {
  success: boolean;
  token?: string;
  error?: string;
}

class HoldersIntegration {
  private endpoint: string;
  private isTestnet: boolean;

  constructor(isTestnet: boolean = false) {
    this.isTestnet = isTestnet;
    this.endpoint = isTestnet 
      ? 'https://card-staging.whales-api.com'
      : 'https://card-prod.whales-api.com';
  }

  /**
   * TON Proof creating
   */
  private createTonProof(
    address: Address,
    keys: WalletKeys,
    domain: string,
    payload: string,
    walletStateInit: string
  ) {
    const timestamp = Math.floor(Date.now() / 1000);
    const timestampBuffer = new Int64LE(timestamp).toBuffer();
    
    const domainBuffer = Buffer.from(domain);
    const domainLengthBuffer = Buffer.allocUnsafe(4);
    domainLengthBuffer.writeInt32LE(domainBuffer.byteLength);

    const rawAddress = address.toRawString();
    const [workchain, addrHash] = rawAddress.split(':');

    const addressWorkchainBuffer = Buffer.allocUnsafe(4);
    addressWorkchainBuffer.writeInt32BE(Number(workchain));

    const addressBuffer = Buffer.concat([
      addressWorkchainBuffer,
      Buffer.from(addrHash, 'hex'),
    ]);

    const messageBuffer = Buffer.concat([
      Buffer.from('ton-proof-item-v2/'),
      addressBuffer,
      domainLengthBuffer,
      domainBuffer,
      timestampBuffer,
      Buffer.from(payload),
    ]);

    const message = sha256_sync(messageBuffer);

    const bufferToSign = Buffer.concat([
      Buffer.from('ffff', 'hex'),
      Buffer.from('ton-connect'),
      message,
    ]);

    const signed = nacl.sign.detached(
      sha256_sync(bufferToSign),
      Uint8Array.from(keys.secretKey)
    );

    return {
      timestamp,
      domain: {
        lengthBytes: domainBuffer.byteLength,
        value: domain,
      },
      signature: Buffer.from(signed).toString('base64'),
      payload,
      walletStateInit,
      publicKey: keys.publicKey.toString('hex'),
    };
  }

  /**
   * Fetching the application manifest
   */
  async getManifest() {
    const manifestUrl = this.isTestnet
      ? 'https://yourwallet-stage.holders.io/jsons/tonconnect-manifest.json'
      : 'https://yourwallet.holders.io/jsons/tonconnect-manifest.json';
    
    const response = await fetch(manifestUrl);
    return response.json();
  }

  /**
   * Wallet connect (enrollment)
   */
  async enrollWallet(
    address: Address,
    keys: WalletKeys,
    walletStateInit: string,
    inviteId?: string
  ): Promise<EnrollmentResult> {
    try {
      const manifest = await this.getManifest();
      const domain = new URL(manifest.url).hostname;
      
      const tonProof = this.createTonProof(
        address,
        keys,
        domain,
        'ton-proof-any',
        walletStateInit
      );

      const requestBody = [
        {
          stack: 'ton',
          network: this.isTestnet ? 'ton-testnet' : 'ton-mainnet',
          key: {
            kind: 'tonconnect-v2',
            wallet: 'yourwallet',
            config: {
              address: address.toRawString(),
              proof: tonProof,
            },
          },
          inviteId,
        },
      ];

      const response = await fetch(`${this.endpoint}/v2/user/wallet/connect`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(requestBody),
      });

      const data = await response.json();

      if (!data.ok) {
        return { success: false, error: 'Failed to fetch user token' };
      }

      return { success: true, token: data.token };
    } catch (error) {
      return { success: false, error: String(error) };
    }
  }

  /**
   * Fetching the user state
   */
  async getUserState(token: string) {
    const response = await fetch(`${this.endpoint}/account/state`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token }),
    });

    if (response.status === 401) {
      return null;
    }

    const data = await response.json();
    
    if (!data.ok) {
      throw new Error('Failed to fetch account state');
    }

    return data.state;
  }

  /**
   * Fetching the account list
   */
  async getAccounts(token: string) {
    const response = await fetch(`${this.endpoint}/v2/account/list`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token }),
    });

    const data = await response.json();

    if (!data.ok) {
      throw new Error('Failed to fetch accounts');
    }

    return {
      accounts: data.list,
      prepaidCards: data.prepaidCards,
    };
  }

  /**
   * Public account data (no authorization)
   */
  async getPublicAccounts(address: string, solanaAddress?: string) {
    const body = solanaAddress
      ? {
          walletKind: 'yourwallet',
          wallets: [
            { network: this.isTestnet ? 'ton-testnet' : 'ton-mainnet', address },
            { network: 'solana', address: solanaAddress },
          ],
        }
      : {
          walletKind: 'yourwallet',
          network: this.isTestnet ? 'ton-testnet' : 'ton-mainnet',
          address,
        };

    const response = await fetch(`${this.endpoint}/v2/public/accounts`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });

    const data = await response.json();

    if (!data.ok) {
      throw new Error('Failed to fetch public accounts');
    }

    return data.accounts;
  }

  /**
   * Access check
   */
  async checkInvite(address: string, countryCode: string) {
    const response = await fetch(`${this.endpoint}/v2/invite/wallet/check/v2`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        wallet: address,
        network: this.isTestnet ? 'ton-testnet' : 'ton-mainnet',
        region: { countryCode },
      }),
    });

    return response.json();
  }
}

// Usage example
async function example() {
  const holders = new HoldersIntegration(false); // Production
  
  // Create a proof and connect the wallet
  const result = await holders.enrollWallet(
    Address.parse('EQ...'),
    { publicKey: Buffer.from('...'), secretKey: Buffer.from('...') },
    'base64-state-init...',
    'optional-invite-code'
  );
  
  if (result.success && result.token) {
    // Save the token
    localStorage.setItem('holders-token', result.token);
    
    // Fetch the state
    const state = await holders.getUserState(result.token);
    console.log('User state:', state);
    
    // Fetch the accounts
    if (state.state === 'ok') {
      const accounts = await holders.getAccounts(result.token);
      console.log('Accounts:', accounts);
    }
  }
}
```

## React Native: WebView component

```
import React, { useRef, useMemo, useCallback } from 'react';
import { View } from 'react-native';
import WebView, { WebViewMessageEvent } from 'react-native-webview';

interface HoldersWebViewProps {
  token: string;
  userState: any;
  accounts?: any[];
  onClose?: () => void;
  isTestnet?: boolean;
}

export function HoldersWebView({
  token,
  userState,
  accounts,
  onClose,
  isTestnet = false,
}: HoldersWebViewProps) {
  const webViewRef = useRef<WebView>(null);

  const baseUrl = isTestnet
    ? 'https://tonhub-stage.holders.io'
    : 'https://tonhub.holders.io';

  const source = useMemo(() => {
    const params = new URLSearchParams({
      lang: 'en',
      currency: 'USD',
      theme: 'holders',
      'theme-style': 'dark',
      'initial-route': '/accounts',
    });

    return { uri: `${baseUrl}?${params.toString()}` };
  }, [baseUrl]);

  // Initial state injection
  const injectedJS = useMemo(() => {
    const initialState = {
      user: {
        status: {
          state: userState.state,
          suspended: userState.suspended || false,
        },
        token,
      },
      accountsList: accounts || [],
    };

    return `
      (function() {
        window.initialState = ${JSON.stringify(initialState)};
      })();
      true;
    `;
  }, [token, userState, accounts]);

  // Handling messages from the WebView
  const handleMessage = useCallback((event: WebViewMessageEvent) => {
    try {
      const message = JSON.parse(event.nativeEvent.data);
      
      switch (message.type) {
        case 'closeApp':
          onClose?.();
          break;
          
        case 'sendTransaction':
          // Transaction handling
          handleTransaction(message.payload);
          break;
          
        case 'loaded':
          // WebView loaded
          console.log('Holders WebView loaded');
          break;
      }
    } catch (error) {
      console.error('Failed to parse WebView message:', error);
    }
  }, [onClose]);

  return (
    <View style={{ flex: 1 }}>
      <WebView
        ref={webViewRef}
        source={source}
        injectedJavaScriptBeforeContentLoaded={injectedJS}
        onMessage={handleMessage}
        allowsInlineMediaPlayback
        javaScriptEnabled
        domStorageEnabled
      />
    </View>
  );
}
```

# Interaction flowcharts

## Full Holders workflow

<img src="https://mintcdn.com/whalescorp/sYcwF1WqD1mDpark/images/Integrationflow(1).png?fit=max&auto=format&n=sYcwF1WqD1mDpark&q=85&s=4ea34aedeb560eeec405e3e47c52676a" alt="Integrationflow(1)" width="2840" height="5224" data-path="images/Integrationflow(1).png" />

## Handling transactions via TonConnect

<img src="https://mintcdn.com/whalescorp/sYcwF1WqD1mDpark/images/Screenshot2026-01-27at13.19.41.png?fit=max&auto=format&n=sYcwF1WqD1mDpark&q=85&s=91235c0b1cc4cb7f3f22c8478cd8b73b" alt="Screenshot2026 01 27at13 19 41" width="920" height="885" data-path="images/Screenshot2026-01-27at13.19.41.png" />

# Push notifications

The Holders platform implements a push notification system that informs users about key operations being performed. For each integration project, it is recommended to individually determine the optimal mechanism for delivering notifications to end users. For questions regarding the configuration of this functionality, please contact the Holders integration manager.

# Data storage

Recommended storage structure\
**Typescript**

```
interface HoldersStorage {
  // JWT token by wallet address
  getToken(address: string): string | null;
  setToken(address: string, token: string): void;
  deleteToken(address: string): void;
  
  // Apple Pay credentials
  getProvisioningCredentials(): ProvisioningCredential[];
  setProvisioningCredentials(creds: ProvisioningCredential[]): void;
  
  // Invite/referral data
  getInviteId(): string | null;
  setInviteId(id: string): void;
  
  // Campaign parameters
  getCampaignParams(): Record<string, string>;
  setCampaignParams(params: Record<string, string>): void;
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.