npm package: @sputnikx/eu-trade-sdk
Description: Lightweight JavaScript SDK for SputnikX EU Trade Analytics API — 28M+ Eurostat COMEXT records, product catalog, orders, and fuel calculator
Author: SputnikX
Latest version: 1.0.0

# @sputnikx/eu-trade-sdk

[![npm version](https://img.shields.io/npm/v/@sputnikx/eu-trade-sdk.svg)](https://www.npmjs.com/package/@sputnikx/eu-trade-sdk)
[![license](https://img.shields.io/npm/l/@sputnikx/eu-trade-sdk.svg)](./LICENSE)
[![node](https://img.shields.io/node/v/@sputnikx/eu-trade-sdk.svg)](https://nodejs.org)

Lightweight JavaScript SDK for the **SputnikX EU Trade Analytics API** — 28M+ Eurostat COMEXT records across 27 EU countries, plus commerce endpoints for product catalog, pricing, quotes, and orders.

**Zero dependencies.** Uses native `fetch` (Node 18+). Full TypeScript support via JSDoc + `.d.ts`.

## Quick Start

```bash
npm install @sputnikx/eu-trade-sdk
```

```js
import { TradeClient } from '@sputnikx/eu-trade-sdk';

const trade = new TradeClient({ apiKey: process.env.SPUTNIKX_API_KEY });
const { data } = await trade.overview();
console.log(`${data.total_records.toLocaleString()} trade records`);
```

## Authentication

Public endpoints (products, prices, calculator) require **no API key**.

Agent endpoints (trade data, availability, quotes, orders) require a Bearer token:

```bash
export SPUTNIKX_API_KEY=sk_live_your_key_here
```

Get your API key at [sputnikx.xyz](https://sputnikx.xyz) admin panel or via the x402 USDC payment protocol.

### Configuration

| Option | Env Variable | Default |
|--------|-------------|---------|
| `apiKey` | `SPUTNIKX_API_KEY` | _(none)_ |
| `baseUrl` | `SPUTNIKX_API_URL` | `https://sputnikx.xyz` |
| `tenant` | `SPUTNIKX_TENANT` | `siltums` |
| `timeout` | `SPUTNIKX_TIMEOUT` | `30000` |

Legacy env vars (`SILTUMS_API_KEY`, etc.) are supported as fallbacks.

## API Reference

### TradeClient

EU trade data endpoints. All require authentication with `read` scope.

```js
import { TradeClient } from '@sputnikx/eu-trade-sdk';
const trade = new TradeClient({ apiKey: '...' });
```

#### `trade.overview()`

High-level statistics: total records, countries, date range, yearly breakdown.

```js
const { data } = await trade.overview();
// { total_records: 28000000+, countries_with_data: 27, date_range: { from, to }, years: [...] }
```

#### `trade.countries()`

EU27 countries with data availability status.

```js
const { data } = await trade.countries();
// [{ code: 'LV', name_en: 'Latvia', has_data: true, total_records: 1200000, years_available: [2021,2022,...] }]
```

#### `trade.timeline(opts?)`

Monthly trade volume time series.

| Parameter | Type | Description |
|-----------|------|-------------|
| `reporters` | `string[]` | EU27 codes, e.g. `['LV', 'DE']` |
| `flow` | `string` | `'IMPORT'` or `'EXPORT'` |
| `years` | `string` | Range `'2021-2025'` or single `'2024'` |
| `limit` | `number` | Max rows (default: 1000, max: 10000) |

```js
const { data } = await trade.timeline({
  reporters: ['LV', 'EE', 'LT'],
  flow: 'EXPORT',
  years: '2023-2025',
});
```

#### `trade.topPartners(opts)`

Top trading partners by value for a reporter country.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `reporter` | `string` | Yes | EU27 country code |
| `year` | `number` | No | Filter by year |
| `flow` | `string` | No | `'IMPORT'` or `'EXPORT'` |
| `limit` | `number` | No | Max results (default: 20) |

```js
const { data } = await trade.topPartners({ reporter: 'LV', flow: 'EXPORT', year: 2025 });
```

#### `trade.topProducts(opts)`

Top HS2 product categories by value.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `reporter` | `string` | Yes | EU27 country code |
| `year` | `number` | No | Filter by year |
| `flow` | `string` | No | `'IMPORT'` or `'EXPORT'` |
| `limit` | `number` | No | Max results (default: 20) |

```js
const { data } = await trade.topProducts({ reporter: 'DE', year: 2025, limit: 10 });
```

#### `trade.balance(opts)`

Trade balance (export - import) over time.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `reporter` | `string` | Yes | EU27 country code |
| `years` | `string` | No | Range (default: last 5 years) |

```js
const { data } = await trade.balance({ reporter: 'LV', years: '2020-2025' });
// [{ year: 2020, import_eur, export_eur, balance_eur, ... }]
```

#### `trade.woodProducts(opts)`

Wood products HS4-level breakdown (Chapter 44) with top 3 partners per product.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `reporter` | `string` | Yes | EU27 country code |
| `year` | `number` | No | Filter by year |
| `flow` | `string` | No | `'IMPORT'` or `'EXPORT'` |

```js
const { data } = await trade.woodProducts({ reporter: 'LV', year: 2025, flow: 'EXPORT' });
// [{ hs4_code: '4407', hs4_name: 'Wood sawn lengthwise', value_eur, top_partners: [...] }]
```

#### `trade.heatmap(opts)`

Cross-country comparison for a product/year combination.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `year` | `number` | Yes | Year |
| `flow` | `string` | No | `'IMPORT'` or `'EXPORT'` |
| `hs2` | `string` | No | HS2 code (e.g. `'44'` for wood) |

```js
const { data } = await trade.heatmap({ year: 2025, hs2: '44', flow: 'IMPORT' });
// [{ code: 'DE', name: 'Germany', value_eur: 5200000000, weight_kg: ... }]
```

#### `trade.productDetail(opts)`

Deep dive into an HS2 chapter: monthly series + top 20 partners.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `reporter` | `string` | Yes | EU27 country code |
| `hs2` | `string` | Yes | HS2 code (e.g. `'44'`) |
| `years` | `string` | No | Range (default: last 3 years) |

```js
const { monthly, top_partners } = await trade.productDetail({
  reporter: 'LV', hs2: '44', years: '2023-2025',
});
```

#### `trade.usage()`

Check API rate limits and usage for the current key.

```js
const usage = await trade.usage();
```

---

### CommerceClient

Product catalog, pricing, calculator, quotes, and orders.

```js
import { CommerceClient } from '@sputnikx/eu-trade-sdk';
const commerce = new CommerceClient({ apiKey: '...' }); // apiKey optional for public endpoints
```

#### `commerce.products()` (public)

Full product catalog of in-stock items.

```js
const products = await commerce.products();
```

#### `commerce.prices()` (public)

Real-time price feed with per-kg and per-ton rates.

```js
const { prices, currency, updated_at } = await commerce.prices();
```

#### `commerce.calculator(opts?)` (public)

Fuel consumption calculator for heating season planning.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `boiler_kw` | `number` | `15` | Boiler power (1-500 kW) |
| `desired_temp` | `number` | `20` | Indoor temperature (C) |
| `heating_months` | `number` | `6` | Season length (1-12) |
| `insulation` | `string` | `'average'` | `poor/average/good/excellent` |

```js
const { data } = await commerce.calculator({ boiler_kw: 25, insulation: 'good' });
console.log(`Need ${data.granulas.kg}kg pellets (${data.granulas.bags} bags)`);
```

#### `commerce.availability(opts?)` (auth)

Check real-time stock levels per warehouse location.

```js
const { data } = await commerce.availability({ slug: 'premium-granulas-a1' });
```

#### `commerce.createQuote(opts)` (auth, `quote` scope)

Create a price quote with automatic VAT calculation (21%).

```js
const quote = await commerce.createQuote({
  client_name: 'Acme SIA',
  client_email: 'info@acme.lv',
  items: [
    { slug: 'premium-granulas-a1', quantity: 10, unit: 'pallet' },
    { slug: 'ozola-briketes', quantity: 50, unit: 'bag' },
  ],
});
console.log(`Quote ${quote.data.quote_number}: EUR ${quote.data.total_with_vat}`);
```

#### `commerce.placeOrder(opts)` (auth, `order` scope)

Place an order. Maximum EUR 50,000 per order.

```js
const order = await commerce.placeOrder({
  slug: 'premium-granulas-a1',
  quantity: 5,
  unit: 'pallet',
  customer_name: 'Janis Berzins',
  customer_email: 'janis@example.com',
  delivery_address: 'Brivibas iela 100, Riga, LV-1001',
  idempotency_key: 'order-abc-123',
});
```

#### `commerce.orderStatus(orderId)` (auth, `order` scope)

Check order status.

```js
const { data } = await commerce.orderStatus(42);
console.log(`Order #${data.id}: ${data.status}`);
```

---

### Constants

```js
import { EU27_COUNTRIES, EU27_CODES, TRADE_FLOWS, HS2_CHAPTERS, WOOD_HS4 } from '@sputnikx/eu-trade-sdk';

EU27_COUNTRIES.LV  // 'Latvia'
EU27_CODES.has('DE')  // true
TRADE_FLOWS.EXPORT  // 'EXPORT'
HS2_CHAPTERS['44']  // 'Wood and articles of wood; wood charcoal'
WOOD_HS4['4412']  // 'Plywood'
```

---

### Error Handling

All API errors throw `SputnikXError` with HTTP status and response data:

```js
import { TradeClient, SputnikXError } from '@sputnikx/eu-trade-sdk';

try {
  await trade.topPartners({ reporter: 'XX' }); // invalid country
} catch (err) {
  if (err instanceof SputnikXError) {
    console.error(`API error (${err.status}): ${err.message}`);
    console.error('Response:', err.data);
  }
}
```

| Status | Meaning |
|--------|---------|
| `400` | Bad request (invalid parameters) |
| `401` | Missing or invalid API key |
| `403` | Insufficient scope |
| `404` | Resource not found |
| `408` | Request timeout |
| `429` | Rate limit exceeded |
| `500` | Server error |

---

### Shared Client

Both `TradeClient` and `CommerceClient` can share a single `SputnikXClient`:

```js
import { SputnikXClient, TradeClient, CommerceClient } from '@sputnikx/eu-trade-sdk';

const client = new SputnikXClient({ apiKey: '...' });
const trade = new TradeClient(client);
const commerce = new CommerceClient(client);
```

---

## x402 USDC Payments

The SputnikX API supports the [x402 payment protocol](https://www.x402.org/) for pay-per-request access using USDC on Base. No API key needed — pay with crypto per request.

---

## Related

- **MCP Server:** [`mcp-sputnikx-market`](https://www.npmjs.com/package/mcp-sputnikx-market) — Model Context Protocol server for Claude, ChatGPT, and other AI assistants
- **OpenAPI:** `https://sputnikx.xyz/api/openapi.json`
- **Agent Card:** `https://sputnikx.xyz/.well-known/agent-card.json`
- **Website:** [sputnikx.xyz](https://sputnikx.xyz)

## License

[MIT](./LICENSE) --- SputnikX