@monerium/sdk 3.4.11 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,27 +5,27 @@
5
5
 
6
6
  <a href="https://docs.monerium.com">
7
7
  <picture>
8
- <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/Developer_portal-2c6ca7"></source>
9
- <img src="https://img.shields.io/badge/Developer_portal-2c6ca7" alt="Static Badge"></img>
8
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/Developer_portal-2c6ca7"/>
9
+ <img src="https://img.shields.io/badge/Developer_portal-2c6ca7" alt="Static Badge"/>
10
10
  </picture>
11
11
  </a>
12
12
  <a href="https://docs.monerium.com/api">
13
13
  <picture>
14
- <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/API_documentation-2c6ca7"></source>
15
- <img src="https://img.shields.io/badge/API_documentation-2c6ca7" alt="Static Badge"></img>
14
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/API_documentation-2c6ca7"/>
15
+ <img src="https://img.shields.io/badge/API_documentation-2c6ca7" alt="Static Badge"/>
16
16
  </picture>
17
17
  </a>
18
- <br></br>
18
+ <br/><br/>
19
19
  <a href="https://www.npmjs.com/package/@monerium/sdk">
20
20
  <picture>
21
- <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=2c6ca7&colorB=21262d"></source>
22
- <img src="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=f6f8fa&colorB=f6f8fa" alt="Version"></img>
21
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=2c6ca7&colorB=21262d"/>
22
+ <img src="https://img.shields.io/npm/v/%40monerium%2Fsdk?colorA=f6f8fa&colorB=f6f8fa" alt="Version"/>
23
23
  </picture>
24
24
  </a>
25
25
  <a href="https://github.com/monerium/js-monorepo/issues">
26
26
  <picture>
27
- <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d"></source>
28
- <img src="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d" alt="Version"></img>
27
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d"/>
28
+ <img src="https://img.shields.io/github/issues/monerium/js-monorepo?colorA=2c6ca7&colorB=21262d" alt="Version"/>
29
29
  </picture>
30
30
  </a>
31
31
 
@@ -36,342 +36,396 @@ All incoming euro payments are automatically minted as EURe tokens to your walle
36
36
  Sending EURe to traditional bank accounts is just as easy.
37
37
  With a single signature from your wallet, your EURe is burned and sent as Euros to any bank account.
38
38
 
