{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/blockvectra/json-schema/blockvectra-plans-response-schema.json",
  "title": "PlansResponse",
  "x-generated": "2026-11-02",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/console.yaml#/components/schemas/PlansResponse",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "free",
    "promo",
    "key_defaults",
    "paid_key_minimums",
    "pricing",
    "method_weights"
  ],
  "properties": {
    "free": {
      "$ref": "#/$defs/FreePlanView"
    },
    "promo": {
      "description": "Active reset promotion granted to new accounts (latest active round); null if none. Account reset chances can be queried via `GET /resets`.",
      "oneOf": [
        {
          "$ref": "#/$defs/ResetPromoView"
        },
        {
          "type": "null"
        }
      ]
    },
    "key_defaults": {
      "$ref": "#/$defs/KeyDefaultsView"
    },
    "paid_key_minimums": {
      "$ref": "#/$defs/PaidKeyMinimumsView"
    },
    "pricing": {
      "$ref": "#/$defs/PricingPlanView"
    },
    "method_weights": {
      "type": "array",
      "description": "CU weight per call, by method across all chains; includes JSON-RPC methods and Data API `data.<op>`; method availability across chains can be queried via data plane `GET /v1/chains` and `/v1/status`. Sorted by method, including `*` row for unlisted methods.\n",
      "items": {
        "$ref": "#/$defs/MethodWeightView"
      }
    }
  },
  "$defs": {
    "FreePlanView": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "signup_units",
        "monthly_units",
        "window_days",
        "max_calls_per_sec"
      ],
      "properties": {
        "signup_units": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Sign-up grant quota for new users (units)."
        },
        "monthly_units": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Balance replenishment target (units) at the end of a usage-started window; not a UTC calendar-month grant. Remaining credit is not accumulated or taken away."
        },
        "window_days": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Usage-started window length in days (currently 30); starts at the first settled usage period, not account creation or UTC month start."
        },
        "max_calls_per_sec": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Per-second call limit for free plan. Token bucket capacity and refill rate equal this value, shared across all keys, chains, and Data API for the account."
        }
      }
    },
    "KeyDefaultsView": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "cu_per_sec",
        "burst_cu"
      ],
      "properties": {
        "cu_per_sec": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Free new-key default CU per-second rate limit."
        },
        "burst_cu": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Free new-key default burst CU capacity, also capping sum of weights in a single request."
        }
      }
    },
    "MethodWeightView": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "method",
        "cu_weight"
      ],
      "properties": {
        "method": {
          "type": "string",
          "description": "Exact JSON-RPC method name, prefix rule ending with `*`, or `*` (weight for all unlisted methods)."
        },
        "cu_weight": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Compute Units (CU) metered per call for this method."
        }
      }
    },
    "PaidKeyMinimumsView": {
      "type": "object",
      "additionalProperties": false,
      "description": "Paid-account CU lower bounds, not custom account limits. Paid eligibility requires a paid top-up; gifts alone do not qualify. Existing higher limits are preserved.",
      "required": [
        "cu_per_sec",
        "burst_cu"
      ],
      "properties": {
        "cu_per_sec": {
          "type": "integer",
          "format": "int64",
          "minimum": 1,
          "description": "Minimum paid-key refill rate in CU per second."
        },
        "burst_cu": {
          "type": "integer",
          "format": "int64",
          "minimum": 1,
          "description": "Minimum paid-key burst capacity in CU."
        }
      }
    },
    "PricingPlanView": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "units_per_usd",
        "cu_per_unit",
        "min_topup_usd",
        "push_free_addresses"
      ],
      "properties": {
        "units_per_usd": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Number of units per 1 USD."
        },
        "cu_per_unit": {
          "type": "integer",
          "format": "int64",
          "maximum": 9007199254740991,
          "description": "Number of Compute Units (CU) per 1 unit."
        },
        "min_topup_usd": {
          "type": "number",
          "description": "Minimum top-up amount (USD)."
        },
        "push_free_addresses": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2147483647,
          "description": "Free address allowance per account per UTC day, shared by all subscription groups regardless of plan. For each group, count its maximum address count while online during that day; allocate the allowance in ascending group ID order. The same address in two groups counts twice; the number of chains in a group does not multiply its address count. A group offline or deleted for the entire day contributes nothing. For each group, the remaining count after its share of the allowance is multiplied by the `push.address_day` CU weight in `method_weights`. The current configured allowance comes from the same pricing policy used for the address-day charge; it is not an account capacity limit or a separate allowance per group.\n"
        }
      }
    },
    "ResetPromoView": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type",
        "chances_per_account",
        "valid_days",
        "reset_to_units",
        "issued_at",
        "ends_at"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "reset"
          ],
          "description": "Promotion type; currently reset only."
        },
        "period": {
          "type": "string",
          "enum": [
            "month"
          ],
          "description": "Present only for monthly rounds (omitted otherwise, not null): chances issued per UTC calendar month, valid from `max(first day of month 00:00 UTC, account_creation_time)` until that timestamp plus one calendar month; `valid_days` is `null`, `issued_at` marks start of first month.\n"
        },
        "chances_per_account": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000,
          "description": "Number of reset chances granted to each eligible account in this round."
        },
        "valid_days": {
          "description": "Validity in days from `max(issued_at, account_creation_time)`; `null` does not imply a monthly round (which has `period` without fixed days, issued per calendar month) — a regular round omitting `valid_days` (lacking `period` key) is also `null`, defaulting to one calendar month validity. Check `period` presence to distinguish.\n",
          "oneOf": [
            {
              "type": "integer",
              "minimum": 1
            },
            {
              "type": "null"
            }
          ]
        },
        "reset_to_units": {
          "type": "integer",
          "format": "int64",
          "minimum": 1,
          "maximum": 9007199254740991,
          "description": "Target balance to replenish to upon reset (units)."
        },
        "issued_at": {
          "$ref": "#/$defs/Timestamp"
        },
        "ends_at": {
          "description": "Only accounts created prior to this timestamp receive chances in this round; null if no end time.",
          "oneOf": [
            {
              "$ref": "#/$defs/Timestamp"
            },
            {
              "type": "null"
            }
          ]
        },
        "next_issue_at": {
          "allOf": [
            {
              "$ref": "#/$defs/Timestamp"
            }
          ],
          "description": "Earliest upcoming auto-grant timestamp among promotion rounds strictly after current time: for monthly rounds, start of next calendar month; for regular rounds, its `issued_at` (if in the future). Present whenever such a timestamp exists; omitted (not null) when no future grants remain.\n"
        },
        "next_period": {
          "type": "string",
          "enum": [
            "month"
          ],
          "description": "Present only when `next_issue_at` originates from a monthly round (omitted otherwise, not null)."
        }
      }
    },
    "Timestamp": {
      "type": "string",
      "format": "date-time",
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$",
      "description": "RFC 3339 UTC, second precision, ending in `Z` (`2026-09-26T08:00:00Z`); no fractional seconds, without `+00:00` timezone offsets."
    }
  }
}