@iteradian-rpc/sdk 1.0.1 → 1.2.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 +294 -115
- package/dist/index.d.mts +907 -323
- package/dist/index.d.ts +907 -323
- package/dist/index.js +202 -47
- package/dist/index.mjs +202 -47
- package/package.json +5 -13
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<p align="center">
|
|
7
7
|
<img src="https://img.shields.io/badge/language-TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" />
|
|
8
8
|
<img src="https://img.shields.io/badge/node-%3E%3D16.0.0-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node 16+" />
|
|
9
|
-
<img src="https://img.shields.io/badge/version-1.
|
|
9
|
+
<img src="https://img.shields.io/badge/version-1.2.0-green?style=flat-square" alt="Version" />
|
|
10
10
|
<img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License" />
|
|
11
11
|
<img src="https://img.shields.io/badge/npm-%40iteradian%2Fsdk-CB3837?style=flat-square&logo=npm&logoColor=white" alt="npm" />
|
|
12
12
|
<img src="https://img.shields.io/badge/deps-zero-brightgreen?style=flat-square" alt="Zero Dependencies" />
|
|
@@ -57,11 +57,15 @@ const client = new IteradianClient({
|
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
// Login — sets the access token automatically
|
|
60
|
-
const
|
|
60
|
+
const login = await client.auth.login({
|
|
61
61
|
email: "user@example.com",
|
|
62
62
|
password: "password123",
|
|
63
63
|
});
|
|
64
|
-
|
|
64
|
+
if (login.requires2FA) {
|
|
65
|
+
// Two-factor auth is on: log in again with a code (see Authentication).
|
|
66
|
+
throw new Error("2FA code required");
|
|
67
|
+
}
|
|
68
|
+
console.log(`Logged in as ${login.user?.email}`);
|
|
65
69
|
|
|
66
70
|
// List organizations
|
|
67
71
|
const orgs = await client.organizations.list();
|
|
@@ -81,12 +85,13 @@ if (orgs.length > 0) {
|
|
|
81
85
|
name: "Production Key",
|
|
82
86
|
environment: "live",
|
|
83
87
|
});
|
|
84
|
-
|
|
88
|
+
// The full key is shown once, in `secret`.
|
|
89
|
+
console.log(`Created key: ${key.prefix} (${key.secret})`);
|
|
85
90
|
|
|
86
91
|
// Query logs
|
|
87
92
|
const logs = await client.logs.query(orgId, {
|
|
88
93
|
status: "error",
|
|
89
|
-
|
|
94
|
+
limit: 50,
|
|
90
95
|
});
|
|
91
96
|
console.log(`Total logs: ${logs.total}`);
|
|
92
97
|
}
|
|
@@ -163,14 +168,26 @@ client.clearAccessToken();
|
|
|
163
168
|
### Authentication (`client.auth`)
|
|
164
169
|
|
|
165
170
|
```typescript
|
|
166
|
-
// Login (token set automatically)
|
|
167
|
-
const
|
|
171
|
+
// Login (the access token is set automatically when the answer has one)
|
|
172
|
+
const login = await client.auth.login({ email: "...", password: "..." });
|
|
173
|
+
|
|
174
|
+
// With two-factor auth on, a login without a code answers
|
|
175
|
+
// { requires2FA: true } and no tokens. Log in again with a code:
|
|
176
|
+
if (login.requires2FA) {
|
|
177
|
+
await client.auth.login({ email: "...", password: "...", twoFactorCode: "123456" });
|
|
178
|
+
// or, with a one-time backup code:
|
|
179
|
+
// await client.auth.login({ email: "...", password: "...", backupCode: "..." });
|
|
180
|
+
}
|
|
168
181
|
|
|
169
|
-
// Register
|
|
170
|
-
|
|
182
|
+
// Register — does NOT sign in. Answers { message, email } and emails a
|
|
183
|
+
// confirmation link; log in once the address is confirmed.
|
|
184
|
+
// acceptedTerms is required: pass true only after the user agreed to the
|
|
185
|
+
// Terms of Service, Privacy Policy and DPA (https://iteradian.com/terms,
|
|
186
|
+
// /privacy, /dpa). The server rejects registration (400) otherwise.
|
|
187
|
+
const { message } = await client.auth.register({
|
|
171
188
|
email: "...",
|
|
172
189
|
password: "...",
|
|
173
|
-
|
|
190
|
+
acceptedTerms: true,
|
|
174
191
|
});
|
|
175
192
|
|
|
176
193
|
// Refresh token
|
|
@@ -179,19 +196,25 @@ const tokens = await client.auth.refresh(refreshToken);
|
|
|
179
196
|
// Logout
|
|
180
197
|
await client.auth.logout();
|
|
181
198
|
|
|
199
|
+
// Email verification
|
|
200
|
+
await client.auth.verifyEmail(token);
|
|
201
|
+
await client.auth.resendVerification("user@example.com");
|
|
202
|
+
|
|
182
203
|
// Two-Factor Authentication
|
|
183
|
-
const setup = await client.auth.enable2FA(
|
|
204
|
+
const setup = await client.auth.enable2FA("password");
|
|
184
205
|
console.log(`Secret: ${setup.secret}`);
|
|
185
206
|
console.log(`QR Code: ${setup.qrCode}`);
|
|
186
|
-
await client.auth.verify2FA(
|
|
187
|
-
await client.auth.
|
|
207
|
+
const { backupCodes } = await client.auth.verify2FA("123456");
|
|
208
|
+
const fresh = await client.auth.regenerateBackupCodes("password");
|
|
209
|
+
await client.auth.disable2FA("password", "123456"); // password + current 6-digit TOTP code
|
|
188
210
|
|
|
189
211
|
// Magic Link
|
|
190
|
-
await client.auth.
|
|
212
|
+
await client.auth.requestMagicLink("user@example.com");
|
|
213
|
+
await client.auth.loginWithMagicLink(tokenFromEmail);
|
|
191
214
|
|
|
192
215
|
// Password Reset
|
|
193
|
-
await client.auth.forgotPassword(
|
|
194
|
-
await client.auth.resetPassword(
|
|
216
|
+
await client.auth.forgotPassword("user@example.com");
|
|
217
|
+
await client.auth.resetPassword(tokenFromEmail, "new-password");
|
|
195
218
|
```
|
|
196
219
|
|
|
197
220
|
### Organizations (`client.organizations`)
|
|
@@ -199,20 +222,40 @@ await client.auth.resetPassword({ token: "...", newPassword: "..." });
|
|
|
199
222
|
```typescript
|
|
200
223
|
// CRUD
|
|
201
224
|
const orgs = await client.organizations.list();
|
|
202
|
-
|
|
225
|
+
// `name`, `planId` and `acceptedTerms` are required; `slug` and
|
|
226
|
+
// `billingInterval` ("month" | "year") are optional.
|
|
227
|
+
const created = await client.organizations.create({
|
|
203
228
|
name: "My Org",
|
|
229
|
+
planId: "plan_free",
|
|
230
|
+
acceptedTerms: true,
|
|
204
231
|
slug: "my-org",
|
|
205
232
|
});
|
|
206
233
|
const org = await client.organizations.get(orgId);
|
|
234
|
+
await client.organizations.update(orgId, { name: "Renamed" });
|
|
207
235
|
await client.organizations.delete(orgId);
|
|
236
|
+
await client.organizations.leave(orgId);
|
|
237
|
+
const perms = await client.organizations.getMyPermissions(orgId);
|
|
208
238
|
|
|
209
239
|
// Members
|
|
210
240
|
const members = await client.organizations.listMembers(orgId);
|
|
211
|
-
|
|
212
|
-
email: "user@example.com",
|
|
213
|
-
role: "member",
|
|
214
|
-
});
|
|
241
|
+
await client.organizations.updateMemberRole(orgId, memberId, "viewer");
|
|
215
242
|
await client.organizations.removeMember(orgId, memberId);
|
|
243
|
+
|
|
244
|
+
// Invitations — inviting creates a pending invite; the invitee becomes a
|
|
245
|
+
// member only after accepting it (signed in, verified email).
|
|
246
|
+
const invite = await client.organizations.inviteMember(orgId, {
|
|
247
|
+
email: "user@example.com",
|
|
248
|
+
role: "developer",
|
|
249
|
+
}); // { id, email, role, status: "pending", expiresAt, createdAt }
|
|
250
|
+
const open = await client.organizations.listInvites(orgId);
|
|
251
|
+
await client.organizations.revokeInvite(orgId, invite.id);
|
|
252
|
+
|
|
253
|
+
// As the invitee
|
|
254
|
+
const { invites } = await client.organizations.listMyInvites();
|
|
255
|
+
await client.organizations.acceptInvite(invites[0].id); // or declineInvite()
|
|
256
|
+
// A user who has not accepted the current terms version gets 403
|
|
257
|
+
// (TERMS_ACCEPTANCE_REQUIRED); once they agree, accept with:
|
|
258
|
+
await client.organizations.acceptInvite(invites[0].id, { acceptedTerms: true });
|
|
216
259
|
```
|
|
217
260
|
|
|
218
261
|
### API Keys (`client.apiKeys`)
|
|
@@ -223,9 +266,12 @@ const key = await client.apiKeys.create(orgId, {
|
|
|
223
266
|
name: "Key Name",
|
|
224
267
|
environment: "live",
|
|
225
268
|
});
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
269
|
+
// The full key is shown once, in `secret`. `key.key` is a deprecated alias.
|
|
270
|
+
console.log(key.secret);
|
|
271
|
+
await client.apiKeys.update(orgId, key.id, { name: "Renamed" });
|
|
272
|
+
const newKey = await client.apiKeys.rotate(orgId, key.id); // new key in newKey.secret
|
|
273
|
+
const analytics = await client.apiKeys.getAnalytics(orgId, key.id, "7d");
|
|
274
|
+
await client.apiKeys.revoke(orgId, key.id);
|
|
229
275
|
```
|
|
230
276
|
|
|
231
277
|
### Endpoints (`client.endpoints`)
|
|
@@ -233,95 +279,135 @@ const analytics = await client.apiKeys.getAnalytics(orgId, keyId);
|
|
|
233
279
|
```typescript
|
|
234
280
|
// Networks
|
|
235
281
|
const networks = await client.endpoints.getNetworks();
|
|
282
|
+
const network = await client.endpoints.getNetwork(networkId);
|
|
236
283
|
|
|
237
284
|
// Endpoint management
|
|
238
285
|
const endpoints = await client.endpoints.list(orgId);
|
|
239
286
|
const endpoint = await client.endpoints.create(orgId, {
|
|
240
|
-
name: "
|
|
287
|
+
name: "My endpoint",
|
|
241
288
|
networkId: "...",
|
|
242
|
-
region: "
|
|
289
|
+
region: "eu_central",
|
|
243
290
|
});
|
|
244
|
-
await client.endpoints.
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
|
|
291
|
+
await client.endpoints.update(orgId, endpoint.id, { name: "Renamed" });
|
|
292
|
+
await client.endpoints.delete(orgId, endpoint.id);
|
|
293
|
+
const paused = await client.endpoints.pause(orgId, endpoint.id);
|
|
294
|
+
const resumed = await client.endpoints.resume(orgId, endpoint.id);
|
|
295
|
+
await client.endpoints.updatePriorities(orgId, [{ id: endpoint.id, priority: 2 }]);
|
|
296
|
+
|
|
297
|
+
// Health and metrics
|
|
298
|
+
const check = await client.endpoints.checkHealth(orgId, endpoint.id); // runs a check now
|
|
299
|
+
const health = await client.endpoints.getHealth(orgId, endpoint.id); // current health
|
|
300
|
+
const summary = await client.endpoints.getHealthOverview(orgId);
|
|
301
|
+
const metrics = await client.endpoints.getMetrics(orgId, endpoint.id);
|
|
302
|
+
const ranged = await client.endpoints.getMetrics(
|
|
303
|
+
orgId,
|
|
304
|
+
endpoint.id,
|
|
305
|
+
"2026-01-01T00:00:00Z",
|
|
306
|
+
"2026-01-02T00:00:00Z",
|
|
307
|
+
);
|
|
249
308
|
```
|
|
250
309
|
|
|
310
|
+
Decimal fields such as `avgLatencyMs`, `successRate` and `uptime` can arrive as
|
|
311
|
+
numeric strings; they are typed `number | string`, so use `Number(value)`.
|
|
312
|
+
|
|
251
313
|
### Usage & Dashboard
|
|
252
314
|
|
|
253
315
|
```typescript
|
|
254
|
-
// Usage
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
//
|
|
261
|
-
const data = await client.dashboard.get(orgId,
|
|
316
|
+
// Usage: a list of rows (one per key per day)
|
|
317
|
+
const rows = await client.usage.get(orgId, "2026-01-01", "2026-01-31");
|
|
318
|
+
const usage = await client.usage.getSummary(orgId);
|
|
319
|
+
|
|
320
|
+
// Dashboard. The optional second argument is the API timeRange:
|
|
321
|
+
// last_hour, last_24_hours (default), last_7_days, last_30_days or custom.
|
|
322
|
+
// The short forms "1h", "24h", "7d" and "30d" are translated.
|
|
323
|
+
const data = await client.dashboard.get(orgId, "7d");
|
|
324
|
+
const custom = await client.dashboard.get(orgId, "custom", { from: "2026-01-01", to: "2026-01-07" });
|
|
262
325
|
const health = await client.dashboard.getHealth(orgId);
|
|
263
|
-
const stats = await client.dashboard.getQuickStats(orgId,
|
|
326
|
+
const stats = await client.dashboard.getQuickStats(orgId, "24h");
|
|
327
|
+
const requestRate = await client.dashboard.getRequestRate(orgId); // { currentRate, timeSeries, ... }
|
|
328
|
+
const errorRate = await client.dashboard.getErrorRate(orgId);
|
|
329
|
+
const latency = await client.dashboard.getLatency(orgId); // { p50, p95, p99, ... }
|
|
330
|
+
const perf = await client.dashboard.getPerformance(orgId);
|
|
264
331
|
```
|
|
265
332
|
|
|
266
333
|
### Alerts (`client.alerts`)
|
|
267
334
|
|
|
268
335
|
```typescript
|
|
269
|
-
// Alerts
|
|
336
|
+
// Alerts. list() returns the alerts array; overview() also has the counters,
|
|
337
|
+
// rules and channels.
|
|
270
338
|
const alerts = await client.alerts.list(orgId);
|
|
339
|
+
const overview = await client.alerts.overview(orgId);
|
|
271
340
|
const ack = await client.alerts.acknowledge(orgId, alertId);
|
|
272
341
|
const resolved = await client.alerts.resolve(orgId, alertId);
|
|
342
|
+
await client.alerts.evaluate(orgId);
|
|
273
343
|
|
|
274
|
-
// Alert Rules
|
|
344
|
+
// Alert Rules. type is one of high_error_rate, high_latency,
|
|
345
|
+
// rate_limit_exceeded, quota_warning, service_down, key_expiring,
|
|
346
|
+
// unusual_traffic; config holds the thresholds for that type.
|
|
275
347
|
const rules = await client.alerts.listRules(orgId);
|
|
276
348
|
const rule = await client.alerts.createRule(orgId, {
|
|
277
|
-
name: "High
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
349
|
+
name: "High error rate",
|
|
350
|
+
type: "high_error_rate",
|
|
351
|
+
config: { threshold: 5 },
|
|
352
|
+
severity: "warning", // info | warning | error | critical
|
|
353
|
+
cooldownSeconds: 900, // at least 60
|
|
282
354
|
isEnabled: true,
|
|
283
|
-
cooldownMinutes: 15,
|
|
284
355
|
});
|
|
285
|
-
await client.alerts.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
356
|
+
await client.alerts.updateRule(orgId, rule.id, { name: "Renamed" });
|
|
357
|
+
await client.alerts.toggleRule(orgId, rule.id);
|
|
358
|
+
await client.alerts.seedDefaults(orgId);
|
|
359
|
+
await client.alerts.deleteRule(orgId, rule.id);
|
|
360
|
+
|
|
361
|
+
// Channels. type is email | webhook | slack.
|
|
362
|
+
const channels = await client.alerts.listChannels(orgId);
|
|
363
|
+
const channel = await client.alerts.createChannel(orgId, {
|
|
364
|
+
name: "Ops webhook",
|
|
365
|
+
type: "webhook",
|
|
366
|
+
config: { url: "https://example.com/hook" },
|
|
367
|
+
});
|
|
368
|
+
await client.alerts.updateChannel(orgId, channel.id, { isEnabled: false });
|
|
369
|
+
await client.alerts.testChannel(orgId, channel.id);
|
|
370
|
+
await client.alerts.deleteChannel(orgId, channel.id);
|
|
290
371
|
```
|
|
291
372
|
|
|
292
373
|
### Logs (`client.logs`)
|
|
293
374
|
|
|
294
375
|
```typescript
|
|
295
|
-
// Query with filters
|
|
376
|
+
// Query with filters. Page with limit (1-200) and offset.
|
|
296
377
|
const logs = await client.logs.query(orgId, {
|
|
297
|
-
|
|
298
|
-
|
|
378
|
+
limit: 50,
|
|
379
|
+
offset: 0,
|
|
299
380
|
status: "error",
|
|
300
381
|
method: "eth_call",
|
|
301
|
-
network: "
|
|
382
|
+
network: "eth-mainnet",
|
|
383
|
+
minLatencyMs: 100,
|
|
302
384
|
sortBy: "timestamp",
|
|
303
385
|
sortOrder: "desc",
|
|
304
386
|
});
|
|
305
|
-
console.log(
|
|
387
|
+
console.log(`${logs.logs.length} of ${logs.total}`);
|
|
306
388
|
for (const log of logs.logs) {
|
|
307
389
|
console.log(` [${log.status}] ${log.method} (${log.latencyMs}ms)`);
|
|
308
390
|
}
|
|
309
391
|
|
|
310
392
|
// Get single log
|
|
311
|
-
const log = await client.logs.get(orgId,
|
|
393
|
+
const log = await client.logs.get(orgId, logs.logs[0].id);
|
|
312
394
|
|
|
313
395
|
// Filter options
|
|
314
396
|
const filters = await client.logs.getFilterOptions(orgId);
|
|
315
397
|
|
|
316
398
|
// Stats
|
|
317
|
-
const stats = await client.logs.getStats(orgId
|
|
399
|
+
const stats = await client.logs.getStats(orgId);
|
|
318
400
|
```
|
|
319
401
|
|
|
320
402
|
### Subscriptions (`client.subscriptions`)
|
|
321
403
|
|
|
322
404
|
```typescript
|
|
323
405
|
const sub = await client.subscriptions.get(orgId);
|
|
324
|
-
|
|
406
|
+
// The caller confirms the user accepted the plan-change billing terms; the
|
|
407
|
+
// server rejects the change (400) unless acceptedTerms is true.
|
|
408
|
+
const updated = await client.subscriptions.changePlan(orgId, "plan_builder", {
|
|
409
|
+
acceptedTerms: true,
|
|
410
|
+
});
|
|
325
411
|
const cancelled = await client.subscriptions.cancel(orgId);
|
|
326
412
|
const reactivated = await client.subscriptions.reactivate(orgId);
|
|
327
413
|
const invoices = await client.subscriptions.getInvoices(orgId);
|
|
@@ -337,22 +423,41 @@ const plan = await client.plans.get(planId);
|
|
|
337
423
|
### Support (`client.support`)
|
|
338
424
|
|
|
339
425
|
```typescript
|
|
426
|
+
// listTickets() returns the tickets array.
|
|
340
427
|
const tickets = await client.support.listTickets(orgId);
|
|
341
428
|
const ticket = await client.support.createTicket(orgId, {
|
|
342
429
|
subject: "API returning 500 errors",
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
430
|
+
body: "Detailed description...",
|
|
431
|
+
category: "technical", // optional
|
|
432
|
+
priority: "high", // optional: low | medium | high | urgent
|
|
346
433
|
});
|
|
347
|
-
const
|
|
348
|
-
await client.support.
|
|
349
|
-
|
|
434
|
+
const stats = await client.support.getStats(orgId);
|
|
435
|
+
const detail = await client.support.getTicket(orgId, ticket.id);
|
|
436
|
+
await client.support.addMessage(orgId, ticket.id, "Follow-up message...");
|
|
437
|
+
await client.support.updateStatus(orgId, ticket.id, "resolved");
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### RPC (`client.rpc`)
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
const gateway = new IteradianClient({ apiKey: "itrd_live_..." });
|
|
444
|
+
const networks = await gateway.rpc.networks();
|
|
445
|
+
const res = await gateway.rpc.call("eth-mainnet", {
|
|
446
|
+
jsonrpc: "2.0",
|
|
447
|
+
method: "eth_blockNumber",
|
|
448
|
+
params: [],
|
|
449
|
+
id: 1,
|
|
350
450
|
});
|
|
451
|
+
const batch = await gateway.rpc.batch("eth-mainnet", [
|
|
452
|
+
{ jsonrpc: "2.0", method: "eth_blockNumber", params: [], id: 1 },
|
|
453
|
+
{ jsonrpc: "2.0", method: "eth_chainId", params: [], id: 2 },
|
|
454
|
+
]);
|
|
351
455
|
```
|
|
352
456
|
|
|
353
457
|
## Type Definitions
|
|
354
458
|
|
|
355
|
-
All types are exported from the package and defined in `src/types.ts`
|
|
459
|
+
All types are exported from the package and defined in `src/types.ts`. Response fields are optional except `id`; decimal
|
|
460
|
+
fields are typed `number | string` (`Numeric`):
|
|
356
461
|
|
|
357
462
|
### Configuration
|
|
358
463
|
|
|
@@ -362,66 +467,75 @@ All types are exported from the package and defined in `src/types.ts` (538 lines
|
|
|
362
467
|
|
|
363
468
|
### Auth Types
|
|
364
469
|
|
|
365
|
-
| Type
|
|
366
|
-
|
|
|
367
|
-
| `LoginRequest`
|
|
368
|
-
| `RegisterRequest`
|
|
369
|
-
| `
|
|
370
|
-
| `
|
|
470
|
+
| Type | Fields |
|
|
471
|
+
| ------------------ | ------------------------------------------------------------------- |
|
|
472
|
+
| `LoginRequest` | `email`, `password`, `twoFactorCode?`, `backupCode?` |
|
|
473
|
+
| `RegisterRequest` | `email`, `password`, `acceptedTerms` |
|
|
474
|
+
| `RegisterResponse` | `message`, `email` (no tokens) |
|
|
475
|
+
| `LoginResult` | `accessToken?`, `refreshToken?`, `user?`, `requires2FA?` |
|
|
476
|
+
| `AuthTokens` | `accessToken`, `refreshToken`, `user?` (refresh) |
|
|
477
|
+
| `TwoFASetup` | `secret`, `qrCode` |
|
|
371
478
|
|
|
372
479
|
### Organization Types
|
|
373
480
|
|
|
374
|
-
| Type
|
|
375
|
-
|
|
|
376
|
-
| `Organization`
|
|
377
|
-
| `OrgMember`
|
|
378
|
-
| `
|
|
379
|
-
| `
|
|
481
|
+
| Type | Fields |
|
|
482
|
+
| --------------------------- | ----------------------------------------------------------------------- |
|
|
483
|
+
| `Organization` | `id`, `name?`, `slug?`, `role?`, `subscription?`, `members?` |
|
|
484
|
+
| `OrgMember` | `id`, `userId?`, `email?`, `role?`, `joinedAt?` |
|
|
485
|
+
| `CreateOrganizationRequest` | `name`, `planId`, `acceptedTerms`, `slug?`, `billingInterval?` |
|
|
486
|
+
| `OrgInvite` | `id`, `email?`, `role?`, `status?`, `expiresAt?`, `createdAt?`, `invitedBy?` |
|
|
487
|
+
| `MyInvites` | `emailVerified?`, `invites` (`MyInvite[]`) |
|
|
488
|
+
| `InviteAcceptance` | `organizationId?`, `membershipId?`, `role?` |
|
|
380
489
|
|
|
381
490
|
### API Key Types
|
|
382
491
|
|
|
383
|
-
| Type | Fields
|
|
384
|
-
| --------------------- |
|
|
385
|
-
| `ApiKey` | `id`, `name
|
|
386
|
-
| `
|
|
492
|
+
| Type | Fields |
|
|
493
|
+
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
494
|
+
| `ApiKey` | `id`, `name?`, `prefix?`, `environment?`, `status?`, `ipAllowlist?`, `allowedNetworks?`, `rateLimit?`, `dailyLimit?`, `expiresAt?`, `lastUsedAt?`, `createdAt?` |
|
|
495
|
+
| `ApiKeyWithSecret` | `ApiKey` plus `secret` (create and rotate) and `key` (deprecated alias of `secret`) |
|
|
496
|
+
| `CreateApiKeyRequest` | `name`, `environment`, `ipAllowlist?`, `allowedNetworks?`, `rateLimit?`, `dailyLimit?`, `expiresAt?`, `walletUrlAuth?` |
|
|
387
497
|
|
|
388
498
|
### Network & Endpoint Types
|
|
389
499
|
|
|
390
|
-
| Type | Fields
|
|
391
|
-
| ----------------------- |
|
|
392
|
-
| `Network` | `id`, `
|
|
393
|
-
| `Endpoint` | `id`, `
|
|
394
|
-
| `CreateEndpointRequest` | `name`, `networkId`, `region`, `priority?`, `timeoutMs?`, `retryCount?`
|
|
500
|
+
| Type | Fields |
|
|
501
|
+
| ----------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
502
|
+
| `Network` | `id`, `name?`, `chainId?`, `type?`, `environment?`, `nativeCurrency?`, `isActive?` |
|
|
503
|
+
| `Endpoint` | `id`, `networkId?`, `region?`, `name?`, `priority?`, `status?`, `isEnabled?`, `timeoutMs?`, `retryCount?`, metrics |
|
|
504
|
+
| `CreateEndpointRequest` | `name`, `networkId`, `region`, `priority?`, `timeoutMs?`, `retryCount?`, `rateLimitOverride?` |
|
|
505
|
+
| `EndpointHealth` | `status?`, `nodeCount?`, `healthyNodeCount?`, `latencyMs?`, `lastCheck?` |
|
|
395
506
|
|
|
396
507
|
### Logging Types
|
|
397
508
|
|
|
398
|
-
| Type | Fields
|
|
399
|
-
| ---------------- |
|
|
400
|
-
| `RequestLog` | `id`, `
|
|
401
|
-
| `LogsResponse` | `logs`, `total
|
|
402
|
-
| `LogQueryParams` | `
|
|
509
|
+
| Type | Fields |
|
|
510
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
511
|
+
| `RequestLog` | `id`, `method?`, `status?`, `statusCode?`, `latencyMs?`, `network?`, `region?`, `timestamp?` |
|
|
512
|
+
| `LogsResponse` | `logs`, `total?`, `stats?` |
|
|
513
|
+
| `LogQueryParams` | `limit?`, `offset?`, `status?`, `method?`, `apiKeyId?`, `network?`, `region?`, `search?`, `statusCode?`, `minLatencyMs?`, `maxLatencyMs?`, `from?`, `to?`, `sortBy?`, `sortOrder?` |
|
|
403
514
|
|
|
404
515
|
### Alert Types
|
|
405
516
|
|
|
406
|
-
| Type
|
|
407
|
-
|
|
|
408
|
-
| `Alert`
|
|
409
|
-
| `AlertRule`
|
|
410
|
-
| `CreateAlertRuleRequest`
|
|
517
|
+
| Type | Fields |
|
|
518
|
+
| -------------------------- | -------------------------------------------------------------------------------------------- |
|
|
519
|
+
| `Alert` | `id`, `ruleId?`, `type?`, `severity?`, `status?`, `title?`, `message?`, `firedAt?`, `metadata?` |
|
|
520
|
+
| `AlertRule` | `id`, `name?`, `type?`, `severity?`, `isEnabled?`, `config?`, `cooldownSeconds?` |
|
|
521
|
+
| `CreateAlertRuleRequest` | `name`, `type`, `config`, `severity?`, `cooldownSeconds?`, `isEnabled?` |
|
|
522
|
+
| `AlertChannel` | `id`, `name?`, `type?`, `isEnabled?`, `config?` |
|
|
523
|
+
| `CreateAlertChannelRequest` | `name`, `type`, `config`, `isEnabled?` |
|
|
411
524
|
|
|
412
525
|
### Billing Types
|
|
413
526
|
|
|
414
|
-
| Type | Fields
|
|
415
|
-
| -------------- |
|
|
416
|
-
| `Plan` | `id`, `name
|
|
417
|
-
| `Subscription` | `id`, `
|
|
527
|
+
| Type | Fields |
|
|
528
|
+
| -------------- | ------------------------------------------------------------------------------------------------------- |
|
|
529
|
+
| `Plan` | `id`, `name?`, `displayName?`, `priceMonthly?`, `limits?`, `features?`, `isActive?` |
|
|
530
|
+
| `Subscription` | `id`, `status?`, `plan?`, `billingInterval?`, `currentPeriodEnd?`, `cancelAtPeriodEnd?`, `recentInvoices?` |
|
|
418
531
|
|
|
419
532
|
### Support Types
|
|
420
533
|
|
|
421
|
-
| Type | Fields
|
|
422
|
-
| --------------------- |
|
|
423
|
-
| `SupportTicket` | `id`, `
|
|
424
|
-
| `CreateTicketRequest` | `subject`, `
|
|
534
|
+
| Type | Fields |
|
|
535
|
+
| --------------------- | ------------------------------------------------------------------------------ |
|
|
536
|
+
| `SupportTicket` | `id`, `subject?`, `category?`, `priority?`, `status?`, `messages?`, `createdBy?` |
|
|
537
|
+
| `CreateTicketRequest` | `subject`, `body`, `category?`, `priority?` |
|
|
538
|
+
| `TicketMessage` | `id`, `body?`, `isStaff?`, `author?`, `createdAt?` |
|
|
425
539
|
|
|
426
540
|
### Error Types
|
|
427
541
|
|
|
@@ -441,7 +555,7 @@ try {
|
|
|
441
555
|
} catch (err) {
|
|
442
556
|
if (err instanceof IteradianError) {
|
|
443
557
|
console.log(`Status: ${err.statusCode}`); // 401
|
|
444
|
-
console.log(`Message: ${err.message}`); // "Invalid credentials"
|
|
558
|
+
console.log(`Message: ${err.message}`); // "Invalid credentials" (validation errors: messages joined with ", ")
|
|
445
559
|
console.log(`Error: ${err.error}`); // Error code
|
|
446
560
|
} else {
|
|
447
561
|
console.log(`Unexpected error: ${err}`);
|
|
@@ -449,6 +563,16 @@ try {
|
|
|
449
563
|
}
|
|
450
564
|
```
|
|
451
565
|
|
|
566
|
+
### Terms acceptance (403 `TERMS_ACCEPTANCE_REQUIRED`)
|
|
567
|
+
|
|
568
|
+
After Iteradian publishes a new version of the Terms of Service, Privacy
|
|
569
|
+
Policy or DPA, any write (POST/PUT/PATCH/DELETE) made with a user JWT may
|
|
570
|
+
answer `IteradianError` with `statusCode` 403 until the user accepts the new
|
|
571
|
+
version in the dashboard (the response body carries
|
|
572
|
+
`code: "TERMS_ACCEPTANCE_REQUIRED"`, `termsVersion` and `termsUrl`). API keys
|
|
573
|
+
and agent tokens are unaffected. `organizations.acceptInvite(id, {
|
|
574
|
+
acceptedTerms: true })` records the acceptance as part of joining.
|
|
575
|
+
|
|
452
576
|
On a gateway call the same error also carries the JSON-RPC detail, which is how
|
|
453
577
|
you tell "wait a second" from "you are out of quota until the period rolls
|
|
454
578
|
over":
|
|
@@ -465,6 +589,9 @@ try {
|
|
|
465
589
|
if (err instanceof IteradianError) {
|
|
466
590
|
if (err.isRateLimited) {
|
|
467
591
|
// -32005. Wait err.retryAfter seconds and try again.
|
|
592
|
+
} else if (err.isDailyLimitReached) {
|
|
593
|
+
// -32008. This API key's daily limit is used up. err.data carries
|
|
594
|
+
// { dailyLimit, used, cost, resetsAt }; resetsAt is the next 00:00 UTC.
|
|
468
595
|
} else if (err.isQuotaExhausted) {
|
|
469
596
|
// -32006 or -32007. Retrying will not help: err.data.resetsAt says when
|
|
470
597
|
// the allowance returns, and the cap needs a plan change.
|
|
@@ -489,8 +616,9 @@ The SDK automatically retries:
|
|
|
489
616
|
- **5xx Server Errors** — with exponential backoff
|
|
490
617
|
- **429 Too Many Requests**, but **only** `-32005` (rate or concurrency limit).
|
|
491
618
|
`-32006` (monthly quota exhausted) and `-32007` (overage spend cap) do not
|
|
492
|
-
recover until the billing period rolls over,
|
|
493
|
-
|
|
619
|
+
recover until the billing period rolls over, and `-32008` (per-API-key daily
|
|
620
|
+
limit) not until `error.data.resetsAt` (the next 00:00 UTC), so retrying
|
|
621
|
+
them burns your time for a guaranteed 429.
|
|
494
622
|
|
|
495
623
|
Backoff formula: `min(1000 * 2^(attempt-1), 10000)` ms, or the gateway's own
|
|
496
624
|
`retryAfter` hint when it gives one — capped at 30 seconds either way.
|
|
@@ -622,10 +750,61 @@ This SDK takes both, and defaults the gateway to `https://rpc.iteradian.com`.
|
|
|
622
750
|
organization holds. Creating more keys does not raise them.
|
|
623
751
|
- The gateway returns HTTP 429 with a JSON-RPC error body:
|
|
624
752
|
`-32005` rate limited (retry after `error.data.retryAfter`), `-32006` monthly
|
|
625
|
-
quota exhausted, `-32007` overage spend cap reached
|
|
626
|
-
|
|
753
|
+
quota exhausted, `-32007` overage spend cap reached, `-32008` the API key's
|
|
754
|
+
own daily limit reached (`error.data = { dailyLimit, used, cost, resetsAt }`).
|
|
755
|
+
None of the last three recover before `resetsAt` (the billing period roll-over,
|
|
756
|
+
or the next 00:00 UTC for `-32008`), so retrying them is wasted work.
|
|
757
|
+
|
|
758
|
+
Plans (defaults; an admin can change them): Free 25 rps / 3M per month with no
|
|
759
|
+
overage (requests stop at the quota, no card needed), Developer 100 rps / 5M
|
|
760
|
+
with overage at $6 per million, Professional 500 rps / 30M at $4.50 per million,
|
|
761
|
+
Dedicated per contract from $4 per million. Trials are offered on Developer
|
|
762
|
+
only; a trial that ends unpaid falls back to Free. See `sdks/SDK_CONTRACT.md`
|
|
763
|
+
for the full table.
|
|
764
|
+
|
|
765
|
+
### WebSocket
|
|
766
|
+
|
|
767
|
+
The gateway also serves JSON-RPC over WebSocket at
|
|
768
|
+
`wss://rpc.iteradian.com/ws/v1/{network}`. This SDK does not wrap it on
|
|
769
|
+
purpose: connect with any WebSocket client, such as ethers
|
|
770
|
+
`WebSocketProvider`, viem's `webSocket()` transport, or the built-in
|
|
771
|
+
`WebSocket` in browsers and Node 22+. Authenticate with the
|
|
772
|
+
`X-Api-Key` header, `Authorization: Bearer <key>`, or `?apiKey=<key>` on the
|
|
773
|
+
URL (browsers cannot set headers on a WebSocket).
|
|
627
774
|
|
|
628
|
-
|
|
629
|
-
|
|
775
|
+
```typescript
|
|
776
|
+
const ws = new WebSocket(
|
|
777
|
+
"wss://rpc.iteradian.com/ws/v1/eth-mainnet?apiKey=itrd_live_...",
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
ws.addEventListener("open", () => {
|
|
781
|
+
ws.send(JSON.stringify({
|
|
782
|
+
jsonrpc: "2.0", id: 1, method: "eth_subscribe", params: ["newHeads"],
|
|
783
|
+
}));
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
ws.addEventListener("message", (event) => {
|
|
787
|
+
const msg = JSON.parse(event.data);
|
|
788
|
+
if (msg.method === "eth_subscription") {
|
|
789
|
+
console.log("new head", msg.params.result.number);
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
ws.addEventListener("close", (event) => {
|
|
794
|
+
// 1012: node restarted, reconnect and re-subscribe. 4003: key revoked, stop.
|
|
795
|
+
console.log("closed", event.code);
|
|
796
|
+
});
|
|
797
|
+
```
|
|
630
798
|
|
|
631
|
-
|
|
799
|
+
- Each message you send is charged like an HTTP request (a batch of N costs N).
|
|
800
|
+
Subscription notifications pushed to you are not charged.
|
|
801
|
+
- A message refused by a limit gets an ordinary JSON-RPC error under that
|
|
802
|
+
call's `id`, with the same codes as above (`-32005` to `-32008`). The socket
|
|
803
|
+
stays open.
|
|
804
|
+
- An organization can hold `max(5, floor(concurrency / 4))` streams at once;
|
|
805
|
+
past that the upgrade is refused with HTTP 429. Other upgrade failures: 400
|
|
806
|
+
bad path, 401/403 bad key, 404 unknown network, 503 no WebSocket-capable node.
|
|
807
|
+
- Close code `1012` means the upstream node restarted: reconnect and
|
|
808
|
+
re-subscribe. `4003` means the key was revoked or the organization suspended
|
|
809
|
+
(keys are re-checked every 60 s): do not reconnect.
|
|
810
|
+
- The server pings every 30 s. Messages are limited to 1 MB.
|