REFERENCE

TypeScript SDK

@cleo-legal/sdk gives typed methods for search, documents, translation, changes, customs lookups, duties, landed cost, compliance checks, sanctions and webhooks, typed errors, and webhook signature verification. The client uses native fetch and is ESM only. 0.7.0 (npm) has no runtime dependencies; 0.9.0 (GitHub release) installs csv-parse and zod, which the catalog connectors (@cleo-legal/sdk/connectors) use.

Install

Version 0.9.0 adds customs classification, batches, dossiers, human review, the full compliance decision, webhook V2 verification and the catalog connectors. It is not on the npm registry yet (npm registry publication is pending; npm still serves 0.7.0). Install it today from the GitHub release:

terminal · 0.9.0
# @cleo-legal/sdk 0.9.0, from the GitHub release
npm install https://github.com/Cleo-Labs-IA/cleo-customs-examples/releases/download/sdk-v0.9.0/cleo-legal-sdk-0.9.0.tgz
terminal · npm registry
# the npm registry still serves 0.7.0 (no customs classification, review or connectors)
npm install @cleo-legal/sdk

Runnable examples (cURL, TypeScript, Python: needs_information, the full decision, a batch with Idempotency-Key, human review, signed webhooks) are in cleo-customs-examples.

Use

TypeScript
import { LegalData } from '@cleo-legal/sdk';

const ld = new LegalData({ apiKey: process.env.CLEO_API_KEY! });

// Legal search
const search = await ld.search({ q: 'GDPR Article 5', country: 'EU', limit: 5 });
console.log(search.data[0].title);

// Customs candidates for a description
const lookup = await ld.customs.lookup({ description: 'centrifugal pump', country: 'KZ' });

Retries are yours

By default the SDK does not retry, by design: you choose the policy. A 429 rejects with RateLimitError, which exposes retryAfter in seconds. In 0.9.0 (GitHub release) you can opt in with the retry option; it is off unless you pass it. For POST calls, send an Idempotency-Key so a retry replays instead of running (and charging) twice.

TypeScript
import { RateLimitError } from '@cleo-legal/sdk';

async function withRetry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
  for (let i = 0; i < attempts; i++) {
    try { return await fn(); }
    catch (err) {
      if (err instanceof RateLimitError && i < attempts - 1) {
        await new Promise((r) => setTimeout(r, (err.retryAfter ?? 2 ** i) * 1000));
        continue;
      }
      throw err;
    }
  }
  throw new Error('unreachable');
}

Customs classification, review and connectors 0.9.0 · GitHub release, npm pending

Classification, catalog batches, dossiers, human review, the full compliance decision and the catalog connectors ship in @cleo-legal/sdk 0.9.0, installed from the GitHub release above (npm registry publication pending). Without the SDK, the REST endpoints work with any fetch; the Quickstart has the curl.

TypeScript · REST, no SDK
// Works today with any fetch, no SDK needed
const res = await fetch('https://api.legaldata.cleolabs.co/v2/customs/classifications', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.CLEO_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ item_id: 'SKU-TS-100', description: 'Men’s knitted cotton T-shirt', country: 'FR' }),
});
TypeScript · 0.9.0 (GitHub release)
// @cleo-legal/sdk 0.9.0 (GitHub release)
const res = await ld.customs.classify({
  item_id: 'SKU-TS-100',
  description: 'T-shirt en coton, maille (tricoté), 100 % coton, pour hommes',
  country: 'FR',
  facts: { process: 'knitted', composition: [{ material: 'cotton', percent: 100 }], audience: 'men' },
});
console.log(res.data.status, res.advisory_disclaimer);
TypeScript · 0.9.0 (GitHub release)
// @cleo-legal/sdk 0.9.0 (GitHub release) — POST /v2/compliance/check, 5 units
const { data } = await ld.compliance.check({
  product: {
    item_id: 'SKU-TS-100',
    description: 'Men’s knitted T-shirt, 100 % cotton',
    facts: { process: 'knitted', composition: [{ material: 'cotton', percent: 100 }], audience: 'men' },
  },
  origin_country: 'BD',
  destination_country: 'FR',
});
console.log(data.decision.readiness, data.decision.blockers);
TypeScript · 0.9.0 (GitHub release)
// @cleo-legal/sdk 0.9.0 (GitHub release) — human review
await ld.customs.classifications.review(classificationId, {
  decision: 'approved',               // or 'rejected' | 'changes_requested'
  reviewer: 'broker@example.com',
  comment: 'Knitted, 100 % cotton, men',
});
const history = await ld.customs.classifications.reviews(classificationId);

// A batch item, then only the approved rows for write-back
await ld.customs.batches.reviewItem(jobId, 0, { decision: 'approved', reviewer: 'broker@example.com' });
const csv = await ld.customs.batches.itemsCsv(jobId, { approvedOnly: true });
terminal · 0.9.0 (GitHub release)
# @cleo-legal/sdk 0.9.0 (GitHub release) — dry-run unless --apply,
# approved codes only unless --no-require-approval
npx @cleo-legal/sdk connectors --help

The connectors pull a Shopify catalog into a batch CSV and write codes back, and convert Odoo, SAP GTS and WooCommerce CSV exports. Write-back takes only human-approved codes by default (--require-approval). The Shopify connector has not been run against a live store yet, and the SAP GTS profile is marked unverified. The customs guide describes the review rules.

Webhooks: verifyWebhookSignature checks X-Cleo-Signature; 0.9.0 (GitHub release) adds verifyWebhook (a typed event) and verifyWebhookV2, which checks X-Cleo-Signature-V2 and rejects a timestamp more than 300 seconds from your clock by default. See webhooks.

Every endpoint, with its request and response schema, is in the REST reference. Not every endpoint has an SDK method; the REST call always works.