Skip to main content
The @signa-so/sdk package is a typed, ergonomic client for the Signa API: full types for every endpoint and response, automatic pagination, built-in retries, and typed error classes.
The SDK is designed for server-side use. A Signa API key grants full access to your org’s data; putting one in browser code exposes it to every visitor. Proxy requests through your own backend instead.

Install

npm install @signa-so/sdk
Requires Node.js 18+ or Bun 1.0+. TypeScript 5.0+ is recommended but not required.

Configure

import { Signa } from '@signa-so/sdk';

const signa = new Signa({
  api_key: process.env.SIGNA_API_KEY,
  // Optional overrides
  base_url: 'https://api.signa.so', // default
  timeout: 30_000,                  // 30s default
  max_retries: 2,                   // default, retries on 429/5xx
});
If you omit api_key, the client reads SIGNA_API_KEY from the environment:
export SIGNA_API_KEY=sig_your_key_here
// Uses SIGNA_API_KEY automatically
const signa = new Signa();

Resources

The client organizes the API into 19 resource namespaces:
NamespaceDescription
signa.trademarksSearch, retrieve, history, batch lookup, related marks, proceedings, coverage, media
signa.ownersOwner profiles, trademark portfolios, GLEIF corporate relationships
signa.entitiesResolved entities: one company across all offices, trademarks, corporate family
signa.attorneysAttorney profiles, trademark portfolios, client lists
signa.firmsLaw firm profiles, attorneys, trademark portfolios
signa.proceedingsOppositions, cancellations, and other tribunal proceedings
signa.suggestCross-entity typeahead across trademarks, owners, attorneys, and firms
signa.referencesClassifications, offices, jurisdictions, event types, design codes, deadline and opposition rules
signa.goodsServicesGoods & services term catalog and AI-assisted specification drafting
signa.deadlinesBatch maintenance-deadline computations
signa.oppositionsBatch opposition-window computations
signa.reconcileCompare your own records against register data
signa.portfoliosPortfolio CRUD, member marks, deadlines
signa.savedSearchesSaved search CRUD and re-execute
signa.watchesWatch CRUD, pause/resume, preview, bulk create, diagnostics
signa.alertsRead-only alert listing, retrieval, and bulk lookup
signa.webhooksWebhook endpoint CRUD, secret rotation, test deliveries, delivery audit
signa.eventsOrg event stream: list and retrieve with diffs
signa.organizationAccount identity, usage, API key management, request logs

Search and list trademarks

search() takes a text query with structured filters under filters, plus options for aggregations and totals:
const results = await signa.trademarks.search({
  query: 'SIGNA',
  strategies: ['exact', 'phonetic'],
  filters: { jurisdictions: ['US', 'EU'], nice_classes: [9, 42] },
  options: { aggregations: ['office_code'], include_total: true },
});

for (const hit of results.data) {
  console.log(hit.mark_text, hit.score);
}
console.log(results.aggregations);
console.log(results.search_meta);
list() is for filter-only or simple-query listing. Its filters are flat top-level params, not nested:
const page = await signa.trademarks.list({
  offices: ['uspto'],
  status_primary: 'active',
  filing_date_gte: '2024-01-01',
  sort: '-filing_date',
  limit: 50,
});
Both return a SignaList, see Pagination below.

Retrieve and batch

const tm = await signa.trademarks.retrieve('tm_8kLm2nPq');
console.log(tm.mark_text, tm.status.primary);

// Embed the 50 most recent prosecution events inline
const withHistory = await signa.trademarks.retrieve('tm_8kLm2nPq', { include: ['history'] });
Look up multiple trademarks in one call, by Signa ID or office identifier (max 100 per call):
const result = await signa.trademarks.batch({ ids: ['tm_8kLm2nPq', 'tm_9jNq3rTw'] });

console.log(result.data);      // trademarks that matched
console.log(result.not_found); // IDs or identifiers that didn't match

Pagination

