Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions crates/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ This is one of four language bindings published from the same Rust core. See the
- [Endpoint URLs](#endpoint-urls)
- [Metrics](#metrics)
- [Chains](#chains)
- [Account](#account)
- [Billing](#billing)
- [Bulk Operations](#bulk-operations)
- [Account Tags](#account-tags)
Expand Down Expand Up @@ -971,6 +972,21 @@ Lists the blockchains supported by Quicknode along with their networks.
let resp = qn.admin.list_chains().await?;
```

#### Account

##### `account_info` / `accountInfo`

Returns details about the account, including its id, name, creation timestamp, billing version, and current subscription.

**Parameters**: none.

**Returns**: `AccountInfoResponse` with `data: AccountInfo` (including a nested `subscription: AccountSubscription`).

```rust
// Rust
let resp = qn.admin.account_info().await?;
```

#### Billing

##### `list_invoices` / `listInvoices`
Expand Down
17 changes: 17 additions & 0 deletions crates/core/examples/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ async fn main() {
let config = SdkFullConfig::from_env().expect("Config from env failed");
let qn = QuicknodeSdk::new(&config).expect("sdk failed to initialize");

match qn.admin.account_info().await {
Ok(resp) => {
if let Some(a) = &resp.data {
let plan = a
.subscription
.as_ref()
.and_then(|s| s.plan_name.clone())
.unwrap_or_else(|| "<none>".to_string());
println!(
"account {} | {} | billing={:?} | plan={}",
a.id, a.name, a.billing_version, plan
);
}
}
Err(e) => eprintln!("account_info error: {e}"),
}

let params = GetEndpointsRequest::builder()
.limit(20)
.sort_by("created_at".to_string())
Expand Down
51 changes: 51 additions & 0 deletions crates/core/src/admin/account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#[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 account's current subscription.
#[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 AccountSubscription {
/// Plan name (e.g. `Accelerate`).
pub plan_name: Option<String>,
/// Subscription status (e.g. `active`).
pub status: Option<String>,
/// Billing interval (e.g. `monthly`).
pub interval: Option<String>,
}

/// Details about a Quicknode account.
#[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 AccountInfo {
/// Numeric account id.
pub id: i64,
/// Account name.
pub name: String,
/// ISO 8601 timestamp of when the account was created.
pub created_at: String,
/// Billing version (e.g. `v6`).
pub billing_version: Option<String>,
/// The account's current subscription, when present.
pub subscription: Option<AccountSubscription>,
}

/// Response from `account_info`.
#[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 AccountInfoResponse {
/// Account details, when the request succeeded.
pub data: Option<AccountInfo>,
/// Error message when the request did not succeed.
pub error: Option<String>,
}
76 changes: 76 additions & 0 deletions crates/core/src/admin/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod account;
pub mod billing;
pub mod bulk;
pub mod chains;
Expand All @@ -11,6 +12,7 @@ pub mod tags;
pub mod teams;
pub mod usage;

pub use account::{AccountInfo, AccountInfoResponse, AccountSubscription};
pub use billing::{
Invoice, InvoiceLine, ListInvoicesData, ListInvoicesResponse, ListPaymentsData,
ListPaymentsResponse, Payment,
Expand Down Expand Up @@ -1561,6 +1563,27 @@ impl AdminApiClient {
serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
}

/// Returns details about the account, including its id, name, creation
/// timestamp, billing version, and current subscription.
pub async fn account_info(&self) -> Result<AccountInfoResponse, SdkError> {
let url = self.config.admin().base_url.join("account/info")?;
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.
Expand Down Expand Up @@ -2984,6 +3007,59 @@ mod tests {
assert_eq!(resp.data[0].networks[0].chain_id, Some(1));
}

#[tokio::test]
async fn account_info_success() {
let server = MockServer::start().await;

Mock::given(method("GET"))
.and(path("/account/info"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"data": {
"id": 794770,
"name": "MCP Test Account",
"created_at": "2026-03-27T20:22:32.536Z",
"billing_version": "v6",
"subscription": {
"plan_name": "Accelerate",
"status": "active",
"interval": "monthly"
}
},
"error": null
})))
.mount(&server)
.await;

let sdk = make_sdk(format!("{}/", server.uri()));
let resp = sdk.admin.account_info().await.unwrap();
let data = resp.data.expect("expected account data");
assert_eq!(data.id, 794770);
assert_eq!(data.name, "MCP Test Account");
assert_eq!(data.billing_version.as_deref(), Some("v6"));
let subscription = data.subscription.expect("expected subscription");
assert_eq!(subscription.plan_name.as_deref(), Some("Accelerate"));
assert_eq!(subscription.status.as_deref(), Some("active"));
assert_eq!(subscription.interval.as_deref(), Some("monthly"));
}

#[tokio::test]
async fn account_info_api_error() {
let server = MockServer::start().await;

Mock::given(method("GET"))
.and(path("/account/info"))
.respond_with(ResponseTemplate::new(401).set_body_string("Unauthorized"))
.mount(&server)
.await;

let sdk = make_sdk(format!("{}/", server.uri()));
let err = sdk.admin.account_info().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;
Expand Down
7 changes: 7 additions & 0 deletions crates/node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,13 @@ impl AdminApiClient {
self.inner.list_chains().await.map_err(errors::map_sdk_err)
}

/// Returns details about the account, including its id, name, creation
/// timestamp, billing version, and current subscription.
#[napi]
pub async fn account_info(&self) -> Result<core::admin::AccountInfoResponse> {
self.inner.account_info().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.
Expand Down
15 changes: 15 additions & 0 deletions crates/python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,18 @@ impl AdminApiClient {
})
}

/// Returns details about the account, including its id, name, creation
/// timestamp, billing version, and current subscription.
#[gen_stub(override_return_type(
type_repr = "typing.Coroutine[typing.Any, typing.Any, AccountInfoResponse]"
))]
fn account_info<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
let client = self.inner.clone();
pyo3_async_runtimes::tokio::future_into_py(py, async move {
client.account_info().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.
Expand Down Expand Up @@ -2501,6 +2513,9 @@ fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<core::admin::ChainNetwork>()?;
m.add_class::<core::admin::Chain>()?;
m.add_class::<core::admin::ListChainsResponse>()?;
m.add_class::<core::admin::AccountSubscription>()?;
m.add_class::<core::admin::AccountInfo>()?;
m.add_class::<core::admin::AccountInfoResponse>()?;
m.add_class::<core::admin::InvoiceLine>()?;
m.add_class::<core::admin::Invoice>()?;
m.add_class::<core::admin::ListInvoicesData>()?;
Expand Down
9 changes: 9 additions & 0 deletions crates/ruby/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,14 @@ impl AdminApiClient {
.and_then(to_ruby)
}

fn account_info(&self) -> Result<magnus::Value, Error> {
let client = self.inner.clone();
runtime()
.block_on(client.account_info())
.map_err(map_err)
.and_then(to_ruby)
}

fn list_invoices(&self) -> Result<magnus::Value, Error> {
let client = self.inner.clone();
runtime()
Expand Down Expand Up @@ -1987,6 +1995,7 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
method!(AdminApiClient::get_account_metrics, 1),
)?;
admin.define_method("list_chains", method!(AdminApiClient::list_chains, 0))?;
admin.define_method("account_info", method!(AdminApiClient::account_info, 0))?;
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))?;
Expand Down
16 changes: 16 additions & 0 deletions npm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ This is one of four language bindings published from the same Rust core. See the
- [Endpoint URLs](#endpoint-urls)
- [Metrics](#metrics)
- [Chains](#chains)
- [Account](#account)
- [Billing](#billing)
- [Bulk Operations](#bulk-operations)
- [Account Tags](#account-tags)
Expand Down Expand Up @@ -932,6 +933,21 @@ Lists the blockchains supported by Quicknode along with their networks.
const resp = await qn.admin.listChains();
```

#### Account

##### `account_info` / `accountInfo`

Returns details about the account, including its id, name, creation timestamp, billing version, and current subscription.

**Parameters**: none.

**Returns**: `AccountInfoResponse` with `data: AccountInfo` (including a nested `subscription: AccountSubscription`).

```typescript
// Node.js
const resp = await qn.admin.accountInfo();
```

#### Billing

##### `list_invoices` / `listInvoices`
Expand Down
7 changes: 7 additions & 0 deletions npm/examples/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import {
async function main() {
const qn = QuicknodeSdk.fromEnv();

const account = await qn.admin.accountInfo();
if (account.data) {
const a = account.data;
const plan = a.subscription?.planName ?? "<none>";
console.log(`account ${a.id} | ${a.name} | billing=${a.billingVersion} | plan=${plan}`);
}

const response = await qn.admin.getEndpoints({
limit: 20,
sortBy: "created_at",
Expand Down
37 changes: 37 additions & 0 deletions npm/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
/* auto-generated by NAPI-RS */
/* eslint-disable */
/** Details about a Quicknode account. */
export interface AccountInfo {
/** Numeric account id. */
id: number
/** Account name. */
name: string
/** ISO 8601 timestamp of when the account was created. */
createdAt: string
/** Billing version (e.g. `v6`). */
billingVersion?: string
/** The account's current subscription, when present. */
subscription?: AccountSubscription
}

/** Response from `account_info`. */
export interface AccountInfoResponse {
/** Account details, when the request succeeded. */
data?: AccountInfo
/** Error message when the request did not succeed. */
error?: string
}

/** The account's current subscription. */
export interface AccountSubscription {
/** Plan name (e.g. `Accelerate`). */
planName?: string
/** Subscription status (e.g. `active`). */
status?: string
/** Billing interval (e.g. `monthly`). */
interval?: string
}

/** An account-level tag, shared across endpoints. */
export interface AccountTag {
/** Tag identifier. */
Expand Down Expand Up @@ -2202,6 +2234,11 @@ export declare class AdminApiClient {
* Each entry includes the chain slug and its network slugs and names.
*/
listChains(): Promise<ListChainsResponse>
/**
* Returns details about the account, including its id, name, creation
* timestamp, billing version, and current subscription.
*/
accountInfo(): Promise<AccountInfoResponse>
/**
* Returns the account's invoices, including id, status, billing reason,
* amounts due and paid, line items with descriptions and billing periods,
Expand Down
4 changes: 4 additions & 0 deletions npm/sdk.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ export type {
ChainNetwork,
Chain,
ListChainsResponse,
// account
AccountSubscription,
AccountInfo,
AccountInfoResponse,
// metrics
GetEndpointMetricsRequest,
GetAccountMetricsRequest,
Expand Down
Loading
Loading