39
- ## Documentation
40
-
41
- - [Documentation](../../apps/developer/docs/packages/SDK/index.md)
42
- - [Documentation - MoneriumClient](../../apps/developer/docs/packages/SDK/classes/MoneriumClient.md)
43
-
44
- ## Table of Contents
45
-
46
- - [Installation](#installation)
47
- - [Configuration](#configuration)
48
- - [Usage Examples](#usage-examples)
49
- - [API Reference](#api-reference)
50
- - [Contributing](#contributing)
51
- - [FAQs](#faqs)
52
- - [Support](#support)
53
- - [Release Notes](#release-notes)
54
- - [License](#license)
55
-
56
39
  ## Installation
57
40
 
58
- ### Prerequisites
59
-
60
- Node v16.15 or higher is required.
61
-
62
41
  ```sh
63
- yarn add @monerium/sdk
42
+ pnpm add @monerium/sdk
64
43
  ```
65
44
 
66
- ## Configuration
67
-
68
- ### Environments - URLs
45
+ ## Usage Patterns
69
46
 
70
- | Environment | Web | API |
71
- | ----------- | ---------------------------- | ------------------------ |
72
- | sandbox | https://sandbox.monerium.app | https://api.monerium.dev |
73
- | production | https://monerium.app | https://api.monerium.app |
47
+ This section demonstrates how to use the plan-specific client classes (`MoneriumPrivateClient`, `MoneriumWhitelabelClient`, and `MoneriumOAuthClient`) for the integration flows.
74
48
 
75
- ### Environments - Networks
49
+ ### 1. Private Plan
76
50
 
77
- | Environment | Chain | Name |
78
- | ----------- | -------- | -------- |
79
- | sandbox | ethereum | sepolia |
80
- | | polygon | mumbai |
81
- | | gnosis | chiado |
82
- | | linea | sepolia |
83
- | | scroll | sepolia |
84
- | | camino | columbus |
85
- | production | ethereum | mainnet |
86
- | | polygon | mainnet |
87
- | | gnosis | mainnet |
88
- | | linea | mainnet |
89
- | | scroll | mainnet |
90
- | | camino | mainnet |
51
+ [Read the Private Integration Guide](https://docs.monerium.com/private)
91
52
 
92
- ## Usage Examples
53
+ The Private plan gives you direct API access to your own Monerium account.
54
+ You use `MoneriumPrivateClient` for Server-to-Server communication.
93
55
 
94
- We recommend starting in the [Developer Portal](https://docs.monerium.com). There, you will learn more about `client_id`'s and ways of authenticating.
56
+ Instead of manually passing static access tokens, the recommended approach is to provide a `getAccessToken` callback. This allows the client to dynamically retrieve, cache, and refresh tokens seamlessly across all requests using a single global client instance.
95
57
 
96
- #### Initialize and authenticate using Client Credentials
58
+ ```typescript
59
+ import { MoneriumPrivateClient, Currency } from '@monerium/sdk';
97
60
 
98
- > Client Credentials is used when there's no need for user interaction, and the system-to-system interaction requires authentication.
99
-
100
- ```ts
101
- import { MoneriumClient } from '@monerium/sdk';
102
- // Initialize the client with credentials
103
- const monerium = new MoneriumClient({
61
+ // 1. Initialize the client ONCE globally
62
+ const client: MoneriumPrivateClient = new MoneriumPrivateClient({
104
63
  environment: 'sandbox',
105
- clientId: 'your_client_credentials_uuid', // replace with your client ID
106
- clientSecret: 'your_client_secret', // replace with your client secret
64
+ getAccessToken: async () => {
65
+ // a. Check in-memory cache
66
+ let token = memoryCache.get('monerium_token');
67
+
68
+ // b. Fallback to Database
69
+ if (!token) {
70
+ token = await db.getToken();
71
+ if (token) memoryCache.set('monerium_token', token);
72
+ }
73
+
74
+ // c. If token is missing or expired, fetch a new one
75
+ if (!token || isExpired(token)) {
76
+ // clientCredentialsGrant does not require authentication
77
+ const auth = await client.clientCredentialsGrant('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');
78
+ token = auth.access_token;
79
+
80
+ memoryCache.set('monerium_token', token);
81
+ await db.saveToken(token);
82
+ }
83
+
84
+ return token;
85
+ }
107
86
  });
108
87
 
109
- await monerium.getAccess();
110
-
111
- // Retrieve profiles the client has access to.
112
- await monerium.getProfiles();
113
-
114
- // Access tokens are now available for use.
115
- const { access_token, refresh_token } = monerium.bearerProfile as BearerProfile;
116
-
117
- // Use refresh token to get a new access token
118
- await monerium.getAccess(refresh_token);
119
- ```
120
-
121
- API documentation:
122
-
123
- - [/auth/token](https://docs.monerium.com/api#operation/auth-token)
124
-
125
- #### Initialize and authenticate using Authorization Code Flow with PKCE
126
-
127
- > Authorization Code Flow with PKCE is used for apps where direct user interaction is involved, and the application is running on an environment where the confidentiality of a secret cannot be safely maintained. It allows the application to authorize users without handling their passwords and mitigates the additional risk involved in this sort of delegation.
128
-
129
- First, you have to navigate the user to the Monerium authentication flow. This can be done by generating a URL and redirecting the user to it. After the user has authenticated, Monerium will redirect back to your specified URI with a code. You can then finalize the authentication process by exchanging the code for access and refresh tokens.
130
-
131
- ```ts
132
- import { MoneriumClient } from '@monerium/sdk';
133
-
134
- export function App() {
135
- const [profiles, setProfiles] = useState<Profile[] | null>(null);
136
- const [monerium, setMonerium] = useState<MoneriumClient>();
137
- const [isAuthorized, setIsAuthorized] = useState<boolean>(false);
138
-
139
- useEffect(() => {
140
- const sdk = new MoneriumClient({
141
- environment: 'sandbox',
142
- clientId: 'f99e629b-6dca-11ee-8aa6-5273f65ed05b',
143
- redirectUri: 'http://localhost:4200',
88
+ // 2. Set up Webhooks (One-off initialization)
89
+ async function setupWebhooks() {
90
+ const { subscriptions } = await client.getSubscriptions();
91
+ const webhookUrl = 'https://your-app.com/webhooks/monerium';
92
+
93
+ if (!subscriptions.some(sub => sub.url === webhookUrl)) {
94
+ await client.createSubscription({
95
+ url: webhookUrl,
96
+ secret: 'whsec_YOUR_BASE64_ENCODED_SECRET',
97
+ types: ['order.created', 'order.updated']
144
98
  });
145
- setMonerium(sdk);
146
- }, []);
147
-
148
- useEffect(() => {
149
- const connect = async () => {
150
- if (monerium) {
151
- setIsAuthorized(await monerium.getAccess());
152
- }
153
- };
154
-
155
- connect();
99
+ }
100
+ }
156
101
 
157
- return () => {
158
- if (monerium) {
159
- monerium.disconnect();
160
- }
161
- };
162
- }, [monerium]);
163
-
164
- useEffect(() => {
165
- const fetchData = async () => {
166
- if (monerium && isAuthorized) {
167
- try {
168
- const { profiles } = await monerium.getProfiles();
169
- setProfiles(profiles);
170
- } catch (err) {
171
- console.error('Error fetching data:', err);
102
+ async function runPrivateFlow() {
103
+ // 3. Link a Wallet
104
+ const { addresses } = await client.getAddresses();
105
+ if (!addresses.some(a => a.address === '0xYourAddress...')) {
106
+ await client.linkAddress({
107
+ address: '0xYourAddress...',
108
+ message: 'I hereby declare that I am the address owner.',
109
+ signature: '0xYourSignature...',
110
+ chain: 'ethereum'
111
+ });
112
+ }
113
+
114
+ // 4. Send payments (Place an Order)
115
+ // Check if profile and IBAN are approved before placing an order
116
+ const profiles = await client.getProfiles();
117
+ const defaultProfile = profiles.profiles[0];
118
+ const { ibans } = await client.getIbans();
119
+ const activeIban = ibans.find(i => i.state === 'approved');
120
+
121
+ if (defaultProfile?.state === 'approved' && activeIban) {
122
+ await client.placeOrder({
123
+ address: '0xYourAddress...',
124
+ chain: 'ethereum',
125
+ amount: '100.00',
126
+ signature: '0xYourSignature...',
127
+ currency: Currency.eur,
128
+ counterpart: {
129
+ identifier: {
130
+ standard: 'iban',
131
+ iban: 'YOUR_IBAN',
132
+ bic: 'YOUR_BIC'
133
+ },
134
+ details: {
135
+ firstName: 'John',
136
+ lastName: 'Doe',
137
+ country: 'IS'
172
138
  }
173
- }
174
- };
175
- fetchData();
176
- }, [monerium, isAuthorized]);
177
-
178
- return (
179
- <div>
180
- {!isAuthorized && <button onClick={() => monerium?.authorize()}>Connect</button>}
181
-
182
- <p>{profiles[0]?.name}</p>
183
- </div>
184
- );
139
+ },
140
+ message: 'Payment for services'
141
+ });
142
+ }
185
143
  }
186
- ```
187
-
188
- API documentation:
189
-
190
- - [/auth](https://docs.monerium.com/api#operation/auth)
191
- - [/auth/token](https://docs.monerium.com/api#operation/auth-token)
192
-
193
- #### Get account information
194
-
195
- ```ts
196
- // Get all profiles
197
- const { profiles }: Profile[] = await monerium.getProfiles();
198
-
199
- // Fetching all accounts for a specific profile
200
- const { id: profileId, accounts }: Profile = await monerium.getProfile(
201
- profiles[0].id
202
- );
203
144
 
204
- // Fetching all balances for a specific profile
205
- const balances: Balances = await monerium.getBalances();
206
- ```
207
-
208
- API documentation:
209
-
210
- - [/profile](https://docs.monerium.com/api#operation/profile)
211
- - [/profile/&#123;profileId&#123;/balances](https://docs.monerium.com/api#operation/profile-balances)
212
-
213
- #### Get token information
214
-
215
- Get the contract addresses of EURe tokens.
216
-
217
- ```ts
218
- const tokens: Token[] = await monerium.getTokens();
145
+ // 5. Handle Webhooks (e.g., in your Express route)
146
+ async function handleMoneriumWebhook(event: any) {
147
+ // Automatically provision IBAN when the profile is approved
148
+ if (event.type === 'profile.updated' && event.meta?.state === 'approved') {
149
+ const { ibans } = await client.getIbans();
150
+
151
+ if (ibans.length > 0) {
152
+ if (!ibans.some(i => i.address === '0xYourAddress...' && i.chain === 'ethereum')) {
153
+ await client.moveIban({
154
+ iban: ibans[0].iban,
155
+ address: '0xYourAddress...',
156
+ chain: 'ethereum'
157
+ });
158
+ }
159
+ } else {
160
+ await client.requestIban({
161
+ address: '0xYourAddress...',
162
+ chain: 'ethereum'
163
+ });
164
+ }
165
+ }
166
+
167
+ if (event.type === 'order.updated') {
168
+ console.log('Order status changed:', event.meta?.state);
169
+ }
170
+ }
219
171
  ```
220
172
 
221
- API documentation:
222
-
223
- - [/tokens](https://docs.monerium.com/api#operation/tokens)
224
-
225
- #### Link a new address to Monerium
226
-
227
- It's important to understand when interacting with a blockchain, the user needs to provide a signature in their wallet.
228
- This signature is used to verify that the user is the owner of the wallet address.
173
+ ### 2. Whitelabel Plan
229
174
 
230
- We recommend Viem as an Ethereum interface, see: https://viem.sh/docs/actions/wallet/signMessage.html
175
+ [Read the Whitelabel Integration Guide](https://docs.monerium.com/whitelabel)
231
176
 
232
- ```ts
233
-
234
- import { constants } from '@monerium/sdk';
235
- import { walletClient } from '...' // See Viem documentation
177
+ Embed regulated euro accounts and SEPA payments in your product under your own brand.
178
+ You use `MoneriumWhitelabelClient` to manage profiles on behalf of your customers.
236
179
 
237
- const { LINK_MESSAGE } = constants; // "I hereby declare that I am the address owner."
180
+ Similar to the Private plan, use the `getAccessToken` pattern for efficient, secure server-to-server authentication.
238
181
 
239
- // Send a signature request to the wallet.
240
- const signature = await walletClient.signMessage({
241
- message: LINK_MESSAGE,
242
- })
243
-
244
- // Link a new address to Monerium and create accounts for ethereum and gnosis.
245
- await monerium.linkAddress({
246
- profile: 'your-profile-id',
247
- address: '0xUserAddress72413Fa92980B889A1eCE84dD', // user wallet address
248
- message: LINK_MESSAGE
249
- signature,
250
- chain: 'ethereum',
251
- } as LinkAddress);
252
- ```
182
+ ```typescript
183
+ import { MoneriumWhitelabelClient } from '@monerium/sdk';
253
184
 
254
- API documentation:
185
+ // 1. Initialize the client ONCE globally
186
+ const client: MoneriumWhitelabelClient = new MoneriumWhitelabelClient({
187
+ environment: 'sandbox',
188
+ getAccessToken: async () => {
189
+ let token = memoryCache.get('monerium_token');
190
+
191
+ if (!token) {
192
+ token = await db.getToken();
193
+ if (token) memoryCache.set('monerium_token', token);
194
+ }
195
+
196
+ if (!token || isExpired(token)) {
197
+ const auth = await client.clientCredentialsGrant('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');
198
+ token = auth.access_token;
199
+
200
+ memoryCache.set('monerium_token', token);
201
+ await db.saveToken(token);
202
+ }
203
+
204
+ return token;
205
+ }
206
+ });
255
207
 
256
- - [/profile/&#123;profileId&#123;/addresses](https://docs.monerium.com/api#operation/profile-addresses)
208
+ // 2. Set up Webhooks (One-off initialization, listen for profile approvals)
209
+ async function setupWebhooks() {
210
+ const { subscriptions } = await client.getSubscriptions();
211
+ const webhookUrl = 'https://your-app.com/webhooks/monerium';
212
+
213
+ if (!subscriptions.some(sub => sub.url === webhookUrl)) {
214
+ await client.createSubscription({
215
+ url: webhookUrl,
216
+ secret: 'whsec_YOUR_BASE64_ENCODED_SECRET',
217
+ types: ['profile.updated', 'iban.updated', 'order.created', 'order.updated']
218
+ });
219
+ }
220
+ }
257
221
 
258
- #### Get and place orders
222
+ async function runWhitelabelFlow() {
223
+ // 3. Onboard the customer (Create a Profile)
224
+ const profile = await client.createProfile({
225
+ kind: 'personal'
226
+ });
227
+
228
+ // 4. Submit identity data (e.g., via Sumsub integration)
229
+ // await client.shareProfileKYC({ ... });
230
+
231
+ // 5. Link a Wallet
232
+ const { addresses } = await client.getAddresses({ profile: profile.id });
233
+ if (!addresses.some(a => a.address === '0xCustomerAddress...')) {
234
+ await client.linkAddress({
235
+ profile: profile.id,
236
+ address: '0xCustomerAddress...',
237
+ message: 'I hereby declare that I am the address owner.',
238
+ signature: '0xCustomerSignature...',
239
+ chain: 'polygon'
240
+ });
241
+ }
242
+
243
+ // 6. Send/Receive Payments
244
+ // Check if profile and IBAN are approved before interacting
245
+ const currentProfile = await client.getProfile(profile.id);
246
+ const { ibans } = await client.getIbans({ profile: profile.id });
247
+ const activeIban = ibans.find(i => i.state === 'approved');
248
+
249
+ if (currentProfile.state === 'approved' && activeIban) {
250
+ // Monerium handles incoming SEPA payments automatically once the IBAN is active.
251
+ // You can also place outgoing orders here using client.placeOrder()
252
+ }
253
+ }
259
254
 
260
- ```ts
261
- // Get orders for a specific profile
262
- const orders: Order[] = await monerium.getOrders(profileId);
255
+ // 7. Handle Webhooks (e.g., in your Express route)
256
+ async function handleMoneriumWebhook(event: any) {
257
+ // Automatically provision IBAN when the profile is approved
258
+ if (event.type === 'profile.updated' && event.meta?.state === 'approved') {
259
+ const profileId = event.meta?.profile;
260
+ const { ibans } = await client.getIbans({ profile: profileId });
261
+
262
+ if (ibans.length > 0) {
263
+ if (!ibans.some(i => i.address === '0xCustomerAddress...' && i.chain === 'polygon')) {
264
+ await client.moveIban({
265
+ iban: ibans[0].iban,
266
+ address: '0xCustomerAddress...',
267
+ chain: 'polygon'
268
+ });
269
+ }
270
+ } else {
271
+ await client.requestIban({
272
+ address: '0xCustomerAddress...',
273
+ chain: 'polygon'
274
+ });
275
+ }
276
+ }
277
+
278
+ if (event.type === 'iban.updated') {
279
+ console.log('IBAN state changed for profile:', event.meta?.profile);
280
+ }
281
+ }
263
282
  ```
264
283
 
265
- ```ts
266
- // Place a redeem order
267
- import { placeOrderMessage } from '@monerium/sdk';
268
- import { walletClient } from '...'; // See Viem documentation
284
+ ### 3. OAuth Plan
269
285
 
270
- const amount = '100'; // replace with the amount in EUR
271
- const iban = 'EE12341234123412341234'; // replace with requested IBAN
286
+ [Read the OAuth Integration Guide](https://docs.monerium.com/oauth)
272
287
 
273
- // First you have to form the message that will be signed by the user
274
- const message = placeOrderMessage(amount, 'eur', iban);
288
+ The OAuth flow lets users authorize your application to access their Monerium account.
289
+ You use `MoneriumOAuthClient` as it is safe for both browser and server environments (it does not contain `clientCredentialsGrant`).
275
290
 
276
- // The message should look like this, with the current date and time in RFC3339 format:
277
- // Send EUR 100 to EE12341234123412341234 at Thu, 29 Dec 2022 14:58:29Z
291
+ When managing multiple users, you can also use `getAccessToken` to fetch the specific user's token from your database and refresh it automatically via `refreshTokenGrant` if it expires.
278
292
 
279
- // Send a signature request to the wallet.
280
- const signature = await walletClient.signMessage({
281
- message: message,
282
- });
293
+ ```typescript
294
+ import { MoneriumOAuthClient, generatePKCE } from '@monerium/sdk';
283
295
 
284
- // Place the order
285
- const order = await monerium.placeOrder({
286
- amount,
287
- signature,
288
- currency: 'eur',
289
- address: '0xUserAddress72413Fa92980B889A1eCE84dD', // user wallet address
290
- counterpart: {
291
- identifier: {
292
- standard: 'iban', // PaymentStandard.iban,
293
- iban,
294
- },
295
- details: {
296
- firstName: 'User',
297
- lastName: 'Userson',
298
- county: 'IS',
299
- },
300
- },
301
- message,
302
- memo: 'Powered by Monerium SDK',
303
- chain: 'ethereum',
304
- network: 'sepolia',
305
- // supportingDocumentId, see below
296
+ // 1. Initialize the client (Browser or Server)
297
+ const client: MoneriumOAuthClient = new MoneriumOAuthClient({
298
+ environment: 'sandbox',
299
+ getAccessToken: async () => {
300
+ // Fetch the authenticated user's access token from your database/session
301
+ let { accessToken, refreshToken, expiresAt } = await db.getUserTokens(userId);
302
+
303
+ // If expired, refresh it automatically using the OAuth client
304
+ if (Date.now() >= expiresAt) {
305
+ const auth = await client.refreshTokenGrant({
306
+ clientId: 'YOUR_CLIENT_ID',
307
+ refreshToken: refreshToken
308
+ });
309
+
310
+ accessToken = auth.access_token;
311
+ await db.saveUserTokens(userId, auth);
312
+ }
313
+
314
+ return accessToken;
315
+ }
306
316
  });
307
- ```
308
-
309
- API documentation:
310
317
 
311
- - [GET /orders](https://docs.monerium.com/api#operation/orders)
312
- - [POST /orders](https://docs.monerium.com/api#operation/post-orders)
313
-
314
- #### Add supporting documents
318
+ // --- Server or Client: Initiate login ---
319
+ async function initiateAuth() {
320
+ const { codeChallenge, codeVerifier } = generatePKCE();
321
+ // Store `codeVerifier` in a secure, server-side session or cookie
322
+ // session.set('pkce_verifier', codeVerifier);
323
+
324
+ const authUrl = client.buildAuthorizationUrl({
325
+ clientId: 'YOUR_CLIENT_ID',
326
+ redirectUri: 'https://your-app.com/callback',
327
+ codeChallenge: codeChallenge,
328
+ state: 'random_state_string'
329
+ });
330
+
331
+ // Redirect user to the returned URL...
332
+ // (e.g., `window.location.assign(authUrl)` on the client, or `redirect(authUrl)` on the server)
333
+ }
315
334
 
316
- When placing orders with payouts above 15,000 EUR, a supporting document is required. The document must be uploaded to Monerium before the order can be placed. Supporting documents can be an invoice or an agreement.
335
+ // --- Server: Handle Callback ---
336
+ // Exchanging the code requires a secure backend endpoint
337
+ async function handleAuthCallback(requestUrl: string) {
338
+ // 1. Parse Authorization Response
339
+ const { code } = client.parseAuthorizationResponse(requestUrl);
340
+
341
+ // 2. Retrieve the stored verifier
342
+ // const storedVerifier = session.get('pkce_verifier');
343
+
344
+ // 3. Exchange code for tokens
345
+ const tokens = await client.authorizationCodeGrant({
346
+ clientId: 'YOUR_CLIENT_ID',
347
+ redirectUri: 'https://your-app.com/callback',
348
+ code: code!,
349
+ codeVerifier: 'STORED_CODE_VERIFIER'
350
+ });
351
+
352
+ // 4. Save `tokens` to your database associated with the user
353
+ await db.saveUserTokens(userId, tokens);
354
+ }
317
355
 
318
- ```ts
319
- // Upload a supporting document
320
- const supportingDocumentId: SupportingDoc =
321
- await uploadSupportingDocument(document);
356
+ async function runOAuthUserFlow() {
357
+ // 5. Link a Wallet
358
+ const { addresses } = await client.getAddresses();
359
+ if (!addresses.some(a => a.address === '0xUserAddress...')) {
360
+ await client.linkAddress({
361
+ address: '0xUserAddress...',
362
+ message: 'I hereby declare that I am the address owner.',
363
+ signature: '0xUserSignature...',
364
+ chain: 'arbitrum'
365
+ });
366
+ }
367
+
368
+ // 6. Check if Profile & IBAN are approved
369
+ const profiles = await client.getProfiles();
370
+ const defaultProfile = profiles.profiles[0];
371
+ const { ibans } = await client.getIbans();
372
+ const activeIban = ibans.find(i => i.state === 'approved');
373
+
374
+ if (defaultProfile?.state === 'approved' && activeIban) {
375
+ // 7. Get user's balances
376
+ const balances = await client.getBalances({
377
+ address: '0xUserAddress...',
378
+ chain: 'arbitrum'
379
+ });
380
+
381
+ console.log(balances);
382
+
383
+ // You can also place orders here safely!
384
+ } else if (defaultProfile?.state === 'approved' && !activeIban) {
385
+ // Automatically issue/move the IBAN if the profile is approved but the IBAN is not ready
386
+ if (ibans.length > 0) {
387
+ if (!ibans.some(i => i.address === '0xUserAddress...' && i.chain === 'arbitrum')) {
388
+ await client.moveIban({
389
+ iban: ibans[0].iban,
390
+ address: '0xUserAddress...',
391
+ chain: 'arbitrum'
392
+ });
393
+ }
394
+ } else {
395
+ await client.requestIban({
396
+ address: '0xUserAddress...',
397
+ chain: 'arbitrum'
398
+ });
399
+ }
400
+ }
401
+ }
322
402
  ```
323
403
 
324
- API documentation:
325
-
326
- - [/files](https://docs.monerium.com/api#operation/supporting-document)
404
+ ### 4. Custom Transport
327
405
 
328
- #### Subscribe to order events
406
+ _Inject custom logic (retries, logging, proxies) by replacing the default fetch implementation._
329
407
 
330
408
  ```ts
331
- import { OrderState } from '@monerium/sdk';
332
- const [orderState, setOrderState] = useState<OrderState>();
409
+ import { MoneriumOAuthClient } from '@monerium/sdk';
333
410
 
334
- // Subscribe to all order events
335
- monerium.subscribeOrderNotifications();
336
-
337
- // Subscribe to specific order events
338
- monerium.subscribeOrderNotifications({ 
339
- filter: {
340
- state: OrderState.pending,
341
- profile: 'my-profile-id',
411
+ const api = new MoneriumOAuthClient({
412
+ environment: 'sandbox',
413
+ getAccessToken: async () => '...',
414
+ transport: async ({ method, url, headers, body }) => {
415
+ console.log(`Calling ${method} ${url}`);
416
+ const res = await fetch(url, { method, headers, body });
417
+ return { status: res.status, bodyText: await res.text() };
342
418
  },
343
- // optional callback functions
344
- onMessage: (order) => console.log(order)
345
- onError: (error) => console.error(error)
346
- });
347
-
348
- // Unsubscribe from specific order events
349
- monerium.unsubscribeOrderNotifications({ 
350
- state: OrderState.pending,
351
- profile: 'my-profile-id'
352
419
  });
353
- // Unsubscribe from all order events
354
- monerium.unsubscribeOrderNotifications();
355
-
356
420
  ```
357
421
 
358
422
  ## API Reference
359
423
 
360
- [API Documentation](https://docs.monerium.com//api)
424
+ [API Documentation](https://docs.monerium.com/api)
361
425
 
362
426
  ## Contributing
363
427
 
364
- We are using [commitlint](https://github.com/conventional-changelog/commitlint/tree/master/@commitlint/config-conventional) to enforce that developers format the commit messages according to the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) guidelines.
365
-
366
- We are using PNPM as a package manager.
367
-
368
- #### Development mode
369
-
370
- ```
371
- pnpm dev
372
- ```
373
-
374
- While in development mode, TypeScript declaration maps (`.d.ts.map`) are generated. TypeScript declaration maps are mainly used to quickly jump to type definitions in the context of a monorepo.
428
+ We are using PNPM as a package manager and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard.
375
429
 
376
430
  #### Build
377
431
 
@@ -379,26 +433,12 @@ While in development mode, TypeScript declaration maps (`.d.ts.map`) are generat
379
433
  pnpm build
380
434
  ```
381
435
 
382
- ### Documentation
383
-
384
- Refer to [Typedocs](https://typedoc.org/) syntaxes to use for this [documentation](https://monerium.github.io/js-monorepo/).
385
-
386
- #### Publishing
387
-
388
- When changes are merged to the `main` branch that follows the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standard, [release-please](https://github.com/googleapis/release-please) workflow creates a pull request, preparing for the next release. If kept open, the following commits will also be added to the PR. Merging that PR will create a new release, a workflow will publish it on NPM and tag it on Github.
389
-
390
- ## FAQs
436
+ #### Test
391
437
 
392
- Common questions developers have regarding the SDK.
438
+ ```
439
+ pnpm test
440
+ ```
393
441
 
394
442
  ## Support
395
443
 
396
- [Support](https://monerium.app/help)
397
-
398
- [Telegram](https://t.me/+lGtM1gY9zWthNGE8)
399
-
400
- [Github Issues](https://github.com/monerium/js-monorepo/issues)
401
-
402
- ## Release Notes
403
-
404
- https://github.com/monerium/js-monorepo/releases
444
+ [Support](https://monerium.app/help) | [Github Issues](https://github.com/monerium/js-monorepo/issues)