Every list and search method returns a SignaList<T>, which supports three consumption patterns. The first page is fetched eagerly; later pages are fetched lazily. Async iteration, the simplest approach:
for await (const tm of signa.trademarks.list({ offices: ['uspto'] })) {
  console.log(tm.mark_text);
}
Collect to an array with toArray(). A safety cap of 10,000 items applies by default; pass { limit } to change it:
const page = await signa.trademarks.list({ jurisdictions: ['US'], status_primary: 'active' });
const allMarks = await page.toArray();          // up to 10,000
const first500 = await page.toArray({ limit: 500 });
Manual paging, for full control over when the next request fires:
let page = await signa.trademarks.list({ offices: ['uspto'], limit: 100 });

console.log(`Page 1: ${page.data.length} items`);
console.log(`Request ID: ${page.request_id}`);

while (page.has_more) {
  page = await page.getNextPage();
  console.log(`Next page: ${page.data.length} items`);
}
getNextPage() returns an empty list (not an error) once there are no more pages. Every SignaList exposes data, has_more, request_id, and, on search responses, search_meta and aggregations. There is no public pagination field on the list itself, use has_more and getNextPage() to drive pagination rather than reaching for a cursor directly.

Error handling

All errors extend SignaError. API errors (4xx/5xx) extend SignaAPIError and carry a typed subclass per status code:
SignaError
├── SignaAPIError
│   ├── BadRequestError        400
│   ├── AuthenticationError    401
│   ├── PermissionError        403
│   ├── NotFoundError          404
│   ├── ConflictError          409
│   ├── RateLimitError         429 (has retry_after)
│   └── InternalServerError    5xx
├── ConnectionError            DNS, TCP, TLS failures
└── TimeoutError                request exceeded timeout
Use instanceof to handle specific error types:
import { Signa } from '@signa-so/sdk';

const signa = new Signa({ api_key: process.env.SIGNA_API_KEY });

try {
  const tm = await signa.trademarks.retrieve('tm_invalid');
} catch (err) {
  if (err instanceof Signa.NotFoundError) {
    console.log('Trademark not found');
  } else if (err instanceof Signa.RateLimitError) {
    console.log(`Rate limited, retry after ${err.retry_after}s`);
  } else if (err instanceof Signa.AuthenticationError) {
    console.log('Invalid API key');
  } else if (err instanceof Signa.SignaAPIError) {
    console.log(`API error ${err.status}: ${err.message}`);
  } else if (err instanceof Signa.ConnectionError) {
    console.log('Network issue:', err.message);
  } else if (err instanceof Signa.TimeoutError) {
    console.log('Request timed out');
  }
}
Every SignaAPIError carries the structured error body plus the request ID:
try {
  await signa.trademarks.list({ offices: ['invalid_office'] });
} catch (err) {
  if (err instanceof Signa.BadRequestError) {
    console.log(err.error.type);   // machine-readable slug, e.g. "validation_error"
    console.log(err.error.detail); // human-readable detail
    console.log(err.request_id);   // include this in support requests
  }
}

Automatic retries

Error typeRetried?
ConnectionErrorYes
TimeoutErrorYes
RateLimitError (429)Yes, after the retry_after delay
InternalServerError (5xx)Yes, unless the error body says retryable: false
BadRequestError (400)No
AuthenticationError (401)No
NotFoundError (404)No
An explicit retryable: false in the server’s error body overrides the status-based rule: a deterministic failure like the watch preview’s 504 timeout is not retried, since a blind retry would re-run the same over-budget work. Retries use exponential backoff with jitter.
const signa = new Signa({
  api_key: process.env.SIGNA_API_KEY,
  max_retries: 3, // default: 2, set to 0 to disable
});
Override retry behavior per request:
const tm = await signa.trademarks.retrieve('tm_8kLm2nPq', undefined, { max_retries: 0 });

Timeouts

The default timeout is 30 seconds. Configure it globally or per request:
const signa = new Signa({ api_key: process.env.SIGNA_API_KEY, timeout: 60_000 });

const tm = await signa.trademarks.retrieve('tm_8kLm2nPq', undefined, { timeout: 10_000 });

Debug mode

const signa = new Signa({ api_key: process.env.SIGNA_API_KEY, debug: true });
Logs each request and response (method, URL, status, timing) to stderr.