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:
- API-key authentication.
- Typed endpoint helpers.
- Timeouts, retries, and request cancellation.
- GET caching with an injectable cache interface.
- 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
Socialhose API keys are provisioned by Socialhose. This SDK only consumes an existing key; it cannot create, rotate, or discover keys for you.
Ask the Socialhose team or your account administrator for a 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
429responses. - Use
revalidateSecondsfor 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_todouble-counting. - Exact entity sentiment/platform values are used only when facet counts reconcile with the known total.
409mailing-list conflicts are normalized to{ outcome: 'already' }; other non-OK responses throw.