TypeScript SDK
@theneuralledger/sdk is a typed client for the intelligence API. It handles authentication, retries, timeouts, and rate limit headers, and its types are generated from the published OpenAPI schema, so responses stay in step with the API.
npm install @theneuralledger/sdkRequires Node 20 or newer, or any runtime with a global fetch.
Quick start
import { TnlClient } from '@theneuralledger/sdk';
const tnl = new TnlClient({ apiKey: process.env.TNL_API_KEY! });
const page = await tnl.listNews({ page_size: 10, sort: 'pipeline' });
for (const story of page.data) {
console.log(story.publishedAt, story.title);
}Client options
const tnl = new TnlClient({
apiKey: process.env.TNL_API_KEY!,
baseUrl: 'https://theneuralledger.com', // default
timeoutMs: 30_000, // default
retries: 2, // retries on 429 and 5xx
userAgent: 'acme-research/1.4', // identify your integration
requestId: crypto.randomUUID(), // echoed back for support
fetch: undefined, // inject your own for tests
});Setting a distinctive userAgent is worth doing — it is what support looks at when tracing a request.
Reading news
// Newest first
const latest = await tnl.listNews({ sort: 'pipeline', page_size: 25 });
// Filtered
const japan = await tnl.listNews({
country: 'Japan',
category: 'Economic & Macro',
published_since: '2026-07-01T00:00:00Z',
});
// Only the fields you need — smaller responses, less quota
const slim = await tnl.listNews({
fields: 'id,title,publishedAt,impactPaths',
page_size: 100,
});Pagination
Cursor pagination is stable while new stories arrive; offsets shift underneath you. Prefer cursors for anything that walks more than one page.
async function* everyStory(since: string) {
let cursor: string | undefined;
do {
const page = await tnl.listNews({ published_since: since, page_size: 100, cursor });
yield* page.data;
cursor = page.page?.next_cursor ?? undefined;
} while (cursor);
}
for await (const story of everyStory('2026-07-01T00:00:00Z')) {
await save(story);
}Search and discovery
const hits = await tnl.searchNews({ q: 'tariff', page_size: 20 });
const entities = await tnl.listEntities({ q: 'Federal Reserve' });
const paths = await tnl.listImpactPaths({ q: 'oil' });
const byEntity = await tnl.getEntityStories('Bank of Korea');
const byAsset = await tnl.getAssetStories('KRW');
const byPath = await tnl.getImpactPathStories('policy rate -> currency');Saved searches
const saved = await tnl.createSavedSearch({
name: 'JP macro',
query: { country: 'Japan', category: 'Economic & Macro' },
});
const results = await tnl.getSavedSearchResults(saved.data.id);
await tnl.updateSavedSearch(saved.data.id, { name: 'Japan macro' });
await tnl.deleteSavedSearch(saved.data.id);Ledger AI Terminal
const answer = await tnl.askAiTerminal({
question: 'What drove the won this week?',
});
console.log(answer.data.text);Answers are grounded in indexed stories and cite their sources. This consumes AI quota rather than ordinary request quota — see plans.
Rate limits
After any call, lastRateLimit carries what the server reported:
await tnl.listNews({ page_size: 1 });
console.log(tnl.lastRateLimit); // { limit, remaining, resetAt }The client already retries 429 and 5xx responses with backoff, honouring Retry-After. Use lastRateLimit to pace bulk work before you get throttled:
if ((tnl.lastRateLimit?.remaining ?? Infinity) < 10) {
await new Promise((r) => setTimeout(r, 60_000));
}Errors
import { TnlError, TnlRateLimitError, TnlAuthenticationError } from '@theneuralledger/sdk';
try {
await tnl.listNews({ page_size: 1 });
} catch (error) {
if (error instanceof TnlRateLimitError) {
// exhausted after the built-in retries
} else if (error instanceof TnlAuthenticationError) {
// key missing, revoked, or wrong tenant
} else if (error instanceof TnlError) {
console.error(error.status, error.code, error.requestId);
} else {
throw error;
}
}Include requestId when reporting a problem — it identifies the exact request in our logs.
Other methods
getNews(idOrSlug) for a single story, plus getAccount, getFilters, getFeed, getMarkets, listSavedSearches, getSavedSearch. TnlTimeoutError is raised when a request exceeds timeoutMs. Full parameters are in the API reference; the SDK mirrors it and the types are generated from the same schema.