{"_id":"@cleo-legal/sdk","_rev":"6-fb3c3255fc42ac8f74447478121abf77","name":"@cleo-legal/sdk","dist-tags":{"latest":"0.7.0"},"versions":{"0.1.0":{"name":"@cleo-legal/sdk","version":"0.1.0","keywords":["legal","compliance","regulation","law","gdpr","eurlex","legifrance","api","sdk","typescript","rag"],"author":{"url":"https://cleolabs.co","name":"Cleo Labs","email":"hello@cleolabs.co"},"license":"MIT","_id":"@cleo-legal/sdk@0.1.0","maintainers":[{"name":"alexblochia","email":"alex.bloch55@gmail.com"}],"homepage":"https://legaldata-public.cleolabs.co","bugs":{"url":"https://github.com/Cleo-Labs-IA/cleo-legal-api/issues"},"dist":{"shasum":"de143d98fbe896f52e81e381e90a8371ea7d33ef","tarball":"https://registry.npmjs.org/@cleo-legal/sdk/-/sdk-0.1.0.tgz","fileCount":8,"integrity":"sha512-PhDEReh1BjFC6QmeNLe6vhq/G1a/MI37PKZw8eCJuE1+Cvyop+OPgRreTQnFhHHQWLsm0VQ8wmnjw/zlk/NbAw==","signatures":[{"sig":"MEUCIQC1X7SVGxKHZVxQKVqt4HEQMIyw+mK0NmfQ/7SvPsgKFAIgOiU0n1rENm0hLYagQd7FBM2poOffazThXasw6/D7IPg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15933},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"alexblochia","email":"alex.bloch55@gmail.com"},"repository":{"url":"git+https://github.com/Cleo-Labs-IA/cleo-legal-api.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.12.1","description":"Official TypeScript SDK for the LegalData by Cleo public API — search 50+ jurisdictions, retrieve legal documents, stream changes.","directories":{},"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1778611984096_0.44500095301543485","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@cleo-legal/sdk","version":"0.2.0","keywords":["legal","compliance","regulation","law","gdpr","eurlex","legifrance","api","sdk","typescript","rag"],"author":{"url":"https://cleolabs.co","name":"Cleo Labs","email":"hello@cleolabs.co"},"license":"MIT","_id":"@cleo-legal/sdk@0.2.0","maintainers":[{"name":"alexblochia","email":"alex.bloch55@gmail.com"}],"homepage":"https://legaldata-public.cleolabs.co","bugs":{"url":"https://github.com/Cleo-Labs-IA/cleo-legal-api/issues"},"dist":{"shasum":"cd58653329347a424a2220c84822d6f13e7a6731","tarball":"https://registry.npmjs.org/@cleo-legal/sdk/-/sdk-0.2.0.tgz","fileCount":10,"integrity":"sha512-CjrYGSOcF81R5YmB7X5vm/wLfN2uI0Bx31JmNHafp6xmMXZN77X7v7UZ5bUALgDr8NNyIRy5aDV33oFKUn2nlA==","signatures":[{"sig":"MEQCIA27nbDn0PRbnOlZq+oGLy7rM7/JY6HCqDRnmBMi2gcYAiBOSmaKM5VbctA40GdxQ0JbMuNIunxmljUKUedjVVbv7g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41535},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"14af681a972edb7c8224bc69c8f4450e4d0ed227","scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"alexblochia","email":"alex.bloch55@gmail.com"},"repository":{"url":"git+https://github.com/Cleo-Labs-IA/cleo-legal-api.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.12.1","description":"Official TypeScript SDK for the LegalData by Cleo public API — search 50+ jurisdictions, retrieve legal documents, translate, bulk-fetch, stream changes, and run customs/compliance workflows.","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.2.0_1779211283909_0.9574323520021757","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@cleo-legal/sdk","version":"0.3.0","keywords":["legal","compliance","regulation","law","gdpr","eurlex","legifrance","api","sdk","typescript","rag"],"author":{"url":"https://cleolabs.co","name":"Cleo Labs","email":"hello@cleolabs.co"},"license":"MIT","_id":"@cleo-legal/sdk@0.3.0","maintainers":[{"name":"alexblochia","email":"alex.bloch55@gmail.com"}],"homepage":"https://legaldata-public.cleolabs.co","bugs":{"url":"https://github.com/Cleo-Labs-IA/cleo-legal-api/issues"},"dist":{"shasum":"697d57e08061d74a1e87bd8c458b72d7879871bd","tarball":"https://registry.npmjs.org/@cleo-legal/sdk/-/sdk-0.3.0.tgz","fileCount":10,"integrity":"sha512-RRWgg0cM6+QPRjBw/qm3X4tVRM+gPEOWPojYgAjNQjHrNcqircMJdedwDgW83EuPHTJ6qXCr1f2EqVct89Jd5w==","signatures":[{"sig":"MEQCIGVY2aklRU6KNc+U/4b75ickC1ZzJIyyYS73K9LkoHg3AiAq5hEef73cdh7oHssnEqareN6zy4trGceVUSKp0rqOjQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":42700},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"8ae9095d4869d665b255064c2fd0aab50d83e925","scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"alexblochia","email":"alex.bloch55@gmail.com"},"repository":{"url":"git+https://github.com/Cleo-Labs-IA/cleo-legal-api.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.12.1","description":"Official TypeScript SDK for the LegalData by Cleo public API — search 50+ jurisdictions, retrieve legal documents, translate, bulk-fetch, stream changes, and run customs/compliance workflows.","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.3.0_1779306698325_0.4500519909302889","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@cleo-legal/sdk","version":"0.5.0","keywords":["legal","compliance","regulation","law","gdpr","eurlex","legifrance","api","sdk","typescript","rag"],"author":{"url":"https://cleolabs.co","name":"Cleo Labs","email":"hello@cleolabs.co"},"license":"MIT","_id":"@cleo-legal/sdk@0.5.0","maintainers":[{"name":"alexbloch-ia","email":"alex.bloch55@gmail.com"}],"homepage":"https://legaldata-public.cleolabs.co","bugs":{"url":"https://github.com/Cleo-Labs-IA/cleo-legal-api/issues"},"dist":{"shasum":"8712e39a9211c3029e2dea2997c907133e5416b2","tarball":"https://registry.npmjs.org/@cleo-legal/sdk/-/sdk-0.5.0.tgz","fileCount":13,"integrity":"sha512-xSmGCAzy/3a5iVLdHScxt99FU8EU1WrqTuPptXjk0VQvmWfZmoXwRjutuButCL3gfk9jknkEa0WAJlmi+W3tsg==","signatures":[{"sig":"MEUCIQCKrBvrMCWgJa7ivNu9liqxWRW6Ss2eiRDZB4PRFGAP9wIgKJDSqgnUVHQa9XBzhL5JpJr/OSAGh9Iz5kNsU39LvvU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":65724},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./webhook-verify":{"types":"./dist/webhook-verify.d.ts","import":"./dist/webhook-verify.js"}},"scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"alexbloch-ia","email":"alex.bloch55@gmail.com"},"repository":{"url":"git+https://github.com/Cleo-Labs-IA/cleo-legal-api.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.12.1","description":"Official TypeScript SDK for the LegalData by Cleo public API — search 50+ jurisdictions, retrieve legal documents, translate, bulk-fetch, stream changes, and run customs/compliance workflows.","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.7","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.5.0_1780318163888_0.8596777050316287","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@cleo-legal/sdk","version":"0.6.0","keywords":["legal","compliance","regulation","law","gdpr","eurlex","legifrance","api","sdk","typescript","rag"],"author":{"url":"https://cleolabs.co","name":"Cleo Labs","email":"hello@cleolabs.co"},"license":"MIT","_id":"@cleo-legal/sdk@0.6.0","maintainers":[{"name":"alexbloch-ia","email":"alex.bloch55@gmail.com"}],"homepage":"https://legaldata-public.cleolabs.co","bugs":{"url":"https://github.com/Cleo-Labs-IA/cleo-legal-api/issues"},"dist":{"shasum":"8982993a83a3f3d275136096c046bcc24f199c19","tarball":"https://registry.npmjs.org/@cleo-legal/sdk/-/sdk-0.6.0.tgz","fileCount":15,"integrity":"sha512-KL6MiI0vlTPJDXvWu+sEmE9lzM9k2OL6AxVn2TQ/YmMoX0UksHl/LMeoS5Z1NMmrOp0eWQKYIw4Wl8/MkGEXPw==","signatures":[{"sig":"MEQCIFT1Hi/o4M5uLzoYqRDP5USm68gY/mjxV6hs2paBkaDRAiAWMnPozFvFpGPSu3h3WVpdyqiUPNrN+U90zfVBjQ2+3Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70599},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./webhook-verify":{"types":"./dist/webhook-verify.d.ts","import":"./dist/webhook-verify.js"},"./webhook-verify-sync":{"types":"./dist/webhook-verify-sync.d.ts","import":"./dist/webhook-verify-sync.js"}},"scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"alexbloch-ia","email":"alex.bloch55@gmail.com"},"repository":{"url":"git+https://github.com/Cleo-Labs-IA/cleo-legal-api.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.12.1","description":"Official TypeScript SDK for the LegalData by Cleo public API — search 50+ jurisdictions, retrieve legal documents, translate, bulk-fetch, stream changes, and run customs/compliance workflows.","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.7","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.6.0_1780324502226_0.17752325527682777","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@cleo-legal/sdk","version":"0.7.0","description":"Official TypeScript SDK for the LegalData by Cleo public API — search 50+ jurisdictions, retrieve legal documents, translate, bulk-fetch, stream changes, and run customs/compliance workflows.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./webhook-verify":{"import":"./dist/webhook-verify.js","types":"./dist/webhook-verify.d.ts"},"./webhook-verify-sync":{"import":"./dist/webhook-verify-sync.js","types":"./dist/webhook-verify-sync.d.ts"}},"scripts":{"build":"tsc -p tsconfig.json","test":"vitest run","prepublishOnly":"npm run build && npm test"},"keywords":["legal","compliance","regulation","law","gdpr","eurlex","legifrance","api","sdk","typescript","rag"],"author":{"name":"Cleo Labs","email":"hello@cleolabs.co","url":"https://cleolabs.co"},"license":"MIT","homepage":"https://legaldata-public.cleolabs.co","repository":{"type":"git","url":"git+https://github.com/Cleo-Labs-IA/cleo-legal-api.git","directory":"sdk/typescript"},"bugs":{"url":"https://github.com/Cleo-Labs-IA/cleo-legal-api/issues"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"devDependencies":{"typescript":"^5.4.0","vitest":"^4.1.7"},"_id":"@cleo-legal/sdk@0.7.0","_nodeVersion":"26.0.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-IGyPsAXEzXPxpHsPbdu1cGm7E+ISUNfXjCwNeogu9sNyrSes2+sabf+H0hZNZr/+3iDm/ZaShKq1ic1HwgE7zA==","shasum":"9426fe25a585f5c42b0cc5c42ca3f5fec1aaf59c","tarball":"https://registry.npmjs.org/@cleo-legal/sdk/-/sdk-0.7.0.tgz","fileCount":15,"unpackedSize":81275,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIE6/6hxsHyNrS5G8ZjD+I/0EHwcY9UvtfzW+c1QcEOuxAiEAhAVoYTVkIZFN/2dJvLJ2kLRmqAA+9qA1jEvt2PZTnxc="}]},"_npmUser":{"name":"alexbloch-ia","email":"alex.bloch55@gmail.com"},"directories":{},"maintainers":[{"name":"alexbloch-ia","email":"alex.bloch55@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.7.0_1780336451607_0.9852960751210194"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-12T18:53:04.018Z","modified":"2026-06-01T17:54:11.870Z","0.1.0":"2026-05-12T18:53:04.228Z","0.2.0":"2026-05-19T17:21:24.049Z","0.3.0":"2026-05-20T19:51:38.488Z","0.5.0":"2026-06-01T12:49:24.064Z","0.6.0":"2026-06-01T14:35:02.379Z","0.7.0":"2026-06-01T17:54:11.737Z"},"bugs":{"url":"https://github.com/Cleo-Labs-IA/cleo-legal-api/issues"},"author":{"name":"Cleo Labs","email":"hello@cleolabs.co","url":"https://cleolabs.co"},"license":"MIT","homepage":"https://legaldata-public.cleolabs.co","keywords":["legal","compliance","regulation","law","gdpr","eurlex","legifrance","api","sdk","typescript","rag"],"repository":{"type":"git","url":"git+https://github.com/Cleo-Labs-IA/cleo-legal-api.git","directory":"sdk/typescript"},"description":"Official TypeScript SDK for the LegalData by Cleo public API — search 50+ jurisdictions, retrieve legal documents, translate, bulk-fetch, stream changes, and run customs/compliance workflows.","maintainers":[{"name":"alexbloch-ia","email":"alex.bloch55@gmail.com"}],"readme":"# @cleo-legal/sdk\n\n[![npm version](https://img.shields.io/npm/v/@cleo-legal/sdk.svg)](https://www.npmjs.com/package/@cleo-legal/sdk)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Types](https://img.shields.io/npm/types/@cleo-legal/sdk.svg)](https://www.npmjs.com/package/@cleo-legal/sdk)\n\nOfficial TypeScript SDK for the [LegalData by Cleo](https://legaldata-public.cleolabs.co) public API — search 50+ jurisdictions, retrieve legal documents, stream content-diff changes for RAG pipelines.\n\n## Install\n\n```bash\nnpm install @cleo-legal/sdk\n# or\npnpm add @cleo-legal/sdk\n# or\nbun add @cleo-legal/sdk\n```\n\nGet an API key at [legaldata-public.cleolabs.co/dashboard/api-keys](https://legaldata-public.cleolabs.co/dashboard/api-keys). Free tier: 3 lifetime requests. Pro: 1M req/month.\n\n## Quickstart\n\n```ts\nimport { LegalData } from '@cleo-legal/sdk';\n\nconst ld = new LegalData({ apiKey: process.env.CLEO_LEGAL_API_KEY! });\n\n// Semantic search across all 50+ jurisdictions\nconst search = await ld.search({ q: 'GDPR Article 5', country: 'EU', limit: 5 });\nconsole.log(search.data[0].title);\n//=> \"Regulation (EU) 2016/679 (GDPR)\"\n\n// Lean document fetch (no full_text, ~5KB response with ETag)\nconst { data: doc } = await ld.documents.get(search.data[0].id);\nconsole.log(doc.excerpt, doc.full_text_length);\n\n// Get the full document text (gzip-streamed)\nconst text = await ld.documents.text(doc.id);\nconsole.log(text.length, 'chars');\n\n// Coverage transparency — what we ingest, how often\nconst coverage = await ld.coverage();\nconsole.log(coverage.totals); //=> { sources, documents, jurisdictions }\n\n// Content-diff feed — for RAG re-ingestion\nfor await (const change of ld.changes({ since: new Date(Date.now() - 7 * 86400_000) })) {\n  console.log(change.id, change.content_changed_at);\n}\n\n// v0.2 (Group A — EAEU / multilingual)\n\n// 1) Multilingual search with `lang` filter\nconst ruResults = await ld.search({ q: 'насос центробежный', country: 'KZ', lang: 'ru' });\n\n// 2) Project-context split (legally_required vs contractually_expected)\nconst split = await ld.search({ q: 'centrifugal pumps', country: 'KZ', context: 'oil_gas' });\nconsole.log(split.data.legally_required.length, split.data.contractually_expected.length);\n\n// 3) Bulk search — fan-out 1-25 queries in one round-trip\nconst bulk = await ld.searchBulk({\n  queries: [\n    { q: 'centrifugal pump', country: 'KZ', lang: 'ru' },\n    { q: 'mass spectrometer', country: 'KZ', context: 'defense' },\n  ],\n});\n\n// 4) Bulk documents (preserves input order; null for unknown ids)\nconst docs = await ld.documents.bulk({ ids: [doc.id], include: 'lean' });\n\n// 5) Article retrieval — multilingual (\"Article 12\", \"Статья 12\", \"第 12 条\")\nconst art = await ld.documents.article(doc.id, '12');\nconsole.log(art.data.section_title, art.data.text.length);\n\n// 6) Domain-aware translation (Bedrock Haiku)\nconst translation = await ld.translate({\n  text: 'Насос центробежный для нефти',\n  target_lang: 'en',\n  domain: 'customs',\n});\nconsole.log(translation.data.translated, translation.data.alternatives);\n```\n\n## MCP server\n\nThe Legal API also exposes an **MCP server** at `/mcp` (Streamable HTTP transport). Any MCP-aware client (Claude Desktop, Claude Code, Cursor, …) can call all of the above endpoints as tools. See [docs/mcp-server.md](https://github.com/Cleo-Labs-IA/cleo-legal-api/blob/main/docs/mcp-server.md) for the connection JSON and tool inventory.\n\n## API surface\n\n### Constructor\n\n```ts\nnew LegalData({\n  apiKey: string;          // ld_live_… or ld_test_…\n  baseUrl?: string;        // default: https://api.legaldata.cleolabs.co\n  fetch?: typeof fetch;    // optional custom fetch (mocks, retries, Sentry, etc.)\n})\n```\n\n### `/v2` surface (recommended)\n\n**Search & documents**\n\n| Method | Returns | Notes |\n|---|---|---|\n| `ld.search({ q, country?, type?, lang?, context?, limit?, after?, debug? })` | `PagedResponse<SearchResultItem>` (split shape when `context` set) | `debug: true` adds `score_breakdown`; `context` splits into `legally_required` / `contractually_expected` |\n| `ld.searchBulk({ queries })` | `BulkSearchResponse` | 1–25 queries in one round-trip |\n| `ld.documents.get(id, { includeFullText? })` | `{ data: DocumentLean \\| DocumentFull }` | Lean by default; type narrows on `includeFullText: true` |\n| `ld.documents.bulk({ ids, include? })` | `BulkDocumentsResponse` | 1–50 ids; preserves order |\n| `ld.documents.article(id, n)` | `{ data: DocumentArticle }` | The chunk containing article _n_ |\n| `ld.documents.text(id, { format? })` | `string` or `{ data: { … full_text } }` | `format: 'json'` wraps in an envelope |\n| `ld.translate({ text, target_lang, source_lang?, domain? })` | `{ data: TranslateResponse }` | Bedrock Haiku, 14-day cache |\n| `ld.coverage()` | `CoverageReport` | Per-source tier + 7d success rate |\n| `ld.changes({ since, … })` | `AsyncGenerator<ChangeEntry>` | Auto-paginates — just iterate |\n\n**Customs & compliance**\n\n| Method | Returns |\n|---|---|\n| `ld.customs.lookup({ description, country?, … })` | `CustomsLookupResult` — `{ data, empty_response? }` |\n| `ld.customs.obligations({ code, country, … })` | `{ data: CustomsObligationsResponse }` |\n| `ld.customs.alternatives({ code, country, … })` | `{ data: CustomsAlternativesResponse }` |\n| `ld.customs.dualUse({ destination, code?, description? })` | `{ data: DualUseCheckResponse }` (alias: `dualUseCheck`) |\n| `ld.customs.duties({ code, country, … })` | `{ data: CustomsDuty }` |\n| `ld.customs.landedCost({ code, origin, destination, fob_usd, … })` | `{ data: LandedCostResponse }` |\n| `ld.customs.reverseClassify({ target_code, country, … })` | `{ data: ReverseClassifyResponse }` |\n| `ld.customs.rates.history({ code, country, since? })` | `CustomsRatesHistoryResponse` (advisory) |\n| `ld.customs.rates.byYear({ country, year })` | `CustomsRatesByYearResponse` (advisory) |\n| `ld.compliance.check({ product, destination_country, … })` | `{ data: ComplianceCheckResponse }` |\n| `ld.eaeu.parallelImport({ cert_country, cert_type, … })` | `{ data: ParallelImportResponse }` |\n\n**Amendments, as-of-date & sanctions**\n\n| Method | Returns |\n|---|---|\n| `ld.amendments.get(source, sourceId)` | `AmendmentsResponse` — incoming + outgoing relations |\n| `ld.amendments.byYear({ year, country? })` | `AmendmentsByYearResponse` |\n| `ld.laws.asOf(source, sourceId, date)` | `LawAsOfResponse` — version in force at a date |\n| `ld.sanctions.search({ query, authority?, country?, limit? })` | `SanctionsSearchResponse` (advisory) |\n| `ld.sanctions.overlap({ entity })` | `SanctionsOverlapResponse` (advisory) |\n| `ld.sanctions.byAuthority(authority, { limit? })` | `SanctionsByAuthorityResponse` (advisory) |\n\n**Distribution & reference**\n\n| Method | Returns |\n|---|---|\n| `ld.webhooks.create / list / get / delete / test / deliveries(…)` | webhook subscriptions + deliveries |\n| `ld.standards.lookup({ code?, keyword?, … })` | `PagedResponse<StandardEntry>` |\n| `ld.countries.list(…)` · `ld.countries.get(code)` | country profiles |\n| `ld.authorities.list(…)` · `ld.authorities.get(slug)` | authority profiles |\n\n### Discovery\n\n```ts\nawait ld.meta.sources();        // { sources: [{ source, count }] }\nawait ld.meta.types();          // { types: string[] }\nawait ld.meta.languages();      // { languages: string[] }\nawait ld.meta.topics();         // { topics: string[] }\nawait ld.meta.jurisdictions();  // { jurisdictions: [{ country, name, bloc, doc_count }] }\nawait ld.meta.openapi();        // the raw OpenAPI 3.1 spec\n```\n\n### `/v1` surface (legacy, frozen contract)\n\n```ts\nld.v1.search({ q, country?, type?, limit?, after? })\nld.v1.documents.get(id)\nld.v1.documents.list({ country?, source?, type?, date_from?, date_to?, limit?, after? })\n```\n\n## Error handling\n\nEvery non-2xx response rejects with a `LegalDataError` or a typed subclass. `.code`, `.status` and `.message` are always set; errors from v2 resource routes (the `notFound()` envelope) also populate `.reason`, `.kind`, `.hint`, `.alternatives`, `.suggestion` and `.requestId`.\n\n```ts\nimport {\n  LegalData, LegalDataError,\n  NotFoundError, BadInputError, AuthError, PaymentRequiredError, RateLimitError,\n} from '@cleo-legal/sdk';\n\ntry {\n  await ld.documents.get(id);\n} catch (err) {\n  if (err instanceof RateLimitError)            await sleep((err.retryAfter ?? 1) * 1000);\n  else if (err instanceof NotFoundError)        console.log(err.hint, err.alternatives);\n  else if (err instanceof BadInputError)        console.error('bad request:', err.message);\n  else if (err instanceof AuthError)            console.error('check your API key');\n  else if (err instanceof PaymentRequiredError) console.error('quota/subscription:', err.code);\n  else throw err;\n}\n```\n\nA single `catch (e) { if (e instanceof LegalDataError) … }` still works — all subclasses extend it.\n\n| Class | HTTP | Example codes |\n|---|---|---|\n| `BadInputError` | 400 | `invalid_request`, `invalid_id` |\n| `AuthError` | 401 | `missing_api_key`, `invalid_api_key` |\n| `PaymentRequiredError` | 402 | `free_quota_exhausted`, `monthly_quota_exhausted` |\n| `NotFoundError` | 404 | `not_found`, `data_gap` |\n| `RateLimitError` | 429 | `rate_limited`, `too_many_auth_attempts` — exposes `.retryAfter` (seconds) |\n\nRate-limit retry pattern (honours `Retry-After`):\n\n```ts\nasync function withRetry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {\n  for (let i = 0; i < attempts; i++) {\n    try { return await fn(); }\n    catch (err) {\n      if (err instanceof RateLimitError && i < attempts - 1) {\n        await new Promise(r => setTimeout(r, (err.retryAfter ?? 2 ** i) * 1000));\n        continue;\n      }\n      throw err;\n    }\n  }\n  throw new Error('unreachable');\n}\n\nawait withRetry(() => ld.search({ q: 'GDPR' }));\n```\n\n## Runtimes\n\nWorks in:\n- Node.js ≥ 18 (uses native `fetch`)\n- Bun ≥ 1.0\n- Deno (≥ 1.30) — pass `fetch: globalThis.fetch` to silence types\n- Browsers (use `apiKey` from an env exposed to the client only if you accept the risk; otherwise proxy server-side)\n- Cloudflare Workers, Vercel Edge, AWS Lambda\n\n**Webhook verification** — pick the variant for your runtime:\n\n```ts\n// Node server (recommended for webhook handlers) — synchronous, returns a boolean.\nimport { verifyWebhookSignatureSync } from '@cleo-legal/sdk/webhook-verify-sync';\nif (!verifyWebhookSignatureSync(rawBody, req.headers['x-cleo-signature'], secret)) return res.status(401).end();\n\n// Browser / edge / Workers / Deno — async (WebCrypto), no Node built-ins.\nimport { verifyWebhookSignature } from '@cleo-legal/sdk/webhook-verify';\nconst ok = await verifyWebhookSignature(rawBody, req.headers['x-cleo-signature'], secret);\n```\n\n> ⚠️ The async `verifyWebhookSignature` returns a `Promise` — **always `await` it**. `if (verifyWebhookSignature(...))` tests a Promise (always truthy) and silently accepts every webhook. On Node, prefer the **sync** `verifyWebhookSignatureSync`, where this mistake is impossible. (For the async variant, Node 18 needs `--experimental-global-webcrypto`; Node ≥ 19 works out of the box.)\n\nESM only. If you're on CommonJS, use dynamic import:\n\n```js\nconst { LegalData } = await import('@cleo-legal/sdk');\n```\n\n## Bundle size\n\nZero runtime dependencies. Uses native `fetch`. < 5KB minified + gzipped, fully tree-shakable.\n\n## TypeScript\n\nStrict types out of the box. Pre-built `.d.ts` ships with the package. Discriminated unions on `documents.get(id, { includeFullText: true })` — TypeScript narrows the return type at compile time.\n\n## FAQ\n\n**Do I need to handle pagination on `/v2/changes`?**\nNo. `ld.changes(...)` returns an `AsyncGenerator` that auto-paginates. Just `for await`.\n\n**Can I use my own `fetch`?**\nYes. Pass it in the constructor as `fetch`. Useful for retries (e.g., `cross-fetch-retry`), instrumentation (Sentry, OpenTelemetry), or testing.\n\n**How do I rotate API keys?**\nConstruct a new `LegalData` instance. There's no shared state.\n\n**Is the SDK rate-limit-aware?**\nNo automatic retry — by design (caller controls policy). The example above shows a 3-attempt exponential backoff for the common `rate_limited` case.\n\n## Versioning\n\nFollows [semver](https://semver.org/). `/v1` of the API is contractually frozen and the SDK's `ld.v1.*` surface tracks it for at least 12 months. `/v2` is where new features land; SDK methods may evolve before `1.0.0`.\n\n**0.6.0** adds `verifyWebhookSignatureSync` (Node-only, sync, footgun-free) on the `@cleo-legal/sdk/webhook-verify-sync` subpath. **0.5.0** added typed errors, discovery methods (`meta.*`), and the isomorphic async webhook verifier (⚠️ `verifyWebhookSignature` is `async` — `await` it). See the [CHANGELOG](./CHANGELOG.md).\n\n## License\n\nMIT\n","readmeFilename":"README.md"}