Files
2026-05-29 14:57:34 -05:00

4.9 KiB

Usage Guide

What this SDK is

@socialhose/api is a TypeScript client for the Socialhose Public API. It is built for backend services, scripts, serverless functions, and dashboards that need campaign analytics, mention search, mailing-list management, and term-level entity analytics.

The SDK handles:

  1. API-key authentication.
  2. Typed endpoint helpers.
  3. Timeouts, retries, and request cancellation.
  4. GET caching with an injectable cache interface.
  5. Entity analytics assembled from /mentions/ when native analytics endpoints are campaign-scoped.

Install

npm install @socialhose/api

Requires Node 18+ or a custom fetch implementation.

Getting API access

See the repository API access notes for subscription and key-provisioning details. This SDK only consumes an existing key; it cannot create, rotate, or discover keys for you.

Use your provided Public API key and confirm which campaigns it can access. Then set it in your server environment:

export SOCIALHOSE_API_KEY="sh_your_key_here"

Keep this value server-side. For browser applications, create your own backend endpoint that uses this SDK and returns sanitized data to the frontend.

Basic setup

import { SocialhoseClient } from '@socialhose/api';

const socialhose = new SocialhoseClient({
  apiKey: process.env.SOCIALHOSE_API_KEY!,
});

Keep the API key server-side. Do not instantiate this client in browser code.

Production setup

const socialhose = new SocialhoseClient({
  apiKey: process.env.SOCIALHOSE_API_KEY!,
  timeoutMs: 10_000,
  retries: 3,
  cacheTtlMs: 60_000,
});

Recommendations:

  • Keep the default browser-like user-agent unless you have verified an alternative works.
  • Use a shared cache such as Redis for multi-process or serverless deployments.
  • Reduce entity batch concurrency if you see 429 responses.
  • Use revalidateSeconds for dashboards so repeated views do not fan out fresh requests.

List campaigns

const campaigns = await socialhose.getCampaigns();
for (const campaign of campaigns) {
  console.log(campaign.id, campaign.name, campaign.status);
}

Search mentions

const page = await socialhose.getMentions({
  campaign_ids: 'campaign-id',
  content_search: 'hospital',
  platforms: 'twitter,reddit',
  sentiments: 'negative',
  ordering: '-published_at',
});

console.log(page.count);
console.log(page.results[0]?.content);

Fetch campaign dashboard analytics

const filters = { campaign_ids: 'campaign-id', date_from: '2026-05-01' };

const [overview, timeline, sentiment, platforms, topMentions] = await Promise.all([
  socialhose.getOverview(filters),
  socialhose.getTimeline({ ...filters, interval: 'day' }),
  socialhose.getSentiment(filters),
  socialhose.getPlatforms(filters),
  socialhose.getTopMentions({ ...filters, limit: 10 }),
]);

Analyze a term or entity

const stats = await socialhose.getEntityStats('RSF', 'campaign-id', {
  revalidateSeconds: 900,
});

console.log({
  total: stats.total,
  sentiment: stats.sentiment,
  platformMix: stats.platformMix,
  momentumPct: stats.momentumPct,
  topUrls: stats.sample.slice(0, 3).map((m) => m.url),
});

Use getEntityBrief() for cheap cards/lists and getEntityStats() for detail pages.

Batch entity briefs

const briefs = await socialhose.getEntityBriefs(
  ['Burhan', 'Hemedti', 'SAF', 'RSF'],
  'campaign-id',
  5,
  { revalidateSeconds: 3600 },
);

Failed terms are skipped. Lower concurrency if rate limits are visible.

Pagination

getCampaigns() and getMailingLists() return first-page arrays. getMentions() exposes a page filter.

For manual pagination, use get():

let page = 1;
while (true) {
  const response = await socialhose.get('/mentions/', { page, content_search: 'cholera' });
  // process response.results
  if (!response.next) break;
  page += 1;
}

Error handling

import { SocialhoseError } from '@socialhose/api';

try {
  await socialhose.getOverview({ campaign_ids: 'bad-id' });
} catch (error) {
  if (error instanceof SocialhoseError) {
    console.error({ status: error.status, path: error.path, body: error.body });
  } else {
    throw error;
  }
}

Caching

GET requests are cached; POST requests are not.

await socialhose.getMentions(
  { content_search: 'sudan' },
  { revalidateSeconds: 900 },
);

The default cache is process-local. Use a persistent/shared cache for production dashboards and rate-limit control.

Operational pitfalls

  • Entity analytics are request-heavy. One getEntityStats() call can issue roughly 20+ requests.
  • The API rate limit is roughly 60 requests/minute per API key.
  • The entity timeline uses cumulative differencing intentionally to avoid inclusive date_to double-counting.
  • Exact entity sentiment/platform values are used only when facet counts reconcile with the known total.
  • 409 mailing-list conflicts are normalized to { outcome: 'already' }; other non-OK responses throw.