npm package: @socialinsider/api-client
Description: Official Socialinsider API client for Node.js and browsers
Latest version: 1.0.1

# @socialinsider/api-client

Official TypeScript client for the [Socialinsider API](https://api-docs.socialinsider.io/). Fully typed, zero dependencies, supports both V1 and V2 endpoints.

## Installation

```bash
npm install @socialinsider/api-client
```

If you want to use the Socialinsider API from another language or with a different client library, see the official API documentation at [https://api-docs.socialinsider.io/](https://api-docs.socialinsider.io/).

## Quick Start

```ts
import { SocialinsiderApiClient } from "@socialinsider/api-client";

const client = new SocialinsiderApiClient({
  apiKey: "your-api-key",
});

// List all projects and profiles
const projects = await client.v2.getProfiles();

for (const project of projects) {
  console.log(`${project.projectname}: ${project.profiles.length} profiles`);
}
```

## Concepts

- **Profile** — A social media account tracked in Socialinsider (Facebook page, Instagram profile, Twitter account, etc.).
- **Project** — A logical grouping of profiles.
- **Brand** — Groups related profiles belonging to the same company within a project (e.g. Netflix's Facebook, Instagram, and Twitter under one "Netflix" brand).
- **Campaign (tag)** — Labels applied to posts for grouping and filtering (e.g. "black friday", "product-launch").

## API Versions

The Socialinsider API has two versions. Access them via the `.v1` and `.v2` namespaces:

```ts
// V1
const data = await client.v1.getProfileData({ ... });

// V2 (recommended)
const data = await client.v2.getProfileData({ ... });
```

**Key differences in V2:**

- `getProfileData` **requires** the `projectname` parameter (optional in V1).
- `getPosts` returns a more consistent response format across all platforms.

Both versions share the same endpoints — choose V2 for new integrations.

## API Reference

### `getProfiles(params?)`

Retrieve all projects and their tracked social media profiles. Use the returned `id` and `profile_type` values in all subsequent API calls.

```ts
// All projects
const projects = await client.v2.getProfiles();

// Filter by project name
const projects = await client.v2.getProfiles({ projectname: "My Project" });
```

**Parameters:**

| Name          | Type     | Required | Description                           |
| ------------- | -------- | -------- | ------------------------------------- |
| `projectname` | `string` | No       | Filter results to a specific project. |

**Returns:** `Project[]` — each project contains a `projectname` and an array of `profiles`.

---

### `getBrands(params)`

Retrieve brands defined within a project. Brands group related social profiles belonging to the same company.

```ts
const brands = await client.v2.getBrands({ projectname: "Streaming services" });

for (const brand of brands) {
  console.log(`${brand.brandname}: ${brand.profiles.length} profiles`);
}
```

**Parameters:**

| Name          | Type     | Required | Description                       |
| ------------- | -------- | -------- | --------------------------------- |
| `projectname` | `string` | Yes      | Project to retrieve brands from.  |

**Returns:** `Brand[]` — each brand contains a `brandname` and its `profiles`.

---

### `getCampaigns(params)`

Retrieve campaign tags (used for post filtering) within a project.

```ts
const campaigns = await client.v2.getCampaigns({ projectname: "My Project" });
// => ["#branded", "q4-campaign", "product-launch"]
```

**Parameters:**

| Name          | Type     | Required | Description                         |
| ------------- | -------- | -------- | ----------------------------------- |
| `projectname` | `string` | Yes      | Project to retrieve campaigns from. |

**Returns:** `string[]` — array of campaign names.

---

### `getPosts(params)`

Retrieve posts published by a profile within a date range. Posts are sorted chronologically by `created_time`. Results are paginated with a max of **50 posts per request**.

```ts
const result = await client.v2.getPosts({
  id: "44596321012",
  profile_type: "facebook_page",
  date: {
    start: new Date("2024-01-01").getTime(),
    end: new Date("2024-06-30").getTime(),
    timezone: "Europe/London",
  },
  projectname: "My Project",
  from: 0,
  size: 25,
});

console.log(`Got ${result.returned} of ${result.total} posts`);

for (const post of result.posts) {
  console.log(post.created_time, post.engagement);
}
```

**Parameters:**

| Name           | Type        | Required | Description                                                  |
| -------------- | ----------- | -------- | ------------------------------------------------------------ |
| `id`           | `string`    | Yes      | Profile ID from `getProfiles()`.                             |
| `profile_type`  | `string`    | Yes      | Profile type from `getProfiles()`.                           |
| `date`         | `DateRange` | Yes      | Start/end timestamps (ms) and IANA timezone.                 |
| `projectname`  | `string`    | Yes      | Project the profile belongs to.                              |
| `from`         | `number`    | No       | Pagination offset. Default `0`.                              |
| `size`         | `number`    | No       | Page size, max `50`. Default `50`.                           |
| `campaign_name` | `string`    | No       | Filter to posts tagged with this campaign.                   |

**Returns:** `{ returned, total, from, size, posts }` — paginated post list.

#### Pagination

```ts
let from = 0;
const size = 50;
let total = Infinity;

while (from < total) {
  const page = await client.v2.getPosts({
    id: "44596321012",
    profile_type: "facebook_page",
    date: { start, end, timezone: "Europe/London" },
    projectname: "My Project",
    from,
    size,
  });

  total = page.total;
  from += page.returned;

  for (const post of page.posts) {
    // process each post
  }
}
```

---

### `getProfileData(params)`

Retrieve aggregated daily metrics for a profile over a date range. The returned metrics vary by platform and whether the profile has connected insights.

The response is keyed by **profile ID**, then by **date string** (`"DD-MM-YYYY"`):

```ts
const data = await client.v2.getProfileData({
  id: "44596321012",
  profile_type: "facebook_page",
  date: {
    start: new Date("2024-01-01").getTime(),
    end: new Date("2024-03-31").getTime(),
    timezone: "Europe/London",
  },
  projectname: "My Project", // Required in V2, optional in V1
});

// data = { "44596321012": { "01-01-2024": { date, reactions, followers, ... }, ... } }
for (const [profileId, days] of Object.entries(data)) {
  for (const [date, metrics] of Object.entries(days)) {
    console.log(date, "engagement:", metrics.engagement);
  }
}
```

**Parameters:**

| Name          | Type        | Required    | Description                        |
| ------------- | ----------- | ----------- | ---------------------------------- |
| `id`          | `string`    | Yes         | Profile ID from `getProfiles()`.   |
| `profile_type` | `string`    | Yes         | Profile type from `getProfiles()`. |
| `date`        | `DateRange` | Yes         | Date range for metrics.            |
| `projectname` | `string`    | **V2: Yes** / V1: No | Project the profile belongs to.    |

**Returns:** `Record<string, Record<string, ProfileMetrics>>` — nested object of daily metrics keyed by profile ID and date.

---

### `profileSearch(params)`

Search for a social media profile by its URL. Use this before `addProfile` to get the profile's metadata.

```ts
const result = await client.v2.profileSearch({
  search_string: "www.facebook.com/netflix",
});

if (result.count > 0) {
  const profile = result.profiles[0];
  console.log(`Found: ${profile.name} (${profile.platform})`);
}
```

**Parameters:**

| Name           | Type     | Required | Description                            |
| -------------- | -------- | -------- | -------------------------------------- |
| `search_string` | `string` | Yes      | Profile URL (e.g. `"www.facebook.com/netflix"`). |

**Returns:** `{ profiles, count }` — matched profiles with platform, type, name, handle, URL, and ID.

---

### `addProfile(params)`

Add a social media profile to your Socialinsider account. After adding, the profile is scheduled for a data refresh — historical data is typically available within 10 minutes.

```ts
// 1. Search for the profile
const search = await client.v2.profileSearch({
  search_string: "www.facebook.com/netflix",
});

// 2. Add it to your project
const added = await client.v2.addProfile({
  profile_url: search.profiles[0].profile_url,
  profile_type: search.profiles[0].profile_type,
  projectname: "My Project",
  history_refresh_months: 6,
});

console.log(`Added ${added.name} — data will be ready soon.`);
```

**Parameters:**

| Name                   | Type     | Required | Description                                     |
| ---------------------- | -------- | -------- | ----------------------------------------------- |
| `profile_url`           | `string` | Yes      | Profile URL from `profileSearch()`.              |
| `profile_type`          | `string` | Yes      | Profile type from `profileSearch()`.             |
| `projectname`          | `string` | Yes      | Project to add the profile to.                   |
| `history_refresh_months` | `number` | No       | Months of historical data to fetch. Default `12`. |

**Returns:** `AddedProfile` — the added profile's details including `name`, `handle`, `canAdd`, and `profile_added` timestamp.

---

### `deleteProfile(params)`

Delete a profile from your Socialinsider account. Permanently removes the profile and its data from the specified project.

```ts
await client.v2.deleteProfile({
  id: "netflix",
  profile_type: "instagram_profile",
  projectname: "My Project",
});
```

**Parameters:**

| Name          | Type     | Required | Description                        |
| ------------- | -------- | -------- | ---------------------------------- |
| `id`          | `string` | Yes      | Profile ID from `getProfiles()`.   |
| `profile_type` | `string` | Yes      | Profile type from `getProfiles()`. |
| `projectname` | `string` | Yes      | Project the profile belongs to.    |

**Returns:** `void`

---

### `getInstagramStories(params)`

Retrieve Instagram stories published by an authorized profile within a date range. Stories are sorted chronologically. Paginated with a max of **50 stories per request**.

**Important:** Only works for authorized Instagram business profiles (`instagram_profile_own`). Stories are not available for competitor profiles or for historical periods before the profile was authorized.

```ts
const result = await client.v2.getInstagramStories({
  id: "socialinsider.io",
  profile_type: "instagram_profile_own",
  date: {
    start: new Date("2024-01-01").getTime(),
    end: new Date("2024-01-31").getTime(),
    timezone: "Europe/London",
  },
});

for (const story of result.stories) {
  console.log(story.created_time, story.type);
}
```

**Parameters:**

| Name          | Type        | Required | Description                                        |
| ------------- | ----------- | -------- | -------------------------------------------------- |
| `id`          | `string`    | Yes      | Profile ID. Must be an `instagram_profile_own`.     |
| `profile_type` | `string`    | Yes      | Must be `"instagram_profile_own"`.                  |
| `date`        | `DateRange` | Yes      | Start/end timestamps (ms) and IANA timezone.        |
| `from`        | `number`    | No       | Pagination offset. Default `0`.                     |
| `size`        | `number`    | No       | Page size, max `50`. Default `50`.                  |

**Returns:** `{ returned, total, from, size, stories }` — paginated story list.

## Configuration

### Client Options

```ts
const client = new SocialinsiderApiClient({
  // Required: your API key (sent as Bearer token)
  apiKey: "your-api-key",

  // Optional: override the base URL (for staging/proxy)
  baseUrl: "https://app.socialinsider.io/api",

  // Optional: custom fetch implementation
  fetch: customFetchFn,
});
```

## Error Handling

All API errors throw a `SocialinsiderApiError` with structured information:

```ts
import { SocialinsiderApiClient, SocialinsiderApiError } from "@socialinsider/api-client";

try {
  await client.v2.getProfiles();
} catch (error) {
  if (error instanceof SocialinsiderApiError) {
    console.error("Message:", error.message);
    console.error("HTTP status:", error.statusCode);   // e.g. 401, 500
    console.error("RPC error:", error.rpcError);        // JSON-RPC error object
  }
}
```

## Supported Platforms

| Platform  | Profile Type(s)                                              |
| --------- | ------------------------------------------------------------ |
| Facebook  | `facebook_page`, `facebook_page_own`, `facebook_ad_account_own` |
| Instagram | `instagram_profile`, `instagram_profile_own`                 |
| Twitter   | `twitter_profile`, `twitter_profile_own`                     |
| LinkedIn  | `linkedin_page`                                              |
| TikTok    | `tiktok_profile`                                             |
| YouTube   | `youtube_channel`                                            |

Profile types with `_own` suffix indicate authenticated profiles with access to private insights (reach, impressions, demographics, stories, etc.).

## TypeScript

The package ships with full type definitions. All request parameters, response objects, and platform-specific post/metric types are exported:

```ts
import type {
  // Common
  Profile,
  Project,
  Brand,
  DateRange,
  ProfileType,

  // Posts (per platform)
  FacebookPost,
  InstagramPost,
  InstagramStory,
  TwitterPost,
  LinkedInPost,
  TikTokPost,
  YouTubePost,

  // Metrics (per platform)
  FacebookMetrics,
  InstagramMetrics,
  TwitterMetrics,

  // Request/Response
  GetPostsParams,
  GetPostsResponse,
  GetProfileDataResponse,
} from "@socialinsider/api-client";
```

## Requirements

- Node.js >= 18 (uses global `fetch`)
- Works in browsers and edge runtimes with native `fetch`

## License

Apache-2.0 — see [LICENSE](./LICENSE) for details.