Skip to main content

Installation

npm install @chat-ads/chatads-sdk

Quick Start

import { ChatAdsClient } from '@chat-ads/chatads-sdk';

const client = new ChatAdsClient({
  apiKey: process.env.CHATADS_API_KEY!,
  baseUrl: 'https://api.getchatads.com'
});

// Using analyzeMessage (string + options)
const response = await client.analyzeMessage(
  "What are the best noise-cancelling headphones?",
  { country: "US" }
);

if (response.error === null && response.data?.returned > 0) {
  // Access first offer
  const offer = response.data.offers[0];
  console.log(`link_text: ${offer.link_text}`);
  console.log(`url: ${offer.url}`);

  // Or iterate all offers
  response.data.offers.forEach((offer, i) => {
    console.log(`Offer ${i + 1}: ${offer.link_text} - ${offer.url}`);
  });
}

Configuration Options

import { ChatAdsClient } from '@chat-ads/chatads-sdk';

const client = new ChatAdsClient({
  apiKey: 'cak_your_api_key',                    // Required
  baseUrl: 'https://api.getchatads.com',         // Required: API base URL
  timeoutMs: 10000,                              // Optional: request timeout (default: 10000)
  maxRetries: 2,                                 // Optional: retry attempts (default: 0)
  retryBackoffFactorMs: 500,                     // Optional: backoff between retries
  raiseOnFailure: true,                          // Optional: throw on API errors
  fetchImplementation: customFetch,              // Optional: custom fetch for Node 16
  logger: console,                               // Optional: debug logging
});

Methods

analyze

Analyze a message using a payload object.
const response = await client.analyze({
  message: "Looking for a good yoga mat",
  country: "US",
  quality: "standard"              // fast | standard | best
});

analyzeMessage

Convenience method that takes a message string directly.
// Simple usage
const response = await client.analyzeMessage("Looking for a good yoga mat");

// With options
const response = await client.analyzeMessage(
  "Looking for a good yoga mat",
  {
    country: "US",
    quality: "standard"
  }
);

Response Types

The SDK exports the following types from @chat-ads/chatads-sdk:
import type {
  ChatAdsResponseEnvelope,
  AnalyzeData,
  Offer,
  Product,
  ChatAdsError,
  ChatAdsMeta,
  UsageInfo
} from '@chat-ads/chatads-sdk';

// Response envelope returned by analyze() and analyzeMessage()
interface ChatAdsResponseEnvelope {
  data?: AnalyzeData | null;
  error?: ChatAdsError | null;
  meta: ChatAdsMeta;
}

interface AnalyzeData {
  status: "filled" | "partial_fill" | "no_offers_found" | "internal_error";  // Response status
  offers: Offer[];              // Array of affiliate offers (only contains filled offers)
  requested: number;            // Number of offers requested
  returned: number;             // Number of offers returned
}

interface Offer {
  link_text: string;             // Text to use for the affiliate link
  url: string;                   // Affiliate URL (always populated)
  confidence_level: string;      // Confidence classification (low, medium, high)
  product?: Product;             // Product metadata
}

interface Product {
  title?: string;               // Product title from search
  description?: string;         // Product description
  stars?: number;               // Product rating (e.g., 4.5)
  reviews?: number;             // Number of reviews
}

interface ChatAdsError {
  code: string;
  message: string;
  details?: Record<string, unknown>;
}

interface ChatAdsMeta {
  request_id: string;
  timestamp?: string;
  version?: string;
  country?: string | null;
  timing_ms?: Record<string, number> | null;
  usage?: UsageInfo | null;
}

interface UsageInfo {
  monthly_requests: number;
  is_free_tier: boolean;
  free_tier_limit?: number | null;
  free_tier_remaining?: number | null;
  daily_requests?: number | null;
  daily_limit?: number | null;
}

Error Handling

The SDK exports two error classes for typed error handling:
import {
  ChatAdsClient,
  ChatAdsAPIError,
  ChatAdsSDKError
} from '@chat-ads/chatads-sdk';

try {
  const response = await client.analyzeMessage("Looking for headphones");

  // Check response-level errors (when raiseOnFailure is false)
  if (response.error !== null) {
    switch (response.error?.code) {
      case 'DAILY_LIMIT_EXCEEDED':
      case 'MONTHLY_LIMIT_EXCEEDED':
        // Rate limit hit - wait for reset
        break;
      case 'UNAUTHORIZED':
        // Check API key
        break;
      default:
        console.error(response.error?.message);
    }
  }
} catch (error) {
  // ChatAdsAPIError: HTTP errors (4xx, 5xx) or logical failures (when raiseOnFailure is true)
  if (error instanceof ChatAdsAPIError) {
    console.error('API Error:', error.statusCode, error.response?.error);
  }
  // ChatAdsSDKError: Configuration, validation, or transport errors
  else if (error instanceof ChatAdsSDKError) {
    console.error('SDK Error:', error.message);
  }
  else {
    console.error('Unexpected error:', error);
  }
}

Framework Examples

Next.js API Route

// app/api/affiliate/route.ts
import { ChatAdsClient } from '@chat-ads/chatads-sdk';
import { NextResponse } from 'next/server';

const client = new ChatAdsClient({
  apiKey: process.env.CHATADS_API_KEY!,
  baseUrl: process.env.CHATADS_BASE_URL!
});

export async function POST(request: Request) {
  const { message } = await request.json();

  const response = await client.analyzeMessage(message, { country: "US" });

  return NextResponse.json(response);
}

Express.js

import express from 'express';
import { ChatAdsClient } from '@chat-ads/chatads-sdk';

const app = express();
app.use(express.json());

const client = new ChatAdsClient({
  apiKey: process.env.CHATADS_API_KEY!,
  baseUrl: process.env.CHATADS_BASE_URL!
});

app.post('/analyze', async (req, res) => {
  const response = await client.analyzeMessage(req.body.message);
  res.json(response);
});