# 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 ```bash npm install @socialhose/api ``` Requires Node 18+ or a custom `fetch` implementation. ## Basic setup ```ts 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 ```ts 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 ```ts const campaigns = await socialhose.getCampaigns(); for (const campaign of campaigns) { console.log(campaign.id, campaign.name, campaign.status); } ``` ## Search mentions ```ts 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 ```ts 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 ```ts 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 ```ts 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()`: ```ts 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 ```ts 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. ```ts 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.