@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.
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');
}
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' }),
});
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.