Skip to main content

forge_primitives/usage/
openrouter.rs

1//! OpenRouter `/api/v1/key` and `/api/v1/credits` response shapes.
2//!
3//! Type-only - the HTTP fetcher lives in the forge-gateway
4//! OpenRouter backend. These are the JSON wire shapes; the fetcher
5//! deserializes into them.
6
7use serde::{Deserialize, Serialize};
8
9/// Envelope. The endpoint wraps everything in a single `data` object.
10#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
11pub struct KeyResponse {
12    pub data: Option<KeyData>,
13}
14
15/// Per-key spend. The figures are scoped to the key the request
16/// authenticated with, not to the account: the same endpoint called
17/// with a different key on the same account returns that key's own
18/// numbers. Today, this week and this month arrive pre-computed, so
19/// forge does no summation and no timezone arithmetic.
20///
21/// Deliberately partial. The payload also carries a truncated copy of
22/// the key itself, a creator id, an all-time total, and `byok_*`
23/// figures for inference billed to a different provider account; none
24/// of those are mapped. See `ApiSpend`.
25#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26pub struct KeyData {
27    /// Spend since the start of today, in USD.
28    pub usage_daily: Option<f64>,
29    /// Spend since the start of this week, in USD.
30    pub usage_weekly: Option<f64>,
31    /// Spend since the start of this month, in USD.
32    pub usage_monthly: Option<f64>,
33    /// Spending cap on this key, in USD. `None` on an uncapped key,
34    /// which is a normal state rather than an error - a key can have a
35    /// cap added or removed from the dashboard at any time.
36    pub limit: Option<f64>,
37    /// What is left of `limit`, in USD.
38    pub limit_remaining: Option<f64>,
39    /// Cadence the cap resets on, e.g. `"monthly"`. Free-form on the
40    /// wire, so it is carried through rather than parsed.
41    pub limit_reset: Option<String>,
42    /// When the key stops working. `None` on a key with no expiry.
43    pub expires_at: Option<String>,
44}
45
46/// Envelope for the account credit endpoint. `/v1/credits` is
47/// account-wide - the figures cover every key on the account - unlike
48/// [`KeyData`]'s per-key spend.
49#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
50pub struct CreditsResponse {
51    pub data: Option<CreditsData>,
52}
53
54/// The account's credit pool, in USD. Both figures are required: a
55/// payload missing either is a shape forge cannot compute a balance
56/// from, and half a balance is worse than none.
57#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
58pub struct CreditsData {
59    /// Credits on the account, in USD.
60    pub total_credits: f64,
61    /// All-time usage across every key, in USD.
62    pub total_usage: f64,
63}