From aa59a606c47d4d5fbd6bc15fea74888f9024281b Mon Sep 17 00:00:00 2001 From: John Mitsch Date: Tue, 7 Jul 2026 14:51:01 -0400 Subject: [PATCH] feat(admin): add get_api_credits endpoint (DX-6100) Adds `get_api_credits` to the admin client, wrapping `GET /v0/api-credits/{chain}`. Returns the per-method API credit costs for a chain, resolved for the calling account's billing version. Accepts the same chain slugs as `list_chains` (e.g. `ethereum`), so the two compose. An unknown chain slug surfaces as a 404 `ApiError`. Exposed across all four language layers following the existing path-param GET pattern: - Core: new `api_credits.rs` with `ApiCredit` and `GetApiCreditsResponse` types plus wiremock tests (happy path, unknown-slug 404, API error). - Python (`get_api_credits`), Node (`getApiCredits`), Ruby (`get_api_credits`) bindings, surface files, RBS signature, and per-language READMEs. - Example usage added to all four admin examples. --- crates/core/README.md | 13 +++ crates/core/examples/admin.rs | 12 +++ crates/core/src/admin/api_credits.rs | 32 +++++++ crates/core/src/admin/mod.rs | 96 +++++++++++++++++++ crates/node/src/lib.rs | 15 +++ crates/python/src/lib.rs | 17 ++++ crates/ruby/src/lib.rs | 14 +++ npm/README.md | 13 +++ npm/examples/admin.ts | 8 ++ npm/index.d.ts | 26 +++++ npm/sdk.d.ts | 3 + python/README.md | 13 +++ python/examples/admin.py | 6 ++ python/quicknode_sdk/__init__.py | 4 + python/quicknode_sdk/__init__.pyi | 4 + python/quicknode_sdk/_core/__init__.pyi | 63 ++++++++++++ python/quicknode_sdk/init_manual_override.pyi | 4 + ruby/README.md | 13 +++ ruby/examples/admin.rb | 8 ++ ruby/sig/quicknode_sdk.rbs | 1 + 20 files changed, 365 insertions(+) create mode 100644 crates/core/src/admin/api_credits.rs diff --git a/crates/core/README.md b/crates/core/README.md index 21b0d96..3c93024 100644 --- a/crates/core/README.md +++ b/crates/core/README.md @@ -987,6 +987,19 @@ Returns details about the account, including its id, name, creation timestamp, b let resp = qn.admin.account_info().await?; ``` +##### `get_api_credits` / `getApiCredits` + +Returns the per-method API credit costs for a chain, identified by its slug (the same slugs returned by `list_chains`, e.g. `ethereum`). An unknown chain slug returns a 404 (surfaced as `ApiError`). + +**Parameters**: `chain` (string, required) — the chain slug. + +**Returns**: `GetApiCreditsResponse` with `data: Vec`, where each `ApiCredit` has `method` and `credits`. + +```rust +// Rust +let resp = qn.admin.get_api_credits("ethereum").await?; +``` + #### Billing ##### `list_invoices` / `listInvoices` diff --git a/crates/core/examples/admin.rs b/crates/core/examples/admin.rs index f0e504f..ff97f70 100644 --- a/crates/core/examples/admin.rs +++ b/crates/core/examples/admin.rs @@ -23,6 +23,18 @@ async fn main() { Err(e) => eprintln!("account_info error: {e}"), } + match qn.admin.get_api_credits("ethereum").await { + Ok(resp) => { + if let Some(credits) = &resp.data { + println!("ethereum api credits: {} methods", credits.len()); + for c in credits.iter().take(3) { + println!(" {} = {}", c.method, c.credits); + } + } + } + Err(e) => eprintln!("get_api_credits error: {e}"), + } + let params = GetEndpointsRequest::builder() .limit(20) .sort_by("created_at".to_string()) diff --git a/crates/core/src/admin/api_credits.rs b/crates/core/src/admin/api_credits.rs new file mode 100644 index 0000000..761adee --- /dev/null +++ b/crates/core/src/admin/api_credits.rs @@ -0,0 +1,32 @@ +#[cfg(feature = "node")] +use napi_derive::napi; +#[cfg(feature = "python")] +use pyo3::pyclass; +#[cfg(feature = "python")] +use pyo3_stub_gen::derive::gen_stub_pyclass; +use serde::{Deserialize, Serialize}; + +/// The API credit cost of a single RPC method on a chain. +#[cfg_attr(feature = "python", gen_stub_pyclass)] +#[cfg_attr(feature = "python", pyclass(get_all, set_all))] +#[cfg_attr(feature = "node", napi(object))] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ApiCredit { + /// RPC method name (e.g. `eth_chainId`). + pub method: String, + /// Number of API credits the method costs. + pub credits: i64, +} + +/// Response from `get_api_credits`. +#[cfg_attr(feature = "python", gen_stub_pyclass)] +#[cfg_attr(feature = "python", pyclass(get_all, set_all))] +#[cfg_attr(feature = "node", napi(object))] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GetApiCreditsResponse { + /// Per-method API credit costs for the chain, when the request succeeded. + /// `None` for an unknown chain slug. + pub data: Option>, + /// Error message when the request did not succeed. + pub error: Option, +} diff --git a/crates/core/src/admin/mod.rs b/crates/core/src/admin/mod.rs index 2071fb0..f9c7ad2 100644 --- a/crates/core/src/admin/mod.rs +++ b/crates/core/src/admin/mod.rs @@ -1,4 +1,5 @@ pub mod account; +pub mod api_credits; pub mod billing; pub mod bulk; pub mod chains; @@ -13,6 +14,7 @@ pub mod teams; pub mod usage; pub use account::{AccountInfo, AccountInfoResponse, AccountSubscription}; +pub use api_credits::{ApiCredit, GetApiCreditsResponse}; pub use billing::{ Invoice, InvoiceLine, ListInvoicesData, ListInvoicesResponse, ListPaymentsData, ListPaymentsResponse, Payment, @@ -1584,6 +1586,34 @@ impl AdminApiClient { serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body }) } + /// Returns the per-method API credit costs for a chain, identified by its + /// slug (the same slugs returned by `list_chains`, e.g. `ethereum`). Each + /// item carries the RPC `method` name and its `credits` cost, resolved for + /// the calling account's billing version. An unknown chain slug returns a + /// 404 (surfaced as `SdkError::Api`). + pub async fn get_api_credits(&self, chain: &str) -> Result { + let url = self + .config + .admin() + .base_url + .join(&format!("api-credits/{}", chain))?; + let resp = self + .config + .http_client() + .get(url) + .send() + .await + .map_err(SdkError::Http)?; + + let status = resp.status(); + let body = resp.text().await.map_err(SdkError::Http)?; + + if !status.is_success() { + return Err(SdkError::Api { status, body }); + } + serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body }) + } + /// Returns the account's invoices, including id, status, billing reason, /// amounts due and paid, line items with descriptions and billing periods, /// and creation timestamps. @@ -3060,6 +3090,72 @@ mod tests { assert_eq!(status.as_u16(), 401); } + #[tokio::test] + async fn get_api_credits_success() { + let server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path("/api-credits/ethereum")) + .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ + "data": [ + {"method": "eth_chainId", "credits": 20}, + {"method": "eth_sendRawTransaction", "credits": 40} + ], + "error": null + }))) + .mount(&server) + .await; + + let sdk = make_sdk(format!("{}/", server.uri())); + let resp = sdk.admin.get_api_credits("ethereum").await.unwrap(); + let data = resp.data.expect("expected credits data"); + assert_eq!(data.len(), 2); + assert_eq!(data[0].method, "eth_chainId"); + assert_eq!(data[0].credits, 20); + assert_eq!(data[1].method, "eth_sendRawTransaction"); + assert_eq!(data[1].credits, 40); + } + + #[tokio::test] + async fn get_api_credits_unknown_chain() { + let server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path("/api-credits/not-a-chain")) + .respond_with(ResponseTemplate::new(404).set_body_json(serde_json::json!({ + "data": null, + "error": "Chain not found" + }))) + .mount(&server) + .await; + + let sdk = make_sdk(format!("{}/", server.uri())); + let err = sdk.admin.get_api_credits("not-a-chain").await.unwrap_err(); + let SdkError::Api { status, body } = err else { + unreachable!("expected SdkError::Api, got {err:?}"); + }; + assert_eq!(status.as_u16(), 404); + assert!(body.contains("Chain not found")); + } + + #[tokio::test] + async fn get_api_credits_api_error() { + let server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path("/api-credits/ethereum")) + .respond_with(ResponseTemplate::new(401).set_body_string("Unauthorized")) + .mount(&server) + .await; + + let sdk = make_sdk(format!("{}/", server.uri())); + let err = sdk.admin.get_api_credits("ethereum").await.unwrap_err(); + let SdkError::Api { status, .. } = err else { + unreachable!("expected SdkError::Api, got {err:?}"); + }; + assert_eq!(status.as_u16(), 401); + } + #[tokio::test] async fn list_invoices_success() { let server = MockServer::start().await; diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index e03cfcd..a25ab88 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -722,6 +722,21 @@ impl AdminApiClient { self.inner.account_info().await.map_err(errors::map_sdk_err) } + /// Returns the per-method API credit costs for a chain, identified by its + /// slug (the same slugs returned by `list_chains`, e.g. `ethereum`). Each + /// item carries the RPC `method` name and its `credits` cost. An unknown + /// chain slug rejects with `ApiError` (status 404). + #[napi] + pub async fn get_api_credits( + &self, + chain: String, + ) -> Result { + self.inner + .get_api_credits(&chain) + .await + .map_err(errors::map_sdk_err) + } + /// Returns the account's invoices, including id, status, billing reason, /// amounts due and paid, line items with descriptions and billing periods, /// and creation timestamps. diff --git a/crates/python/src/lib.rs b/crates/python/src/lib.rs index 74c6de6..3174460 100644 --- a/crates/python/src/lib.rs +++ b/crates/python/src/lib.rs @@ -1086,6 +1086,23 @@ impl AdminApiClient { }) } + /// Returns the per-method API credit costs for a chain, identified by its + /// slug (the same slugs returned by `list_chains`, e.g. `ethereum`). Each + /// item carries the RPC `method` name and its `credits` cost. An unknown + /// chain slug raises `ApiError` with status 404. + #[gen_stub(override_return_type( + type_repr = "typing.Coroutine[typing.Any, typing.Any, GetApiCreditsResponse]" + ))] + fn get_api_credits<'py>(&self, py: Python<'py>, chain: String) -> PyResult> { + let client = self.inner.clone(); + pyo3_async_runtimes::tokio::future_into_py(py, async move { + client + .get_api_credits(&chain) + .await + .map_err(errors::map_sdk_err) + }) + } + /// Returns the account's invoices, including id, status, billing reason, /// amounts due and paid, line items with descriptions and billing periods, /// and creation timestamps. diff --git a/crates/ruby/src/lib.rs b/crates/ruby/src/lib.rs index 132b8c8..cf432b0 100644 --- a/crates/ruby/src/lib.rs +++ b/crates/ruby/src/lib.rs @@ -918,6 +918,16 @@ impl AdminApiClient { .and_then(to_ruby) } + fn get_api_credits(&self, opts: RHash) -> Result { + validate_keys(&opts, &["chain"])?; + let client = self.inner.clone(); + let chain = hash_require_string(&opts, "chain")?; + runtime() + .block_on(client.get_api_credits(&chain)) + .map_err(map_err) + .and_then(to_ruby) + } + fn list_invoices(&self) -> Result { let client = self.inner.clone(); runtime() @@ -1996,6 +2006,10 @@ fn init(ruby: &Ruby) -> Result<(), Error> { )?; admin.define_method("list_chains", method!(AdminApiClient::list_chains, 0))?; admin.define_method("account_info", method!(AdminApiClient::account_info, 0))?; + admin.define_method( + "get_api_credits", + method!(AdminApiClient::get_api_credits, 1), + )?; admin.define_method("list_invoices", method!(AdminApiClient::list_invoices, 0))?; admin.define_method("list_payments", method!(AdminApiClient::list_payments, 0))?; admin.define_method("list_teams", method!(AdminApiClient::list_teams, 0))?; diff --git a/npm/README.md b/npm/README.md index 99c9391..0f4f847 100644 --- a/npm/README.md +++ b/npm/README.md @@ -948,6 +948,19 @@ Returns details about the account, including its id, name, creation timestamp, b const resp = await qn.admin.accountInfo(); ``` +##### `get_api_credits` / `getApiCredits` + +Returns the per-method API credit costs for a chain, identified by its slug (the same slugs returned by `list_chains`, e.g. `ethereum`). An unknown chain slug rejects with `ApiError` (status 404). + +**Parameters**: `chain` (string, required) — the chain slug. + +**Returns**: `GetApiCreditsResponse` with `data: ApiCredit[]`, where each `ApiCredit` has `method` and `credits`. + +```typescript +// Node.js +const resp = await qn.admin.getApiCredits("ethereum"); +``` + #### Billing ##### `list_invoices` / `listInvoices` diff --git a/npm/examples/admin.ts b/npm/examples/admin.ts index e49838f..ff32bec 100644 --- a/npm/examples/admin.ts +++ b/npm/examples/admin.ts @@ -15,6 +15,14 @@ async function main() { console.log(`account ${a.id} | ${a.name} | billing=${a.billingVersion} | plan=${plan}`); } + const credits = await qn.admin.getApiCredits("ethereum"); + if (credits.data) { + console.log(`ethereum api credits: ${credits.data.length} methods`); + for (const c of credits.data.slice(0, 3)) { + console.log(` ${c.method} = ${c.credits}`); + } + } + const response = await qn.admin.getEndpoints({ limit: 20, sortBy: "created_at", diff --git a/npm/index.d.ts b/npm/index.d.ts index 5de3b16..f653f5e 100644 --- a/npm/index.d.ts +++ b/npm/index.d.ts @@ -71,6 +71,14 @@ export interface AdminConfig { baseUrl?: string } +/** The API credit cost of a single RPC method on a chain. */ +export interface ApiCredit { + /** RPC method name (e.g. `eth_chainId`). */ + method: string + /** Number of API credits the method costs. */ + credits: number +} + /** Configuration for delivering stream batches to Azure Blob Storage. */ export interface AzureAttributes { /** Azure storage account name. */ @@ -759,6 +767,17 @@ export interface GetAccountMetricsResponse { error?: string } +/** Response from `get_api_credits`. */ +export interface GetApiCreditsResponse { + /** + * Per-method API credit costs for the chain, when the request succeeded. + * `None` for an unknown chain slug. + */ + data?: Array + /** Error message when the request did not succeed. */ + error?: string +} + /** Parameters for `get_endpoint_logs`. */ export interface GetEndpointLogsRequest { /** Start of the query window (timestamp). */ @@ -2239,6 +2258,13 @@ export declare class AdminApiClient { * timestamp, billing version, and current subscription. */ accountInfo(): Promise + /** + * Returns the per-method API credit costs for a chain, identified by its + * slug (the same slugs returned by `list_chains`, e.g. `ethereum`). Each + * item carries the RPC `method` name and its `credits` cost. An unknown + * chain slug rejects with `ApiError` (status 404). + */ + getApiCredits(chain: string): Promise /** * Returns the account's invoices, including id, status, billing reason, * amounts due and paid, line items with descriptions and billing periods, diff --git a/npm/sdk.d.ts b/npm/sdk.d.ts index 10a5097..e2528a8 100644 --- a/npm/sdk.d.ts +++ b/npm/sdk.d.ts @@ -138,6 +138,9 @@ export type { AccountSubscription, AccountInfo, AccountInfoResponse, + // api credits + ApiCredit, + GetApiCreditsResponse, // metrics GetEndpointMetricsRequest, GetAccountMetricsRequest, diff --git a/python/README.md b/python/README.md index 14da731..d4ea2fa 100644 --- a/python/README.md +++ b/python/README.md @@ -949,6 +949,19 @@ Returns details about the account, including its id, name, creation timestamp, b resp = await qn.admin.account_info() ``` +##### `get_api_credits` / `getApiCredits` + +Returns the per-method API credit costs for a chain, identified by its slug (the same slugs returned by `list_chains`, e.g. `ethereum`). An unknown chain slug raises `ApiError` (status 404). + +**Parameters**: `chain` (string, required) — the chain slug. + +**Returns**: `GetApiCreditsResponse` with `data: list[ApiCredit]`, where each `ApiCredit` has `method` and `credits`. + +```python +# Python +resp = await qn.admin.get_api_credits("ethereum") +``` + #### Billing ##### `list_invoices` / `listInvoices` diff --git a/python/examples/admin.py b/python/examples/admin.py index 062defe..927ea4c 100644 --- a/python/examples/admin.py +++ b/python/examples/admin.py @@ -20,6 +20,12 @@ async def main(): plan = a.subscription.plan_name if a.subscription is not None else "" print(f"account {a.id} | {a.name} | billing={a.billing_version} | plan={plan}") + credits = await qn.admin.get_api_credits("ethereum") + if credits.data is not None: + print(f"ethereum api credits: {len(credits.data)} methods") + for c in credits.data[:3]: + print(f" {c.method} = {c.credits}") + response = await qn.admin.get_endpoints( limit=20, sort_by="created_at", diff --git a/python/quicknode_sdk/__init__.py b/python/quicknode_sdk/__init__.py index d7eb5f3..b8af2c7 100644 --- a/python/quicknode_sdk/__init__.py +++ b/python/quicknode_sdk/__init__.py @@ -91,6 +91,8 @@ AccountSubscription, AccountInfo, AccountInfoResponse, + ApiCredit, + GetApiCreditsResponse, InvoiceLine, Invoice, ListInvoicesData, @@ -301,6 +303,8 @@ "AccountSubscription", "AccountInfo", "AccountInfoResponse", + "ApiCredit", + "GetApiCreditsResponse", "InvoiceLine", "Invoice", "ListInvoicesData", diff --git a/python/quicknode_sdk/__init__.pyi b/python/quicknode_sdk/__init__.pyi index eec813d..fbc1834 100644 --- a/python/quicknode_sdk/__init__.pyi +++ b/python/quicknode_sdk/__init__.pyi @@ -93,6 +93,8 @@ from quicknode_sdk._core import ( AccountSubscription, AccountInfo, AccountInfoResponse, + ApiCredit, + GetApiCreditsResponse, InvoiceLine, Invoice, ListInvoicesData, @@ -319,6 +321,8 @@ __all__ = [ "AccountSubscription", "AccountInfo", "AccountInfoResponse", + "ApiCredit", + "GetApiCreditsResponse", "InvoiceLine", "Invoice", "ListInvoicesData", diff --git a/python/quicknode_sdk/_core/__init__.pyi b/python/quicknode_sdk/_core/__init__.pyi index a977268..2b67431 100644 --- a/python/quicknode_sdk/_core/__init__.pyi +++ b/python/quicknode_sdk/_core/__init__.pyi @@ -11,6 +11,7 @@ __all__ = [ "AddressBookConfig", "AdminApiClient", "AdminConfig", + "ApiCredit", "AzureAttributes", "BitcoinWalletFilterArgs", "BitcoinWalletFilterByListArgs", @@ -86,6 +87,7 @@ __all__ = [ "EvmWalletFilterTemplate", "GetAccountMetricsRequest", "GetAccountMetricsResponse", + "GetApiCreditsResponse", "GetEndpointLogsRequest", "GetEndpointLogsResponse", "GetEndpointMetricsRequest", @@ -655,6 +657,13 @@ class AdminApiClient: Returns details about the account, including its id, name, creation timestamp, billing version, and current subscription. """ + def get_api_credits(self, chain: builtins.str) -> typing.Coroutine[typing.Any, typing.Any, GetApiCreditsResponse]: + r""" + Returns the per-method API credit costs for a chain, identified by its + slug (the same slugs returned by `list_chains`, e.g. `ethereum`). Each + item carries the RPC `method` name and its `credits` cost. An unknown + chain slug raises `ApiError` with status 404. + """ def list_invoices(self) -> typing.Coroutine[typing.Any, typing.Any, ListInvoicesResponse]: r""" Returns the account's invoices, including id, status, billing reason, @@ -766,6 +775,32 @@ class AdminConfig: def base_url(self, value: typing.Optional[builtins.str]) -> None: ... def __new__(cls, base_url: typing.Optional[builtins.str] = None) -> AdminConfig: ... +@typing.final +class ApiCredit: + r""" + The API credit cost of a single RPC method on a chain. + """ + @property + def method(self) -> builtins.str: + r""" + RPC method name (e.g. `eth_chainId`). + """ + @method.setter + def method(self, value: builtins.str) -> None: + r""" + RPC method name (e.g. `eth_chainId`). + """ + @property + def credits(self) -> builtins.int: + r""" + Number of API credits the method costs. + """ + @credits.setter + def credits(self, value: builtins.int) -> None: + r""" + Number of API credits the method costs. + """ + @typing.final class AzureAttributes: r""" @@ -3017,6 +3052,34 @@ class GetAccountMetricsResponse: Error message when the request did not succeed. """ +@typing.final +class GetApiCreditsResponse: + r""" + Response from `get_api_credits`. + """ + @property + def data(self) -> typing.Optional[builtins.list[ApiCredit]]: + r""" + Per-method API credit costs for the chain, when the request succeeded. + `None` for an unknown chain slug. + """ + @data.setter + def data(self, value: typing.Optional[builtins.list[ApiCredit]]) -> None: + r""" + Per-method API credit costs for the chain, when the request succeeded. + `None` for an unknown chain slug. + """ + @property + def error(self) -> typing.Optional[builtins.str]: + r""" + Error message when the request did not succeed. + """ + @error.setter + def error(self, value: typing.Optional[builtins.str]) -> None: + r""" + Error message when the request did not succeed. + """ + @typing.final class GetEndpointLogsRequest: r""" diff --git a/python/quicknode_sdk/init_manual_override.pyi b/python/quicknode_sdk/init_manual_override.pyi index eec813d..fbc1834 100644 --- a/python/quicknode_sdk/init_manual_override.pyi +++ b/python/quicknode_sdk/init_manual_override.pyi @@ -93,6 +93,8 @@ from quicknode_sdk._core import ( AccountSubscription, AccountInfo, AccountInfoResponse, + ApiCredit, + GetApiCreditsResponse, InvoiceLine, Invoice, ListInvoicesData, @@ -319,6 +321,8 @@ __all__ = [ "AccountSubscription", "AccountInfo", "AccountInfoResponse", + "ApiCredit", + "GetApiCreditsResponse", "InvoiceLine", "Invoice", "ListInvoicesData", diff --git a/ruby/README.md b/ruby/README.md index aced643..7e2d499 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -944,6 +944,19 @@ Returns details about the account, including its id, name, creation timestamp, b resp = qn.admin.account_info ``` +##### `get_api_credits` / `getApiCredits` + +Returns the per-method API credit costs for a chain, identified by its slug (the same slugs returned by `list_chains`, e.g. `ethereum`). An unknown chain slug raises `ApiError` (status 404). + +**Parameters**: `chain` (string, required) — the chain slug. + +**Returns**: `GetApiCreditsResponse` with `data: [ApiCredit]`, where each `ApiCredit` has `method` and `credits`. + +```ruby +# Ruby +resp = qn.admin.get_api_credits(chain: "ethereum") +``` + #### Billing ##### `list_invoices` / `listInvoices` diff --git a/ruby/examples/admin.rb b/ruby/examples/admin.rb index 445d12d..da015d0 100644 --- a/ruby/examples/admin.rb +++ b/ruby/examples/admin.rb @@ -9,6 +9,14 @@ puts "account #{a[:id]} | #{a[:name]} | billing=#{a[:billing_version]} | plan=#{plan}" end +credits = qn.admin.get_api_credits(chain: "ethereum") +if credits[:data] + puts "ethereum api credits: #{credits[:data].length} methods" + credits[:data].first(3).each do |c| + puts " #{c[:method]} = #{c[:credits]}" + end +end + response = qn.admin.get_endpoints( limit: 20, sort_by: "created_at", diff --git a/ruby/sig/quicknode_sdk.rbs b/ruby/sig/quicknode_sdk.rbs index 747bac8..20489d5 100644 --- a/ruby/sig/quicknode_sdk.rbs +++ b/ruby/sig/quicknode_sdk.rbs @@ -92,6 +92,7 @@ module QuicknodeSdk def get_account_metrics: (period: String, metric: String, ?percentile: String) -> untyped def list_chains: () -> untyped def account_info: () -> untyped + def get_api_credits: (chain: String) -> untyped def list_invoices: () -> untyped def list_payments: () -> untyped def list_teams: () -> untyped