quicknode_sdk 0.1.0 → 0.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.
data/README.md ADDED
@@ -0,0 +1,1647 @@
1
+ # quicknode_sdk (Ruby)
2
+
3
+ Ruby bindings for the Quicknode SDK.
4
+
5
+ This is one of four language bindings published from the same Rust core. See the [project README](https://github.com/quicknode/sdk/blob/main/README.md) for the polyglot overview, development setup, and release process.
6
+
7
+ > **Pre-1.0**: While on `0.x`, releases may contain breaking changes. Check the [release notes](https://github.com/quicknode/sdk/releases) before upgrading.
8
+
9
+ ## Table of Contents
10
+
11
+ - [Installation](#installation)
12
+ - [Quick Start](#quick-start)
13
+ - [Configuration](#configuration)
14
+ - [Platform Support](#platform-support)
15
+ - [API Reference](#api-reference)
16
+ - [Admin Client](#admin-client)
17
+ - [Endpoints](#endpoints)
18
+ - [Endpoint Tags](#endpoint-tags)
19
+ - [Teams](#teams)
20
+ - [Usage](#usage)
21
+ - [Logs](#logs)
22
+ - [Endpoint Security](#endpoint-security)
23
+ - [Security Options](#security-options)
24
+ - [Tokens](#tokens)
25
+ - [Referrers](#referrers)
26
+ - [IPs](#ips)
27
+ - [Domain Masks](#domain-masks)
28
+ - [JWTs](#jwts)
29
+ - [Request Filters](#request-filters)
30
+ - [Multichain](#multichain)
31
+ - [IP Custom Headers](#ip-custom-headers)
32
+ - [Method Rate Limits](#method-rate-limits)
33
+ - [Endpoint Rate Limits](#endpoint-rate-limits)
34
+ - [Endpoint URLs](#endpoint-urls)
35
+ - [Metrics](#metrics)
36
+ - [Chains](#chains)
37
+ - [Billing](#billing)
38
+ - [Bulk Operations](#bulk-operations)
39
+ - [Account Tags](#account-tags)
40
+ - [Streams Client](#streams-client)
41
+ - [Datasets, Regions, and Destinations](#datasets-regions-and-destinations)
42
+ - [Streams methods](#streams-methods)
43
+ - [Webhooks Client](#webhooks-client)
44
+ - [Templates and destination](#templates-and-destination)
45
+ - [Webhooks methods](#webhooks-methods)
46
+ - [KV Store Client](#kv-store-client)
47
+ - [Sets](#sets)
48
+ - [Lists](#lists)
49
+ - [Error Handling](#error-handling)
50
+ - [License](#license)
51
+
52
+ ## Installation
53
+
54
+ `gem install quicknode_sdk`
55
+
56
+ ## Quick Start
57
+
58
+ Construct the SDK once, then reach into the four sub-clients (`admin`, `streams`, `webhooks`, `kvstore`). Subsequent API Reference snippets assume you have a `qn` handle from one of these blocks.
59
+
60
+ ```ruby
61
+ # Ruby
62
+ require "quicknode_sdk"
63
+
64
+ qn = QuicknodeSdk::SDK.from_env
65
+ resp = qn.admin.get_endpoints
66
+ puts "#{resp[:data].length} endpoints"
67
+ ```
68
+
69
+ ## Configuration
70
+
71
+ There are two ways to configure the SDK.
72
+
73
+ ### Option A — Pass config directly
74
+
75
+ ```ruby
76
+ qn = QuicknodeSdk::SDK.from_config(api_key: "your-key")
77
+ ```
78
+
79
+ ### Option B — Load from environment (`from_env()`)
80
+
81
+ ```ruby
82
+ # Ruby
83
+ qn = QuicknodeSdk::SDK.from_env
84
+ ```
85
+
86
+ Environment variables (prefix `QN_SDK__`, separator `__`):
87
+
88
+ | Variable | Required | Default | Description |
89
+ |----------|----------|---------|-------------|
90
+ | `QN_SDK__API_KEY` | yes | — | Your Quicknode API key |
91
+ | `QN_SDK__HTTP__TIMEOUT_SECS` | no | 30 | HTTP request timeout in seconds |
92
+ | `QN_SDK__HTTP__POOL_MAX_IDLE_PER_HOST` | no | — | Max idle HTTP connections per host |
93
+ | `QN_SDK__ADMIN__BASE_URL` | no | `https://api.quicknode.com/v0/` | Override admin API base URL (HTTPS, must end with `/`) |
94
+ | `QN_SDK__STREAMS__BASE_URL` | no | `https://api.quicknode.com/streams/rest/v1/` | Override streams base URL |
95
+ | `QN_SDK__WEBHOOKS__BASE_URL` | no | `https://api.quicknode.com/webhooks/rest/v1/` | Override webhooks base URL |
96
+ | `QN_SDK__KVSTORE__BASE_URL` | no | `https://api.quicknode.com/kv/rest/v1/` | Override KV store base URL |
97
+ | `QN_SDK__HTTP__HEADERS__<NAME>` | no | — | Custom HTTP header sent on every request. Overrides SDK-managed headers (see below). |
98
+
99
+ ### Custom headers and `User-Agent`
100
+
101
+ Every outbound HTTP request includes an auto-generated `User-Agent` of the form:
102
+
103
+ ```
104
+ quicknode-sdk-<language>/<sdk-version> (<os>-<arch>; <language>-<runtime-version>)
105
+ ```
106
+
107
+ You can attach arbitrary headers via `HttpConfig.headers`. **These headers OVERRIDE any SDK-managed header with the same name**, including `User-Agent`, `x-api-key`, `Accept`, and `Content-Type`. Use this to inject correlation IDs, proxy auth, or to replace the default `User-Agent`. Header names are matched case-insensitively.
108
+
109
+ ```ruby
110
+ qn = QuicknodeSdk::SDK.from_config(
111
+ api_key: "your-key",
112
+ http: {
113
+ headers: {
114
+ "X-Correlation-Id" => "abc-123",
115
+ "User-Agent" => "my-app/1.0", # overrides SDK default
116
+ },
117
+ },
118
+ )
119
+ ```
120
+
121
+ You can also set custom headers via env vars (`QN_SDK__HTTP__HEADERS__<NAME>`) when using `from_env`.
122
+
123
+ ## Platform Support
124
+
125
+ Precompiled platform gems are published for:
126
+
127
+ | Platform | Targets |
128
+ |---|---|
129
+ | Linux (glibc) | `x86_64-linux`, `aarch64-linux` — glibc **2.17+** (manylinux2014) |
130
+ | macOS | Apple Silicon (`arm64-darwin`) |
131
+
132
+ Linux gems are built against glibc 2.17 so they load on any distro from 2014 onward — RHEL 7+, Ubuntu 14.04+, Debian 8+, Amazon Linux 2+, SLES 12+, Fedora 19+.
133
+
134
+ **Not supported:** Alpine and other musl-libc distros (the Rust cdylib that backs the gem requires the dynamic linker glibc provides), RHEL/CentOS 6 (glibc 2.12), Debian 7 (glibc 2.13), Ubuntu 12.04 (glibc 2.15), Intel macOS, Windows. The `ruby`-platform fallback gem is present only so Bundler's resolver can complete on those platforms — `require "quicknode_sdk"` raises a `LoadError` listing the supported platforms.
135
+
136
+ ## API Reference
137
+
138
+ Snippets assume `qn` was already constructed via the Quick Start. Optional parameters are skipped unless showing one is needed to illustrate usage.
139
+
140
+ ### Language conventions
141
+
142
+ - Methods are **blocking** (not async). Parameters are a single Hash with symbol keys. Unknown parameter keys raise `ArgumentError`.
143
+ - **Response shape.** Every method that returns data returns a `QuicknodeSdk::IndifferentHash` — a plain `Hash` subclass with `Hashie::Extensions::IndifferentAccess`. Access values with `resp[:data]`, `resp["data"]`, or `resp.dig(:data, :id)`. Nested hashes and arrays are wrapped recursively, so symbol or string keys work at every level. **Dot accessors (`resp.data.id`) do not work** — there is no `MethodAccess` extension on this class. Use `[]` or `dig`.
144
+ - **Pagination key naming differs across products** because the underlying APIs do. Admin list endpoints return `resp[:pagination]` (`{ total, limit, offset }`); streams and webhooks list endpoints return `resp[:pageInfo]` (same shape, camelCase). Per-method `**Returns**` blocks note which one applies.
145
+
146
+ ---
147
+
148
+ ### Admin Client
149
+
150
+ Accessed as `qn.admin`. Manages endpoints, tags, teams, billing, usage, metrics, security, and rate limits. Backed by `https://api.quicknode.com/v0/`.
151
+
152
+ #### Endpoints
153
+
154
+ ##### `get_endpoints` / `getEndpoints`
155
+
156
+ Returns a paginated list of endpoints on the account with optional search, filters (networks, statuses, labels, tags, dedicated, flat-rate), sorting, and pagination.
157
+
158
+ **Parameters** (all optional): `limit` (i32), `offset` (i32), `search` (string), `sort_by` (string), `sort_direction` (`"asc"` | `"desc"`), `networks` (string[]), `statuses` (string[]), `labels` (string[]), `dedicated` (bool), `is_flat_rate` (bool), `tag_ids` (i32[]), `tag_labels` (string[]).
159
+
160
+ **Returns**: `GetEndpointsResponse` — `{ data: Endpoint[], pagination?: Pagination }`.
161
+
162
+ ```ruby
163
+ # Ruby
164
+ resp = qn.admin.get_endpoints(limit: 20, sort_by: "created_at", sort_direction: "desc")
165
+ ```
166
+
167
+ ##### `create_endpoint` / `createEndpoint`
168
+
169
+ Creates a new endpoint for the given blockchain and network.
170
+
171
+ **Parameters**: `chain` (string, optional), `network` (string, optional).
172
+
173
+ **Returns**: `CreateEndpointResponse` with `data: SingleEndpoint`.
174
+
175
+ ```ruby
176
+ # Ruby
177
+ resp = qn.admin.create_endpoint(chain: "ethereum", network: "mainnet")
178
+ ```
179
+
180
+ ##### `show_endpoint` / `showEndpoint`
181
+
182
+ Fetches a single endpoint by id, including its full security configuration and rate limits.
183
+
184
+ **Parameters**: `id` (string, required).
185
+
186
+ **Returns**: `ShowEndpointResponse` with `data: SingleEndpoint`.
187
+
188
+ ```ruby
189
+ # Ruby
190
+ resp = qn.admin.show_endpoint(id: "ep-123")
191
+ ```
192
+
193
+ ##### `update_endpoint` / `updateEndpoint`
194
+
195
+ Updates editable fields on an endpoint. Currently supports `label`.
196
+
197
+ **Parameters**: `id` (string, required); body: `label` (string, optional).
198
+
199
+ **Returns**: nothing.
200
+
201
+ ```ruby
202
+ # Ruby
203
+ qn.admin.update_endpoint(id: "ep-123", label: "my label")
204
+ ```
205
+
206
+ ##### `archive_endpoint` / `archiveEndpoint`
207
+
208
+ Archives an endpoint. The HTTP verb is `DELETE` but the effect is archival, not permanent deletion.
209
+
210
+ **Parameters**: `id` (string, required).
211
+
212
+ **Returns**: nothing.
213
+
214
+ ```ruby
215
+ # Ruby
216
+ qn.admin.archive_endpoint(id: "ep-123")
217
+ ```
218
+
219
+ ##### `update_endpoint_status` / `updateEndpointStatus`
220
+
221
+ Pauses or unpauses an endpoint.
222
+
223
+ **Parameters**: `id` (string, required); body: `status` (string, required — `"active"` or `"paused"`).
224
+
225
+ **Returns**: `UpdateEndpointStatusResponse`.
226
+
227
+ ```ruby
228
+ # Ruby
229
+ qn.admin.update_endpoint_status(id: "ep-123", status: "paused")
230
+ ```
231
+
232
+ #### Endpoint Tags
233
+
234
+ Per-endpoint tag add/remove. For account-wide tag management see [Account Tags](#account-tags).
235
+
236
+ ##### `create_tag` / `createTag`
237
+
238
+ Tags an endpoint with the given label. Creates the tag on the account if it does not exist.
239
+
240
+ **Parameters**: `id` (string, required); body: `label` (string, optional).
241
+
242
+ **Returns**: nothing.
243
+
244
+ ```ruby
245
+ # Ruby
246
+ qn.admin.create_tag(id: "ep-123", label: "prod")
247
+ ```
248
+
249
+ ##### `delete_tag` / `deleteTag`
250
+
251
+ Removes a tag from a specific endpoint.
252
+
253
+ **Parameters**: `id` (endpoint id, string, required), `tag_id` (string, required).
254
+
255
+ **Returns**: nothing.
256
+
257
+ ```ruby
258
+ # Ruby
259
+ qn.admin.delete_tag(id: "ep-123", tag_id: "42")
260
+ ```
261
+
262
+ #### Teams
263
+
264
+ ##### `list_teams` / `listTeams`
265
+
266
+ Lists all teams on the account.
267
+
268
+ **Parameters**: none.
269
+
270
+ **Returns**: `ListTeamsResponse` with `data: TeamSummary[]`.
271
+
272
+ ```ruby
273
+ # Ruby
274
+ resp = qn.admin.list_teams
275
+ ```
276
+
277
+ ##### `create_team` / `createTeam`
278
+
279
+ Creates a new team.
280
+
281
+ **Parameters**: `name` (string, required).
282
+
283
+ **Returns**: `CreateTeamResponse` with `data: CreateTeamData`.
284
+
285
+ ```ruby
286
+ # Ruby
287
+ resp = qn.admin.create_team(name: "Payments")
288
+ ```
289
+
290
+ ##### `get_team` / `getTeam`
291
+
292
+ Fetches team detail including pending invites.
293
+
294
+ **Parameters**: `id` (i64, required).
295
+
296
+ **Returns**: `GetTeamResponse` with `data: TeamDetail`.
297
+
298
+ ```ruby
299
+ # Ruby
300
+ resp = qn.admin.get_team(id: 42)
301
+ ```
302
+
303
+ ##### `delete_team` / `deleteTeam`
304
+
305
+ Deletes a team.
306
+
307
+ **Parameters**: `id` (i64, required).
308
+
309
+ **Returns**: `DeleteTeamResponse`.
310
+
311
+ ```ruby
312
+ # Ruby
313
+ qn.admin.delete_team(id: 42)
314
+ ```
315
+
316
+ ##### `list_team_endpoints` / `listTeamEndpoints`
317
+
318
+ Lists endpoints accessible to a team.
319
+
320
+ **Parameters**: `id` (i64, required).
321
+
322
+ **Returns**: `ListTeamEndpointsResponse` with `data: TeamEndpoint[]`.
323
+
324
+ ```ruby
325
+ # Ruby
326
+ resp = qn.admin.list_team_endpoints(id: 42)
327
+ ```
328
+
329
+ ##### `update_team_endpoints` / `updateTeamEndpoints`
330
+
331
+ Replaces the set of endpoints associated with a team. Pass an empty array to remove all.
332
+
333
+ **Parameters**: `id` (i64, required); body: `endpoint_ids` (string[], required).
334
+
335
+ **Returns**: `UpdateTeamEndpointsResponse`.
336
+
337
+ ```ruby
338
+ # Ruby
339
+ qn.admin.update_team_endpoints(id: 42, endpoint_ids: ["ep-123", "ep-456"])
340
+ ```
341
+
342
+ ##### `invite_team_member` / `inviteTeamMember`
343
+
344
+ Invites a user to a team. Existing users only need `email`; new users require `full_name` and `role`.
345
+
346
+ **Parameters**: `id` (i64, required); body: `email` (string, required), `full_name` (string, optional), `role` (string, optional — `admin` | `viewer` | `billing`).
347
+
348
+ **Returns**: `InviteTeamMemberResponse`.
349
+
350
+ ```ruby
351
+ # Ruby
352
+ qn.admin.invite_team_member(id: 42, email: "alice@example.com", role: "viewer")
353
+ ```
354
+
355
+ ##### `remove_team_member` / `removeTeamMember`
356
+
357
+ Removes a user from a team.
358
+
359
+ **Parameters**: `id` (team id, i64, required), `user_id` (i64, required).
360
+
361
+ **Returns**: `RemoveTeamMemberResponse`.
362
+
363
+ ```ruby
364
+ # Ruby
365
+ qn.admin.remove_team_member(id: 42, user_id: 7)
366
+ ```
367
+
368
+ ##### `resend_team_invite` / `resendTeamInvite`
369
+
370
+ Re-sends a pending team invitation.
371
+
372
+ **Parameters**: `id` (team id, i64, required), `user_id` (i64, required).
373
+
374
+ **Returns**: `ResendTeamInviteResponse`.
375
+
376
+ ```ruby
377
+ # Ruby
378
+ qn.admin.resend_team_invite(id: 42, user_id: 7)
379
+ ```
380
+
381
+ #### Usage
382
+
383
+ All usage methods accept optional `start_time` and `end_time` Unix timestamps. Omit both for account-to-date totals.
384
+
385
+ ##### `get_usage` / `getUsage`
386
+
387
+ Aggregate account usage for a time window.
388
+
389
+ **Returns**: `GetUsageResponse` with `data: UsageData` (`credits_used`, `credits_remaining`, `limit`, `overages`, `start_time`, `end_time`).
390
+
391
+ ```ruby
392
+ # Ruby
393
+ resp = qn.admin.get_usage({})
394
+ ```
395
+
396
+ ##### `get_usage_by_endpoint` / `getUsageByEndpoint`
397
+
398
+ Per-endpoint usage breakdown.
399
+
400
+ **Returns**: `GetUsageByEndpointResponse` with `data.endpoints: EndpointUsage[]`.
401
+
402
+ ```ruby
403
+ # Ruby
404
+ resp = qn.admin.get_usage_by_endpoint({})
405
+ ```
406
+
407
+ ##### `get_usage_by_method` / `getUsageByMethod`
408
+
409
+ Per-RPC-method usage breakdown.
410
+
411
+ **Returns**: `GetUsageByMethodResponse` with `data.methods: MethodUsage[]`.
412
+
413
+ ```ruby
414
+ # Ruby
415
+ resp = qn.admin.get_usage_by_method({})
416
+ ```
417
+
418
+ ##### `get_usage_by_chain` / `getUsageByChain`
419
+
420
+ Per-chain usage breakdown.
421
+
422
+ **Returns**: `GetUsageByChainResponse` with `data.chains: ChainUsage[]`.
423
+
424
+ ```ruby
425
+ # Ruby
426
+ resp = qn.admin.get_usage_by_chain({})
427
+ ```
428
+
429
+ ##### `get_usage_by_tag` / `getUsageByTag`
430
+
431
+ Per-tag usage breakdown.
432
+
433
+ **Returns**: `GetUsageByTagResponse` with `data.tags: TagUsage[]`.
434
+
435
+ ```ruby
436
+ # Ruby
437
+ resp = qn.admin.get_usage_by_tag({})
438
+ ```
439
+
440
+ #### Logs
441
+
442
+ ##### `get_endpoint_logs` / `getEndpointLogs`
443
+
444
+ Fetches a page of request logs for an endpoint. Set `include_details=true` for full request/response payloads (truncated at 2 KB each).
445
+
446
+ **Parameters**: `id` (endpoint id, required); body: `from` (string timestamp, required), `to` (string timestamp, required), `include_details` (bool, optional), `limit` (i32, optional), `next_at` (string cursor, optional).
447
+
448
+ **Returns**: `GetEndpointLogsResponse` — `{ data: EndpointLog[], next_at?: string }`.
449
+
450
+ ```ruby
451
+ # Ruby
452
+ resp = qn.admin.get_endpoint_logs(
453
+ id: "ep-123",
454
+ from_time: "2026-04-01T00:00:00Z",
455
+ to_time: "2026-04-02T00:00:00Z",
456
+ limit: 100
457
+ )
458
+ ```
459
+
460
+ ##### `get_log_details` / `getLogDetails`
461
+
462
+ Returns the full request/response payloads for a single log entry.
463
+
464
+ **Parameters**: `id` (endpoint id, required), `request_id` (log request uuid, required).
465
+
466
+ **Returns**: `GetLogDetailsResponse` with `data: LogDetails`.
467
+
468
+ ```ruby
469
+ # Ruby
470
+ resp = qn.admin.get_log_details(id: "ep-123", request_id: "req-abc")
471
+ ```
472
+
473
+ #### Endpoint Security
474
+
475
+ ##### `get_endpoint_security` / `getEndpointSecurity`
476
+
477
+ Returns the full security configuration for an endpoint: tokens, JWTs, referrers, domain masks, IPs, request filters, and their per-feature toggles.
478
+
479
+ **Parameters**: `id` (string, required).
480
+
481
+ **Returns**: `GetEndpointSecurityResponse` with `data: EndpointSecurity`.
482
+
483
+ ```ruby
484
+ # Ruby
485
+ resp = qn.admin.get_endpoint_security(id: "ep-123")
486
+ ```
487
+
488
+ #### Security Options
489
+
490
+ ##### `get_security_options` / `getSecurityOptions`
491
+
492
+ Returns the list of security features and their enabled state for an endpoint.
493
+
494
+ **Parameters**: `id` (string, required).
495
+
496
+ **Returns**: `GetSecurityOptionsResponse` with `data: SecurityOption[]`.
497
+
498
+ ```ruby
499
+ # Ruby
500
+ resp = qn.admin.get_security_options(id: "ep-123")
501
+ ```
502
+
503
+ ##### `update_security_options` / `updateSecurityOptions`
504
+
505
+ Enables or disables individual security features. Each field accepts `"enabled"` or `"disabled"`.
506
+
507
+ **Parameters**: `id` (string, required); `options`: `SecurityOptionsUpdate` (`tokens`, `referrers`, `jwts`, `ips`, `domain_masks`, `hsts`, `cors`, `request_filters`, `ip_custom_header`).
508
+
509
+ **Returns**: `UpdateSecurityOptionsResponse` with updated `SecurityOption[]`.
510
+
511
+ ```ruby
512
+ # Ruby
513
+ qn.admin.update_security_options(id: "ep-123", tokens: "enabled", jwts: "disabled")
514
+ ```
515
+
516
+ #### Tokens
517
+
518
+ ##### `create_token` / `createToken`
519
+
520
+ Generates a new auth token on an endpoint.
521
+
522
+ **Parameters**: `id` (endpoint id, required).
523
+
524
+ **Returns**: nothing.
525
+
526
+ ```ruby
527
+ # Ruby
528
+ qn.admin.create_token(id: "ep-123")
529
+ ```
530
+
531
+ ##### `delete_token` / `deleteToken`
532
+
533
+ Revokes a token on an endpoint.
534
+
535
+ **Parameters**: `id` (endpoint id, required), `token_id` (string, required).
536
+
537
+ **Returns**: nothing.
538
+
539
+ ```ruby
540
+ # Ruby
541
+ qn.admin.delete_token(id: "ep-123", token_id: "tok-1")
542
+ ```
543
+
544
+ #### Referrers
545
+
546
+ ##### `create_referrer` / `createReferrer`
547
+
548
+ Whitelists a referrer URL or domain on an endpoint.
549
+
550
+ **Parameters**: `id` (endpoint id, required); body: `referrer` (string, optional).
551
+
552
+ **Returns**: nothing.
553
+
554
+ ```ruby
555
+ # Ruby
556
+ qn.admin.create_referrer(id: "ep-123", referrer: "example.com")
557
+ ```
558
+
559
+ ##### `delete_referrer` / `deleteReferrer`
560
+
561
+ Removes a referrer from the whitelist.
562
+
563
+ **Parameters**: `id` (endpoint id, required), `referrer_id` (string, required).
564
+
565
+ **Returns**: nothing.
566
+
567
+ ```ruby
568
+ # Ruby
569
+ qn.admin.delete_referrer(id: "ep-123", referrer_id: "ref-1")
570
+ ```
571
+
572
+ #### IPs
573
+
574
+ ##### `create_ip` / `createIp`
575
+
576
+ Whitelists an IP address on an endpoint.
577
+
578
+ **Parameters**: `id` (endpoint id, required); body: `ip` (string, optional).
579
+
580
+ **Returns**: nothing.
581
+
582
+ ```ruby
583
+ # Ruby
584
+ qn.admin.create_ip(id: "ep-123", ip: "198.51.100.7")
585
+ ```
586
+
587
+ ##### `delete_ip` / `deleteIp`
588
+
589
+ Removes an IP from the whitelist.
590
+
591
+ **Parameters**: `id` (endpoint id, required), `ip_id` (string, required).
592
+
593
+ **Returns**: `DeleteBoolResponse`.
594
+
595
+ ```ruby
596
+ # Ruby
597
+ resp = qn.admin.delete_ip(id: "ep-123", ip_id: "ip-1")
598
+ ```
599
+
600
+ #### Domain Masks
601
+
602
+ ##### `create_domain_mask` / `createDomainMask`
603
+
604
+ Adds a custom domain mask to an endpoint.
605
+
606
+ **Parameters**: `id` (endpoint id, required); body: `domain_mask` (string, optional).
607
+
608
+ **Returns**: nothing.
609
+
610
+ ```ruby
611
+ # Ruby
612
+ qn.admin.create_domain_mask(id: "ep-123", domain_mask: "rpc.example.com")
613
+ ```
614
+
615
+ ##### `delete_domain_mask` / `deleteDomainMask`
616
+
617
+ Removes a domain mask.
618
+
619
+ **Parameters**: `id` (endpoint id, required), `domain_mask_id` (string, required).
620
+
621
+ **Returns**: nothing.
622
+
623
+ ```ruby
624
+ # Ruby
625
+ qn.admin.delete_domain_mask(id: "ep-123", domain_mask_id: "dm-1")
626
+ ```
627
+
628
+ #### JWTs
629
+
630
+ ##### `create_jwt` / `createJwt`
631
+
632
+ Configures JWT validation on an endpoint.
633
+
634
+ **Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, optional), `name` (string, optional).
635
+
636
+ **Returns**: nothing.
637
+
638
+ ```ruby
639
+ # Ruby
640
+ qn.admin.create_jwt(
641
+ id: "ep-123",
642
+ public_key: "-----BEGIN PUBLIC KEY-----\n...",
643
+ kid: "key-1",
644
+ name: "primary"
645
+ )
646
+ ```
647
+
648
+ ##### `delete_jwt` / `deleteJwt`
649
+
650
+ Removes a JWT configuration.
651
+
652
+ **Parameters**: `id` (endpoint id, required), `jwt_id` (string, required).
653
+
654
+ **Returns**: nothing.
655
+
656
+ ```ruby
657
+ # Ruby
658
+ qn.admin.delete_jwt(id: "ep-123", jwt_id: "jwt-1")
659
+ ```
660
+
661
+ #### Request Filters
662
+
663
+ Whitelist specific RPC methods on an endpoint. Requests for methods not on the list are blocked when the feature is enabled.
664
+
665
+ ##### `create_request_filter` / `createRequestFilter`
666
+
667
+ **Parameters**: `id` (endpoint id, required); body: `method` (string[], optional). Ruby's Hash key is `methods` (plural).
668
+
669
+ **Returns**: `CreateRequestFilterResponse` with `data.id`.
670
+
671
+ ```ruby
672
+ # Ruby
673
+ resp = qn.admin.create_request_filter(
674
+ id: "ep-123",
675
+ methods: ["eth_blockNumber", "eth_getBalance"]
676
+ )
677
+ ```
678
+
679
+ ##### `update_request_filter` / `updateRequestFilter`
680
+
681
+ **Parameters**: `id` (endpoint id, required), `request_filter_id` (string, required); body: `method` (string[], optional). Ruby's Hash keys are `request_filter_id` and `methods` (plural).
682
+
683
+ **Returns**: nothing.
684
+
685
+ ```ruby
686
+ # Ruby
687
+ qn.admin.update_request_filter(id: "ep-123", request_filter_id: "f-1", methods: ["eth_call"])
688
+ ```
689
+
690
+ ##### `delete_request_filter` / `deleteRequestFilter`
691
+
692
+ **Parameters**: `id` (endpoint id, required), `request_filter_id` (string, required).
693
+
694
+ **Returns**: nothing.
695
+
696
+ ```ruby
697
+ # Ruby
698
+ qn.admin.delete_request_filter(id: "ep-123", request_filter_id: "f-1")
699
+ ```
700
+
701
+ #### Multichain
702
+
703
+ ##### `enable_multichain` / `enableMultichain`
704
+
705
+ Enables multichain on an endpoint.
706
+
707
+ **Parameters**: `id` (endpoint id, required).
708
+
709
+ **Returns**: nothing.
710
+
711
+ ```ruby
712
+ # Ruby
713
+ qn.admin.enable_multichain(id: "ep-123")
714
+ ```
715
+
716
+ ##### `disable_multichain` / `disableMultichain`
717
+
718
+ Disables multichain on an endpoint.
719
+
720
+ **Parameters**: `id` (endpoint id, required).
721
+
722
+ **Returns**: nothing.
723
+
724
+ ```ruby
725
+ # Ruby
726
+ qn.admin.disable_multichain(id: "ep-123")
727
+ ```
728
+
729
+ #### IP Custom Headers
730
+
731
+ ##### `create_or_update_ip_custom_header` / `createOrUpdateIpCustomHeader`
732
+
733
+ Sets the custom header used to identify the client IP (e.g. when traffic is proxied).
734
+
735
+ **Parameters**: `id` (endpoint id, required); body: `header_name` (string, required).
736
+
737
+ **Returns**: `CreateOrUpdateIpCustomHeaderResponse` with `data.header_name`.
738
+
739
+ ```ruby
740
+ # Ruby
741
+ qn.admin.create_or_update_ip_custom_header(
742
+ id: "ep-123",
743
+ header_name: "X-Forwarded-For"
744
+ )
745
+ ```
746
+
747
+ ##### `delete_ip_custom_header` / `deleteIpCustomHeader`
748
+
749
+ Removes the custom IP header configuration.
750
+
751
+ **Parameters**: `id` (endpoint id, required).
752
+
753
+ **Returns**: `DeleteBoolResponse`.
754
+
755
+ ```ruby
756
+ # Ruby
757
+ qn.admin.delete_ip_custom_header(id: "ep-123")
758
+ ```
759
+
760
+ #### Method Rate Limits
761
+
762
+ ##### `get_method_rate_limits` / `getMethodRateLimits`
763
+
764
+ Lists method-level rate limiters configured on an endpoint.
765
+
766
+ **Parameters**: `id` (endpoint id, required).
767
+
768
+ **Returns**: `GetMethodRateLimitsResponse` with `data.rate_limiters: MethodRateLimiter[]`.
769
+
770
+ ```ruby
771
+ # Ruby
772
+ resp = qn.admin.get_method_rate_limits(id: "ep-123")
773
+ ```
774
+
775
+ ##### `create_method_rate_limit` / `createMethodRateLimit`
776
+
777
+ Creates a new method-level rate limiter.
778
+
779
+ **Parameters**: `id` (endpoint id, required); body: `interval` (string, e.g. `"second"`), `methods` (string[]), `rate` (i32).
780
+
781
+ **Returns**: `CreateMethodRateLimitResponse` with `data: MethodRateLimiter`.
782
+
783
+ ```ruby
784
+ # Ruby
785
+ resp = qn.admin.create_method_rate_limit(
786
+ id: "ep-123",
787
+ interval: "second",
788
+ methods: ["eth_call"],
789
+ rate: 10
790
+ )
791
+ ```
792
+
793
+ ##### `update_method_rate_limit` / `updateMethodRateLimit`
794
+
795
+ Updates an existing rate limiter. Only provided fields change.
796
+
797
+ **Parameters**: `id` (endpoint id, required), `method_rate_limit_id` (string, required); body: `methods` (string[], optional), `status` (`"enabled"` | `"disabled"`, optional), `rate` (i32, optional).
798
+
799
+ **Returns**: `UpdateMethodRateLimitResponse`.
800
+
801
+ ```ruby
802
+ # Ruby
803
+ qn.admin.update_method_rate_limit(id: "ep-123", method_rate_limit_id: "rl-1", rate: 50)
804
+ ```
805
+
806
+ ##### `delete_method_rate_limit` / `deleteMethodRateLimit`
807
+
808
+ Deletes a rate limiter.
809
+
810
+ **Parameters**: `id` (endpoint id, required), `method_rate_limit_id` (string, required).
811
+
812
+ **Returns**: nothing.
813
+
814
+ ```ruby
815
+ # Ruby
816
+ qn.admin.delete_method_rate_limit(id: "ep-123", method_rate_limit_id: "rl-1")
817
+ ```
818
+
819
+ #### Endpoint Rate Limits
820
+
821
+ ##### `update_rate_limits` / `updateRateLimits`
822
+
823
+ Partial update of the endpoint-level RPS / RPM / RPD caps. Only buckets included in the request are modified — omitted buckets are left unchanged. Values are capped by the account's plan tier. Sends `PATCH`.
824
+
825
+ **Parameters**: `id` (endpoint id, required); `rate_limits`: `RateLimitSettings` (`rps`, `rpm`, `rpd`, all optional).
826
+
827
+ **Returns**: nothing.
828
+
829
+ ```ruby
830
+ # Ruby
831
+ qn.admin.update_rate_limits(id: "ep-123", rps: 100, rpm: 5000)
832
+ ```
833
+
834
+ ##### `get_rate_limits` / `getRateLimits`
835
+
836
+ Returns the rate-limit rows currently enforced on the endpoint, each identifying its `bucket` (`"rps"` / `"rpm"` / `"rpd"`), `rate_limit`, and `source` (`"plan_default"` or `"user_override"`). User-set overrides expose an `id` you can pass to `delete_rate_limit_override`.
837
+
838
+ **Parameters**: `id` (endpoint id, required).
839
+
840
+ **Returns**: `GetRateLimitsResponse` (as an `IndifferentHash`) with `data[:rate_limits]: Array<RateLimitEntry>`.
841
+
842
+ ```ruby
843
+ # Ruby
844
+ resp = qn.admin.get_rate_limits(id: "123")
845
+ resp.dig(:data, :rate_limits)&.each do |row|
846
+ puts "#{row[:bucket]} #{row[:rate_limit]} #{row[:source]} #{row[:id]}"
847
+ end
848
+ ```
849
+
850
+ ##### `delete_rate_limit_override` / `deleteRateLimitOverride`
851
+
852
+ Deletes a user-set rate-limit override by UUID. Plan defaults are not deletable — passing a UUID that does not match a user-set override on the endpoint returns 404.
853
+
854
+ **Parameters**: `id` (endpoint id, required); `override_id` (UUID returned by `get_rate_limits`, required).
855
+
856
+ **Returns**: nothing.
857
+
858
+ ```ruby
859
+ # Ruby
860
+ qn.admin.delete_rate_limit_override(id: "123", override_id: "ovr-uuid")
861
+ ```
862
+
863
+ #### Endpoint URLs
864
+
865
+ ##### `get_endpoint_urls` / `getEndpointUrls`
866
+
867
+ Returns the HTTP and WebSocket URLs for the endpoint without fetching the full endpoint record. For multichain endpoints, `multichain_urls` is a per-network map of additional URLs; for single-chain endpoints it is `nil`.
868
+
869
+ **Parameters**: `id` (endpoint id, required).
870
+
871
+ **Returns**: `GetEndpointUrlsResponse` (as an `IndifferentHash`) with `data[:http_url]`, `data[:wss_url]`, and `data[:multichain_urls]`.
872
+
873
+ ```ruby
874
+ # Ruby
875
+ resp = qn.admin.get_endpoint_urls(id: "123")
876
+ puts resp.dig(:data, :http_url)
877
+ resp.dig(:data, :multichain_urls)&.each do |network, urls|
878
+ puts "#{network} #{urls[:http_url]}"
879
+ end
880
+ ```
881
+
882
+ #### Metrics
883
+
884
+ ##### `get_endpoint_metrics` / `getEndpointMetrics`
885
+
886
+ Returns metric series for an endpoint over a time period.
887
+
888
+ **Parameters**: `id` (endpoint id, required); body: `period` (`"hour"` | `"day"` | `"week"` | `"month"`), `metric` (e.g. `"method_calls_over_time"`, `"response_status_breakdown"`).
889
+
890
+ **Returns**: `GetEndpointMetricsResponse` (as an `IndifferentHash`) with `data: Array<EndpointMetric>`. Each `EndpointMetric` has `tag: Array<String>` and `data: Array<Array<Integer>>` of `[timestamp, value]` pairs. Single-axis series (e.g. `response_time_over_time` with a percentile) come back as a one-element tag like `["p95"]`; multi-axis series come back as `["network", "arbitrum-mainnet"]`.
891
+
892
+ ```ruby
893
+ # Ruby
894
+ resp = qn.admin.get_endpoint_metrics(
895
+ id: "ep-123",
896
+ period: "day",
897
+ metric: "method_calls_over_time"
898
+ )
899
+ ```
900
+
901
+ ##### `get_account_metrics` / `getAccountMetrics`
902
+
903
+ Returns account-level metric series. Supports an optional `percentile` (e.g. `"p50"`, `"p95"`, `"p99"`) for latency metrics.
904
+
905
+ **Parameters**: `period` (required), `metric` (required), `percentile` (string, optional).
906
+
907
+ **Returns**: `GetAccountMetricsResponse` (as an `IndifferentHash`) with `data: Array<EndpointMetric>`. See `get_endpoint_metrics` above for the `tag: Array<String>` shape.
908
+
909
+ ```ruby
910
+ # Ruby
911
+ resp = qn.admin.get_account_metrics(period: "day", metric: "credits_over_time")
912
+ ```
913
+
914
+ #### Chains
915
+
916
+ ##### `list_chains` / `listChains`
917
+
918
+ Lists the blockchains supported by Quicknode along with their networks.
919
+
920
+ **Parameters**: none.
921
+
922
+ **Returns**: `ListChainsResponse` with `data: Chain[]`.
923
+
924
+ ```ruby
925
+ # Ruby
926
+ resp = qn.admin.list_chains
927
+ ```
928
+
929
+ #### Billing
930
+
931
+ ##### `list_invoices` / `listInvoices`
932
+
933
+ Lists invoices on the account.
934
+
935
+ **Parameters**: none.
936
+
937
+ **Returns**: `ListInvoicesResponse` with `data.invoices: Invoice[]`.
938
+
939
+ ```ruby
940
+ # Ruby
941
+ resp = qn.admin.list_invoices
942
+ ```
943
+
944
+ ##### `list_payments` / `listPayments`
945
+
946
+ Lists payments on the account.
947
+
948
+ **Parameters**: none.
949
+
950
+ **Returns**: `ListPaymentsResponse` with `data.payments: Payment[]`.
951
+
952
+ ```ruby
953
+ # Ruby
954
+ resp = qn.admin.list_payments
955
+ ```
956
+
957
+ #### Bulk Operations
958
+
959
+ ##### `bulk_update_endpoint_status` / `bulkUpdateEndpointStatus`
960
+
961
+ Activates or pauses many endpoints at once.
962
+
963
+ **Parameters**: `ids` (string[], required), `status` (`"active"` | `"paused"`, required).
964
+
965
+ **Returns**: `BulkUpdateEndpointStatusResponse` with per-endpoint `results`.
966
+
967
+ ```ruby
968
+ # Ruby
969
+ resp = qn.admin.bulk_update_endpoint_status(ids: ["ep-1", "ep-2"], status: "paused")
970
+ ```
971
+
972
+ ##### `bulk_add_tag` / `bulkAddTag`
973
+
974
+ Applies a tag (created if missing) to many endpoints at once.
975
+
976
+ **Parameters**: `ids` (string[], required), `label` (string, required).
977
+
978
+ **Returns**: `BulkAddTagResponse`.
979
+
980
+ ```ruby
981
+ # Ruby
982
+ resp = qn.admin.bulk_add_tag(ids: ["ep-1", "ep-2"], label: "prod")
983
+ ```
984
+
985
+ ##### `bulk_remove_tag` / `bulkRemoveTag`
986
+
987
+ Removes a tag from many endpoints at once.
988
+
989
+ **Parameters**: `ids` (string[], required), `tag_id` (i32, required).
990
+
991
+ **Returns**: `BulkRemoveTagResponse`.
992
+
993
+ ```ruby
994
+ # Ruby
995
+ resp = qn.admin.bulk_remove_tag(ids: ["ep-1", "ep-2"], tag_id: 42)
996
+ ```
997
+
998
+ #### Account Tags
999
+
1000
+ ##### `list_tags` / `listTags`
1001
+
1002
+ Lists every tag on the account along with usage counts.
1003
+
1004
+ **Parameters**: none.
1005
+
1006
+ **Returns**: `ListTagsResponse` with `data.tags: AccountTag[]`.
1007
+
1008
+ ```ruby
1009
+ # Ruby
1010
+ resp = qn.admin.list_tags
1011
+ ```
1012
+
1013
+ ##### `rename_tag` / `renameTag`
1014
+
1015
+ Renames an account-level tag.
1016
+
1017
+ **Parameters**: `id` (i32, required — the tag id); body: `label` (string, required).
1018
+
1019
+ **Returns**: `RenameTagResponse` with updated `AccountTag`.
1020
+
1021
+ ```ruby
1022
+ # Ruby
1023
+ resp = qn.admin.rename_tag(id: 42, label: "staging")
1024
+ ```
1025
+
1026
+ ##### `delete_account_tag` / `deleteAccountTag`
1027
+
1028
+ Deletes a tag from the account. The tag must first be removed from any endpoints using it.
1029
+
1030
+ **Parameters**: `id` (i32, required).
1031
+
1032
+ **Returns**: `DeleteAccountTagResponse`.
1033
+
1034
+ ```ruby
1035
+ # Ruby
1036
+ qn.admin.delete_account_tag(id: 42)
1037
+ ```
1038
+
1039
+ #### Tag / delete method parameter quick-reference
1040
+
1041
+ The pattern across the Admin client: `id:` always names the **parent** resource. The child resource takes its own `<child>_id:`. The two account-level tag operations collapse to a single `id:` (the tag id) because there is no parent endpoint.
1042
+
1043
+ | Method | Required keys |
1044
+ |---|---|
1045
+ | `delete_tag` (per-endpoint) | `id:` (endpoint id), `tag_id:` |
1046
+ | `delete_account_tag` | `id:` (tag id) |
1047
+ | `rename_tag` | `id:` (tag id), `label:` |
1048
+ | `delete_token` | `id:` (endpoint id), `token_id:` |
1049
+ | `delete_referrer` | `id:`, `referrer_id:` |
1050
+ | `delete_ip` | `id:`, `ip_id:` |
1051
+ | `delete_domain_mask` | `id:`, `domain_mask_id:` |
1052
+ | `delete_jwt` | `id:`, `jwt_id:` |
1053
+ | `delete_method_rate_limit` | `id:`, `method_rate_limit_id:` |
1054
+ | `delete_request_filter` | `id:`, `request_filter_id:` |
1055
+ | `delete_rate_limit_override` | `id:`, `override_id:` |
1056
+
1057
+ ---
1058
+
1059
+ ### Streams Client
1060
+
1061
+ Accessed as `qn.streams`. Creates and manages blockchain data streams that deliver filtered on-chain events to configured destinations. Backed by `https://api.quicknode.com/streams/rest/v1/`.
1062
+
1063
+ #### Datasets, Regions, and Destinations
1064
+
1065
+ Enums used across stream methods:
1066
+
1067
+ - **`StreamRegion`**: `UsaEast`, `EuropeCentral`, `AsiaEast` (wire values: `usa_east`, `europe_central`, `asia_east`).
1068
+ - **`StreamDataset`**: `Block`, `BlockWithReceipts`, `Transactions`, `Logs`, `Receipts`, `TraceBlocks`, `DebugTraces`, `BlockWithReceiptsDebugTrace`, `BlockWithReceiptsTraceBlock`, `BlobSidecars`, `ProgramsWithLogs`, `Ledger`, `Events`, `Orders`, `Trades`, `BookUpdates`, `Twap`, `WriterActions`.
1069
+ - **`StreamStatus`**: `Active`, `Paused`, `Terminated`, `Completed`, `Blocked`.
1070
+ - **`FilterLanguage`**: `Javascript`, `Go`, `Wasm`.
1071
+ - **`StreamMetadataLocation`**: `Body`, `Header`, `None`.
1072
+
1073
+ Destinations are expressed via `DestinationAttributes`. Each variant wraps an attribute struct. On returned `Stream` records, `destination_attributes` is **flat** (no `attributes:` nesting) — access fields directly with `resp.dig(:destination_attributes, :url)`.
1074
+
1075
+
1076
+ | Variant | Struct | Key fields |
1077
+ |---|---|---|
1078
+ | `Webhook` | `WebhookAttributes` | `url`, `max_retry`, `retry_interval_sec`, `post_timeout_sec`, `compression`, `security_token?` |
1079
+ | `S3` | `S3Attributes` | `endpoint`, `access_key`, `secret_key`, `bucket`, `object_prefix`, `compression`, `file_type`, `max_retry`, `retry_interval_sec`, `use_ssl?` |
1080
+ | `Azure` | `AzureAttributes` | `storage_account`, `sas_token`, `container`, `compression`, `file_type`, `max_retry`, `retry_interval_sec`, `blob_prefix?` |
1081
+ | `Postgres` | `PostgresAttributes` | `host`, `port?` (default `5432`), `username`, `password`, `database`, `table_name`, `sslmode`, `max_retry?`, `retry_interval_sec?` |
1082
+ | `Kafka` | `KafkaAttributes` | `bootstrap_servers`, `topic_name`, `compression_type`, `batch_size?`, `linger_ms?`, `max_message_bytes?`, `timeout_sec?`, `max_retry?`, `retry_interval_sec?`, `username?`, `password?`, `protocol?`, `mechanisms?` |
1083
+
1084
+ Wrapper naming per language:
1085
+
1086
+ - **Rust**: `DestinationAttributes::Webhook(WebhookAttributes { .. })` etc.
1087
+ - **Python**: `StreamWebhookDestination(WebhookAttributes(...))`, `StreamS3Destination(S3Attributes(...))`, etc.
1088
+ - **Node.js**: a discriminated object `{ destination: "webhook", attributes: { ... } }` using string discriminators.
1089
+ - **Ruby**: factory methods on `QuicknodeSdk::DestinationAttributes`, e.g. `QuicknodeSdk::DestinationAttributes.webhook(url: ..., ...)`.
1090
+
1091
+ #### Streams methods
1092
+
1093
+ ##### `create_stream` / `createStream`
1094
+
1095
+ Creates a new stream that delivers filtered data to the configured destination. Start from a specific block for backfills or from the tip for real-time streaming. Supports filters, reorg handling, distance-from-tip, elastic batching, notification emails, and extra destinations.
1096
+
1097
+ **Parameters**: `CreateStreamParams` — required: `name`, `region`, `network`, `dataset`, `start_range` (i64), `end_range` (i64, `-1` = follow tip), `destination_attributes`, `plan`, `threshold_fetch_buffer`. Common optional fields: `dataset_batch_size`, `include_stream_metadata`, `fix_block_reorgs`, `keep_distance_from_tip`, `elastic_batch_enabled`, `filter_function`, `filter_language`, `status`, `notification_email`, `extra_destinations`.
1098
+
1099
+ **Returns**: `Stream`.
1100
+
1101
+ ```ruby
1102
+ # Ruby
1103
+ dest = QuicknodeSdk::DestinationAttributes.webhook(
1104
+ url: "https://webhook.site/...",
1105
+ max_retry: 3,
1106
+ retry_interval_sec: 1,
1107
+ post_timeout_sec: 10,
1108
+ compression: "none"
1109
+ )
1110
+ stream = qn.streams.create_stream(
1111
+ name: "My Stream",
1112
+ network: "ethereum-mainnet",
1113
+ dataset: "block",
1114
+ region: "usa_east",
1115
+ start_range: 24691804,
1116
+ end_range: 24691904,
1117
+ destination_attributes: dest,
1118
+ plan: "growth_plan",
1119
+ threshold_fetch_buffer: 1000,
1120
+ status: "active"
1121
+ )
1122
+ ```
1123
+
1124
+ ##### `list_streams` / `listStreams`
1125
+
1126
+ Paginated list of streams on the account.
1127
+
1128
+ **Parameters** (all optional): `offset` (i64), `limit` (i64), `order_by` (string), `order_direction` (`"asc"` | `"desc"`), `stream_type` (string).
1129
+
1130
+ **Returns**: `ListStreamsResponse` with `data: Stream[]` and `pageInfo` (camelCase on the wire — access as `resp[:pageInfo][:total]`).
1131
+
1132
+ ```ruby
1133
+ # Ruby
1134
+ resp = qn.streams.list_streams({})
1135
+ ```
1136
+
1137
+ ##### `get_stream` / `getStream`
1138
+
1139
+ Fetches one stream by id.
1140
+
1141
+ **Parameters**: `id` (string, required).
1142
+
1143
+ **Returns**: `Stream`.
1144
+
1145
+ ```ruby
1146
+ # Ruby
1147
+ stream = qn.streams.get_stream(id: "stream-id")
1148
+ ```
1149
+
1150
+ ##### `update_stream` / `updateStream`
1151
+
1152
+ Partially updates a stream. Omitted fields are left unchanged.
1153
+
1154
+ **Parameters**: `id` (string, required); body: any field from `CreateStreamParams` (all optional).
1155
+
1156
+ **Returns**: updated `Stream`.
1157
+
1158
+ ```ruby
1159
+ # Ruby
1160
+ stream = qn.streams.update_stream(id: "stream-id", name: "Renamed")
1161
+ ```
1162
+
1163
+ ##### `delete_stream` / `deleteStream`
1164
+
1165
+ Deletes one stream by id.
1166
+
1167
+ **Parameters**: `id` (string, required).
1168
+
1169
+ **Returns**: nothing.
1170
+
1171
+ ```ruby
1172
+ # Ruby
1173
+ qn.streams.delete_stream(id: "stream-id")
1174
+ ```
1175
+
1176
+ ##### `delete_all_streams` / `deleteAllStreams`
1177
+
1178
+ Deletes every stream on the account. Destructive and takes no arguments.
1179
+
1180
+ **Parameters**: none.
1181
+
1182
+ **Returns**: nothing.
1183
+
1184
+ ```ruby
1185
+ # Ruby
1186
+ qn.streams.delete_all_streams
1187
+ ```
1188
+
1189
+ ##### `activate_stream` / `activateStream`
1190
+
1191
+ Resumes delivery on a stream from its current position.
1192
+
1193
+ **Parameters**: `id` (string, required).
1194
+
1195
+ **Returns**: nothing.
1196
+
1197
+ ```ruby
1198
+ # Ruby
1199
+ qn.streams.activate_stream(id: "stream-id")
1200
+ ```
1201
+
1202
+ ##### `pause_stream` / `pauseStream`
1203
+
1204
+ Halts delivery on a stream.
1205
+
1206
+ **Parameters**: `id` (string, required).
1207
+
1208
+ **Returns**: nothing.
1209
+
1210
+ ```ruby
1211
+ # Ruby
1212
+ qn.streams.pause_stream(id: "stream-id")
1213
+ ```
1214
+
1215
+ ##### `test_filter` / `testFilter`
1216
+
1217
+ Runs a filter function against a block so it can be validated before being attached to a live stream.
1218
+
1219
+ **Parameters**: `network` (string, required), `dataset` (`StreamDataset`, required), `block` (string, required), `filter_function` (string, optional), `filter_language` (`FilterLanguage`, optional), `address_book_config` (optional).
1220
+
1221
+ **Returns**: `TestFilterResponse` with `result` and `logs`.
1222
+
1223
+ ```ruby
1224
+ # Ruby
1225
+ resp = qn.streams.test_filter(
1226
+ network: "ethereum-mainnet",
1227
+ dataset: "block",
1228
+ block: "17811625"
1229
+ )
1230
+ ```
1231
+
1232
+ ##### `get_enabled_count` / `getEnabledCount`
1233
+
1234
+ Counts currently enabled (active) streams, optionally filtered by type.
1235
+
1236
+ **Parameters**: `stream_type` (string, optional).
1237
+
1238
+ **Returns**: `EnabledCountResponse` with `total`.
1239
+
1240
+ ```ruby
1241
+ # Ruby
1242
+ resp = qn.streams.get_enabled_count({})
1243
+ ```
1244
+
1245
+ ---
1246
+
1247
+ ### Webhooks Client
1248
+
1249
+ Accessed as `qn.webhooks`. Creates webhooks from filter templates and manages their lifecycle. Backed by `https://api.quicknode.com/webhooks/rest/v1/`.
1250
+
1251
+ #### Templates and destination
1252
+
1253
+ `WebhookTemplateId` identifies the filter template:
1254
+
1255
+ | Variant | Wire value |
1256
+ |---|---|
1257
+ | `EvmWalletFilter` | `evmWalletFilter` |
1258
+ | `EvmContractEvents` | `evmContractEvents` |
1259
+ | `EvmAbiFilter` | `evmAbiFilter` |
1260
+ | `SolanaWalletFilter` | `solanaWalletFilter` |
1261
+ | `BitcoinWalletFilter` | `bitcoinWalletFilter` |
1262
+ | `XrplWalletFilter` | `xrplWalletFilter` |
1263
+ | `HyperliquidWalletEventsFilter` | `hyperliquidWalletEventsFilter` |
1264
+ | `StellarWalletTransactionsSourceAccountFilter` | `stellarWalletTransactionsSourceAccountFilter` |
1265
+
1266
+ `TemplateArgs` carries the arguments; construct one per template via the factory methods:
1267
+
1268
+ | Factory | Argument struct | Fields |
1269
+ |---|---|---|
1270
+ | `evm_wallet_filter` | `EvmWalletFilterTemplate` | `wallets: string[]` |
1271
+ | `evm_contract_events` | `EvmContractEventsTemplate` | `contracts: string[]`, `eventHashes?: string[]` (camelCase — `event_hashes` is rejected by the API) |
1272
+ | `evm_abi_filter` | `EvmAbiFilterTemplate` | `abi: string` (JSON), `contracts: string[]` |
1273
+ | `solana_wallet_filter` | `SolanaWalletFilterTemplate` | `accounts: string[]` |
1274
+ | `bitcoin_wallet_filter` | `BitcoinWalletFilterTemplate` | `wallets: string[]` |
1275
+ | `xrpl_wallet_filter` | `XrplWalletFilterTemplate` | `wallets: string[]` |
1276
+ | `hyperliquid_wallet_events_filter` | `HyperliquidWalletEventsFilterTemplate` | `wallets: string[]` |
1277
+ | `stellar_wallet_transactions_filter` | `StellarWalletTransactionsFilterTemplate` | `source_accounts: string[]` |
1278
+
1279
+ `WebhookDestinationAttributes`: `url` (required), `security_token` (optional — auto-generated if omitted), `compression` (optional — `"none"` | `"gzip"`).
1280
+
1281
+ `WebhookStartFrom`: `Last` (resume from last delivered block) or `Latest` (start from newest).
1282
+
1283
+ In Ruby, `template_args` is passed as a JSON string under the key `template_args_json` on every template-aware method. The destination is passed as a JSON string under `destination_attributes_json` on `create_webhook_from_template` and `update_webhook`. **`update_webhook_template` cannot change the destination** — it accepts only `webhook_id`, `template_args_json`, `name?`, and `notification_email?`.
1284
+
1285
+ #### Webhooks methods
1286
+
1287
+ ##### `list_webhooks` / `listWebhooks`
1288
+
1289
+ Paginated list of webhooks.
1290
+
1291
+ **Parameters** (all optional): `limit` (i64), `offset` (i64).
1292
+
1293
+ **Returns**: `ListWebhooksResponse` with `data: Webhook[]` and `pageInfo: WebhookPageInfo { limit, offset, total }`.
1294
+
1295
+ ```ruby
1296
+ # Ruby
1297
+ resp = qn.webhooks.list_webhooks({})
1298
+ ```
1299
+
1300
+ ##### `get_webhook` / `getWebhook`
1301
+
1302
+ Fetches a webhook by id.
1303
+
1304
+ **Parameters**: `id` (string, required).
1305
+
1306
+ **Returns**: `Webhook`.
1307
+
1308
+ ```ruby
1309
+ # Ruby
1310
+ webhook = qn.webhooks.get_webhook(id: "wh-1")
1311
+ ```
1312
+
1313
+ ##### `create_webhook_from_template` / `createWebhookFromTemplate`
1314
+
1315
+ Creates a webhook from a predefined filter template.
1316
+
1317
+ **Parameters**: `name` (required), `network` (required), `destination_attributes` (`WebhookDestinationAttributes`, required), `template_args` (required — use the `TemplateArgs` enum variant for the chosen template), `notification_email` (optional).
1318
+
1319
+ **Returns**: `Webhook`.
1320
+
1321
+ ```ruby
1322
+ # Ruby
1323
+ destination_attributes = JSON.generate({
1324
+ url: "https://webhook.site/...",
1325
+ compression: "none"
1326
+ })
1327
+ template_args = JSON.generate({
1328
+ templateId: "evmWalletFilter",
1329
+ templateArgs: { wallets: ["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"] }
1330
+ })
1331
+ webhook = qn.webhooks.create_webhook_from_template(
1332
+ name: "Wallet Webhook",
1333
+ network: "ethereum-mainnet",
1334
+ destination_attributes_json: destination_attributes,
1335
+ template_args_json: template_args
1336
+ )
1337
+ ```
1338
+
1339
+ ##### `update_webhook` / `updateWebhook`
1340
+
1341
+ Partially updates a webhook's name, notification email, and/or destination. If `destination_attributes` is supplied without `security_token`, a new token is generated automatically.
1342
+
1343
+ **Parameters**: `id` (required); body — all optional: `name`, `notification_email`, `destination_attributes`. In Ruby, `destination_attributes` is passed as a JSON string under the key `destination_attributes_json`.
1344
+
1345
+ **Returns**: updated `Webhook`.
1346
+
1347
+ ```ruby
1348
+ # Ruby
1349
+ webhook = qn.webhooks.update_webhook(id: "wh-1", name: "Renamed Webhook")
1350
+ ```
1351
+
1352
+ ##### `update_webhook_template` / `updateWebhookTemplate`
1353
+
1354
+ Updates the template args (and optionally name and notification email) on an existing template-backed webhook. The destination cannot be changed after creation — to point a webhook at a new URL or storage backend, create a new one.
1355
+
1356
+ **Parameters**: `webhook_id` (required), `template_args_json` (required — JSON string); optional: `name`, `notification_email`.
1357
+
1358
+ **Returns**: updated `Webhook`.
1359
+
1360
+ ```ruby
1361
+ # Ruby
1362
+ template_args = JSON.generate({
1363
+ templateId: "evmWalletFilter",
1364
+ templateArgs: { wallets: ["0xnewwallet"] }
1365
+ })
1366
+ webhook = qn.webhooks.update_webhook_template(
1367
+ webhook_id: "wh-1",
1368
+ template_args_json: template_args
1369
+ )
1370
+ ```
1371
+
1372
+ ##### `delete_webhook` / `deleteWebhook`
1373
+
1374
+ Deletes a webhook.
1375
+
1376
+ **Parameters**: `id` (required).
1377
+
1378
+ **Returns**: nothing.
1379
+
1380
+ ```ruby
1381
+ # Ruby
1382
+ qn.webhooks.delete_webhook(id: "wh-1")
1383
+ ```
1384
+
1385
+ ##### `delete_all_webhooks` / `deleteAllWebhooks`
1386
+
1387
+ Deletes every webhook on the account. Destructive and takes no arguments.
1388
+
1389
+ **Parameters**: none.
1390
+
1391
+ **Returns**: nothing.
1392
+
1393
+ ```ruby
1394
+ # Ruby
1395
+ qn.webhooks.delete_all_webhooks
1396
+ ```
1397
+
1398
+ ##### `pause_webhook` / `pauseWebhook`
1399
+
1400
+ Pauses a webhook so it stops delivering events.
1401
+
1402
+ **Parameters**: `id` (required).
1403
+
1404
+ **Returns**: nothing.
1405
+
1406
+ ```ruby
1407
+ # Ruby
1408
+ qn.webhooks.pause_webhook(id: "wh-1")
1409
+ ```
1410
+
1411
+ ##### `activate_webhook` / `activateWebhook`
1412
+
1413
+ Activates a paused or new webhook so it resumes delivering events. `start_from` determines where processing resumes.
1414
+
1415
+ **Parameters**: `id` (required), `start_from` (`WebhookStartFrom`, required — `Last` or `Latest`).
1416
+
1417
+ **Returns**: nothing.
1418
+
1419
+ ```ruby
1420
+ # Ruby
1421
+ qn.webhooks.activate_webhook(id: "wh-1", start_from: "latest")
1422
+ ```
1423
+
1424
+ ##### `get_enabled_count` / `getEnabledCount`
1425
+
1426
+ Counts currently enabled webhooks.
1427
+
1428
+ **Parameters**: none.
1429
+
1430
+ **Returns**: `WebhookEnabledCountResponse` with `total`.
1431
+
1432
+ ```ruby
1433
+ # Ruby
1434
+ resp = qn.webhooks.get_enabled_count
1435
+ ```
1436
+
1437
+ ---
1438
+
1439
+ ### KV Store Client
1440
+
1441
+ Accessed as `qn.kvstore`. Provides two primitives — **sets** (single string values under a key) and **lists** (ordered collections of strings under a key). Backed by `https://api.quicknode.com/kv/rest/v1/`.
1442
+
1443
+ #### Sets
1444
+
1445
+ ##### `create_set` / `createSet`
1446
+
1447
+ Stores a single string value under a key.
1448
+
1449
+ **Parameters**: `key` (string, required), `value` (string, required).
1450
+
1451
+ **Returns**: nothing.
1452
+
1453
+ ```ruby
1454
+ # Ruby
1455
+ qn.kvstore.create_set(key: "my-key", value: "hello")
1456
+ ```
1457
+
1458
+ ##### `get_sets` / `getSets`
1459
+
1460
+ Paginated page of key/value entries.
1461
+
1462
+ **Parameters** (all optional): `limit` (i64), `cursor` (string).
1463
+
1464
+ **Returns**: `GetSetsResponse` — `{ data: KvSetEntry[], cursor: string }`.
1465
+
1466
+ ```ruby
1467
+ # Ruby
1468
+ resp = qn.kvstore.get_sets({})
1469
+ ```
1470
+
1471
+ ##### `get_set` / `getSet`
1472
+
1473
+ Returns the value stored under a key.
1474
+
1475
+ **Parameters**: `key` (string, required).
1476
+
1477
+ **Returns**: `GetSetResponse` with `value`.
1478
+
1479
+ ```ruby
1480
+ # Ruby
1481
+ resp = qn.kvstore.get_set(key: "my-key")
1482
+ ```
1483
+
1484
+ ##### `bulk_sets` / `bulkSets`
1485
+
1486
+ Adds and/or deletes multiple sets in a single request.
1487
+
1488
+ **Parameters** (at least one required): `add_sets` (map<string,string>, optional), `delete_sets` (string[], optional).
1489
+
1490
+ **Returns**: nothing.
1491
+
1492
+ ```ruby
1493
+ # Ruby
1494
+ qn.kvstore.bulk_sets(add_sets: { "k1" => "v1" }, delete_sets: ["old-key"])
1495
+ ```
1496
+
1497
+ ##### `delete_set` / `deleteSet`
1498
+
1499
+ Deletes a single set.
1500
+
1501
+ **Parameters**: `key` (string, required).
1502
+
1503
+ **Returns**: nothing.
1504
+
1505
+ ```ruby
1506
+ # Ruby
1507
+ qn.kvstore.delete_set(key: "my-key")
1508
+ ```
1509
+
1510
+ #### Lists
1511
+
1512
+ ##### `create_list` / `createList`
1513
+
1514
+ Creates a list under a key, seeded with the initial items.
1515
+
1516
+ **Parameters**: `key` (string, required), `items` (string[], required).
1517
+
1518
+ **Returns**: nothing.
1519
+
1520
+ ```ruby
1521
+ # Ruby
1522
+ qn.kvstore.create_list(key: "my-list", items: ["0xabc", "0xdef"])
1523
+ ```
1524
+
1525
+ ##### `get_lists` / `getLists`
1526
+
1527
+ Paginated page of list keys.
1528
+
1529
+ **Parameters** (all optional): `limit` (i64), `cursor` (string).
1530
+
1531
+ **Returns**: `GetListsResponse` — `{ data: { keys: string[] }, cursor: string }`.
1532
+
1533
+ ```ruby
1534
+ # Ruby
1535
+ resp = qn.kvstore.get_lists({})
1536
+ ```
1537
+
1538
+ ##### `get_list` / `getList`
1539
+
1540
+ Paginated page of items for a specific list.
1541
+
1542
+ **Parameters**: `key` (string, required); optional `limit` (i64), `cursor` (string).
1543
+
1544
+ **Returns**: `GetListResponse` — `{ data: { items: string[] }, cursor: string }`.
1545
+
1546
+ ```ruby
1547
+ # Ruby
1548
+ resp = qn.kvstore.get_list(key: "my-list")
1549
+ ```
1550
+
1551
+ ##### `update_list` / `updateList`
1552
+
1553
+ Adds and/or removes items in a single operation.
1554
+
1555
+ **Parameters**: `key` (string, required); optional: `add_items` (string[]), `remove_items` (string[]).
1556
+
1557
+ **Returns**: nothing.
1558
+
1559
+ ```ruby
1560
+ # Ruby
1561
+ qn.kvstore.update_list(key: "my-list", add_items: ["0x456"], remove_items: ["0xabc"])
1562
+ ```
1563
+
1564
+ ##### `add_list_item` / `addListItem`
1565
+
1566
+ Appends a single item to a list.
1567
+
1568
+ **Parameters**: `key` (string, required), `item` (string, required).
1569
+
1570
+ **Returns**: nothing.
1571
+
1572
+ ```ruby
1573
+ # Ruby
1574
+ qn.kvstore.add_list_item(key: "my-list", item: "0x123")
1575
+ ```
1576
+
1577
+ ##### `list_contains_item` / `listContainsItem`
1578
+
1579
+ Checks whether a list contains a specific item.
1580
+
1581
+ **Parameters**: `key` (string, required), `item` (string, required).
1582
+
1583
+ **Returns**: `ListContainsItemResponse` with `exists: bool`.
1584
+
1585
+ ```ruby
1586
+ # Ruby
1587
+ resp = qn.kvstore.list_contains_item(key: "my-list", item: "0x123")
1588
+ ```
1589
+
1590
+ ##### `delete_list_item` / `deleteListItem`
1591
+
1592
+ Removes a single item from a list.
1593
+
1594
+ **Parameters**: `key` (string, required), `item` (string, required).
1595
+
1596
+ **Returns**: nothing.
1597
+
1598
+ ```ruby
1599
+ # Ruby
1600
+ qn.kvstore.delete_list_item(key: "my-list", item: "0x123")
1601
+ ```
1602
+
1603
+ ##### `delete_list` / `deleteList`
1604
+
1605
+ Deletes a list and all of its items.
1606
+
1607
+ **Parameters**: `key` (string, required).
1608
+
1609
+ **Returns**: nothing.
1610
+
1611
+ ```ruby
1612
+ # Ruby
1613
+ qn.kvstore.delete_list(key: "my-list")
1614
+ ```
1615
+
1616
+ ## Error Handling
1617
+
1618
+ Every binding exposes a typed exception hierarchy derived from the core `SdkError`
1619
+ enum (`crates/core/src/errors.rs`). Catch the base class (`QuicknodeSdk::Error`) for any SDK-originated failure, or a specific
1620
+ subclass to branch on transport vs. API semantics.
1621
+
1622
+ | Logical class | When it fires | Extra fields |
1623
+ |----------------------|-------------------------------------------------------------|----------------------|
1624
+ | `QuicknodeError` | base class; catches everything below | — |
1625
+ | `ConfigError` | invalid config or URL surfaced at construction time | — |
1626
+ | `HttpError` | transport failure that isn't a timeout/connect | — |
1627
+ | `TimeoutError` | request timed out (subclass of `HttpError`) | — |
1628
+ | `ConnectionError` | connection refused / DNS / TLS (subclass of `HttpError`) | — |
1629
+ | `ApiError` | non-2xx HTTP response | `status`, `body` |
1630
+ | `DecodeError` | 2xx response but JSON parse failed | `body` |
1631
+
1632
+ Class names: `QuicknodeSdk::Error`, `QuicknodeSdk::ConfigError`, `QuicknodeSdk::HttpError`, `QuicknodeSdk::TimeoutError`, `QuicknodeSdk::ConnectionError`, `QuicknodeSdk::ApiError`, `QuicknodeSdk::DecodeError`. All extend `StandardError`. Hash-key validation still raises `ArgumentError`.
1633
+
1634
+ ```ruby
1635
+ # Ruby
1636
+ begin
1637
+ qn.admin.show_endpoint(id: "missing")
1638
+ rescue QuicknodeSdk::ApiError => e
1639
+ warn "api #{e.status}: #{e.body}" if e.status == 404
1640
+ rescue QuicknodeSdk::TimeoutError
1641
+ warn "timed out"
1642
+ end
1643
+ ```
1644
+
1645
+ ## License
1646
+
1647
+ MIT