Skip to content

Commit 5180b8f

Browse files
committed
Initial commit
0 parents  commit 5180b8f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+4339
-0
lines changed

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
node_modules/
2+
dist/
3+
*.tsbuildinfo
4+
.DS_Store
5+
*.log
6+
coverage/
7+
.env
8+
.env.*
9+
!.env.example
10+
11+
.claude
12+
CLAUDE.md

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 walutomat-sdk contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Walutomat SDK
2+
3+
Unofficial SDK clients for the [Walutomat API v2.0.0](https://api.walutomat.pl/v2.0.0/).
4+
5+
Walutomat is a Polish peer-to-peer currency exchange platform operated by Currency One. This SDK provides typed clients for their REST API, covering wallet management, transfers, direct FX, and the P2P market order book.
6+
7+
## Packages
8+
9+
| Package | Description |
10+
| ------------------------------------------------ | ------------------------------------------ |
11+
| [`packages/typescript`](packages/typescript) | TypeScript client library |
12+
| [`packages/api-explorer`](packages/api-explorer) | Interactive API docs (OpenAPI + Scalar UI) |
13+
14+
## Prerequisites
15+
16+
- A Walutomat account with API access enabled
17+
- An RSA 4096-bit key pair (for signed endpoints)
18+
19+
### Generate RSA keys
20+
21+
```bash
22+
openssl genrsa -out private.key 4096
23+
openssl rsa -in private.key -pubout -out public.key
24+
```
25+
26+
Upload `public.key` in the Walutomat User Panel under **Additional services > API Key**. Keep `private.key` safe — the SDK uses it to sign requests.
27+
28+
## TypeScript SDK
29+
30+
Zero dependencies. Uses native `fetch` and `node:crypto`.
31+
32+
### Install
33+
34+
```bash
35+
cd packages/typescript
36+
bun install
37+
```
38+
39+
### Usage
40+
41+
```typescript
42+
import { createClient } from "walutomat-sdk";
43+
import { readFileSync } from "node:fs";
44+
45+
const client = createClient({
46+
apiKey: "your-api-key",
47+
privateKey: readFileSync("./private.key", "utf-8"),
48+
// sandbox: true, // use api.walutomat.dev
49+
});
50+
51+
// Wallet balances
52+
const balances = await client.account.getBalances();
53+
54+
// Exchange rates + execute a direct exchange
55+
const rate = await client.directFx.getRates({ currencyPair: "EURPLN" });
56+
const { result } = await client.directFx.exchange({
57+
submitId: crypto.randomUUID(),
58+
currencyPair: "EURPLN",
59+
buySell: "BUY",
60+
volume: "100.00",
61+
volumeCurrency: "EUR",
62+
ts: rate.ts,
63+
});
64+
65+
// P2P market order book (no auth required)
66+
const offers = await client.marketFx.getBestOffers({ currencyPair: "EURPLN" });
67+
68+
// Auto-paginate through operation history
69+
for await (const item of client.account.getHistoryIterator()) {
70+
console.log(item.operationAmount, item.currency);
71+
}
72+
```
73+
74+
### Tree-shakeable imports
75+
76+
For smaller bundles, import individual endpoint functions instead of the full client:
77+
78+
```typescript
79+
import { createHttpClient } from "walutomat-sdk";
80+
import { getBalances } from "walutomat-sdk/account";
81+
import { getBestOffers } from "walutomat-sdk/market-fx";
82+
83+
const http = createHttpClient({ apiKey: "...", privateKey: "..." });
84+
const balances = await getBalances(http);
85+
```
86+
87+
### API coverage
88+
89+
| Group | Endpoints |
90+
| ------------- | ------------------------------------------------------------------------------------------------------------------ |
91+
| **Account** | `getBalances`, `getHistory`, `getHistoryIterator`, `getHistoryMt940` |
92+
| **Transfers** | `getTransferStatus`, `createInternalTransfer`, `createIbanTransfer`, `createSepaTransfer`, `createNonIbanTransfer` |
93+
| **Direct FX** | `getRates`, `createExchange` |
94+
| **Market FX** | `getBestOffers`, `getBestOffersDetailed`, `getActiveOrders`, `getOrder`, `submitOrder`, `closeOrder` |
95+
96+
### Error handling
97+
98+
```typescript
99+
import { WalutomatApiError, WalutomatHttpError } from "walutomat-sdk/errors";
100+
101+
try {
102+
await client.transfers.createIban({
103+
/* ... */
104+
});
105+
} catch (err) {
106+
if (err instanceof WalutomatApiError) {
107+
// API returned success: false
108+
console.error(err.errors);
109+
} else if (err instanceof WalutomatHttpError) {
110+
// HTTP error (429, 500, network failure, etc.)
111+
console.error(err.statusCode, err.responseBody);
112+
}
113+
}
114+
```
115+
116+
### Testing
117+
118+
```bash
119+
cd packages/typescript
120+
121+
# Unit tests
122+
bun run test
123+
124+
# Integration tests (requires .env with credentials)
125+
bun run test:integration
126+
```
127+
128+
## API Explorer
129+
130+
Interactive API documentation powered by [Scalar](https://scalar.com/) with a local signing proxy that lets you try all 16 endpoints directly from the browser.
131+
132+
### Setup
133+
134+
```bash
135+
cd packages/api-explorer
136+
137+
# Create .env with your credentials
138+
cp .env.example .env
139+
# Edit .env — set WALUTOMAT_API_KEY and WALUTOMAT_PRIVATE_KEY_PATH
140+
141+
bun start
142+
# Open http://localhost:3333
143+
```
144+
145+
The signing proxy runs on `localhost:3333` and handles RSA signature computation, so Scalar's "Try it" feature works for every endpoint — including authenticated ones that require `X-API-Signature`.
146+
147+
### How the proxy works
148+
149+
Scalar sends requests to `http://localhost:3333/proxy/api/v2.0.0/...`. The proxy:
150+
151+
1. Reads your API key and private key from `.env`
152+
2. Computes `X-API-Timestamp` and `X-API-Signature` headers
153+
3. Forwards the signed request to the real Walutomat API
154+
4. Returns the response with CORS headers
155+
156+
### Keeping the spec in sync
157+
158+
The OpenAPI spec (`packages/api-explorer/openapi.json`) is covered by a drift-detection test in the TypeScript package. Running `bun run test` checks that:
159+
160+
- Every endpoint path + HTTP method in the source code has a matching entry in the spec
161+
- Response schema field names match the TypeScript interfaces
162+
- Enum values match the TypeScript union types
163+
164+
If you add or change an endpoint in the SDK, the test will fail until you update the spec.
165+
166+
## Authentication details
167+
168+
The Walutomat API uses two-layer auth on all endpoints (except `GET /market_fx/best_offers`):
169+
170+
1. **`X-API-Key`** — your API key
171+
2. **`X-API-Signature`** + **`X-API-Timestamp`** — RSA SHA-256 signature of `timestamp + endpointPath + bodyOrQuery`
172+
173+
Both the signature and timestamp must always be provided together. The SDK handles this automatically when you provide a `privateKey`.
174+
175+
## License
176+
177+
[MIT](LICENSE)

packages/api-explorer/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
WALUTOMAT_API_KEY=your-api-key-here
2+
WALUTOMAT_PRIVATE_KEY_PATH=/absolute/path/to/private.key

packages/api-explorer/bun.lock

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/api-explorer/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>Walutomat API Explorer</title>
7+
</head>
8+
<body>
9+
<script
10+
id="api-reference"
11+
data-url="/openapi.json"
12+
data-configuration='{"theme":"kepler","hideClientButton":true}'
13+
></script>
14+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
15+
</body>
16+
</html>

0 commit comments

Comments
 (0)