{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/blockvectra/json-schema/blockvectra-subscription-list-schema.json",
  "title": "SubscriptionList",
  "x-generated": "2026-11-02",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/push.yaml#/components/schemas/SubscriptionList",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "subscriptions",
    "next_page_token"
  ],
  "properties": {
    "subscriptions": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Subscription"
      }
    },
    "next_page_token": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "$defs": {
    "BlockNumber": {
      "type": "integer",
      "minimum": 0
    },
    "ChainName": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9]*(_[a-z0-9]+)+$",
      "description": "lower(chain_slug), ES-030 rule 10."
    },
    "ChainState": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "confirmations",
        "start_block",
        "applied_from_block",
        "delivered_through_block",
        "condition",
        "next_attempt_at",
        "last_error"
      ],
      "properties": {
        "confirmations": {
          "type": "integer",
          "minimum": 1
        },
        "start_block": {
          "oneOf": [
            {
              "$ref": "#/$defs/BlockNumber"
            },
            {
              "type": "null"
            }
          ],
          "description": "First block matched and delivered on this chain; null until the platform stamps it after the chain was added, usually within a second."
        },
        "applied_from_block": {
          "oneOf": [
            {
              "$ref": "#/$defs/BlockNumber"
            },
            {
              "type": "null"
            }
          ],
          "description": "Effective block of the latest applied change (chain added, addresses added or removed) on this chain: blocks from this number on are matched against the addresses as changed; null until start_block is stamped. Used when moving addresses between subscriptions."
        },
        "delivered_through_block": {
          "oneOf": [
            {
              "$ref": "#/$defs/BlockNumber"
            },
            {
              "type": "null"
            }
          ],
          "description": "Lower bound of delivered progress: all events up to this block are delivered (or there were none); null until start_block is stamped. In quiet periods without matching events, progress flushes periodically (at most once every ~60 seconds), so this value may lag behind the release frontier by up to about 60 seconds."
        },
        "condition": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "receiver_failing",
            "insufficient_balance",
            "key_revoked",
            null
          ],
          "description": "Read-only, computed when shown, not a state: why delivery on this chain is held while the subscription is online; null when nothing holds it. receiver_failing: the receiver fails and is retried with backoff (see last_error, next_attempt_at); when a chain has failed for the expiry window (currently 7 days) and no other chain delivered inside it the subscription expires and the system sets it offline. insufficient_balance: billing admission is refused (balance used up, the cu_cap of the key used up or the billed key expired); delivery pauses as soon as the key cu_cap or the account balance is exhausted and resumes without loss after a top-up or a cap increase; the condition field reflects settled usage and can lag up to one settlement period (about one hour). key_revoked: the billed key was revoked or disabled with no successor; continues after a PATCH of key_id to another key of the account. The progress stays in all cases."
        },
        "next_attempt_at": {
          "$ref": "#/$defs/NullableTimestamp"
        },
        "last_error": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "result",
                "http_status",
                "at"
              ],
              "properties": {
                "result": {
                  "type": "string",
                  "enum": [
                    "http_status",
                    "timeout",
                    "connect",
                    "dns",
                    "tls",
                    "ssrf_blocked",
                    "redirect"
                  ]
                },
                "http_status": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 100,
                  "maximum": 599
                },
                "at": {
                  "$ref": "#/$defs/Timestamp"
                }
              }
            }
          ]
        }
      }
    },
    "KeyId": {
      "type": "string",
      "pattern": "^k_[0-9a-f]{12}$"
    },
    "NullableTimestamp": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"
    },
    "Subscription": {
      "allOf": [
        {
          "$ref": "#/$defs/SubscriptionFields"
        }
      ],
      "unevaluatedProperties": false
    },
    "SubscriptionFields": {
      "type": "object",
      "required": [
        "id",
        "url",
        "status",
        "key_id",
        "address_count",
        "applied_version",
        "chains",
        "created_at"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/SubscriptionId"
        },
        "url": {
          "$ref": "#/$defs/Url"
        },
        "status": {
          "type": "string",
          "enum": [
            "online",
            "offline"
          ],
          "description": "online listens and delivers; offline does not listen (addresses unloaded, no matching, delivery or address fee) and keeps its whole configuration, and can go online again at any time. Change it with PATCH; the system also sets offline when the subscription expires (a chain failed for the expiry window, currently 7 days, and no other chain delivered inside it)."
        },
        "key_id": {
          "$ref": "#/$defs/KeyId"
        },
        "address_count": {
          "type": "integer",
          "minimum": 0,
          "description": "Distinct addresses of this subscription; additions cannot exceed 1,000,000. Existing oversized subscriptions can remove addresses and resend existing addresses."
        },
        "applied_version": {
          "type": "integer",
          "minimum": 0,
          "description": "Address and chain changes of this subscription up to this version are applied on every chain; compare with change_version returned by add, remove and PATCH (a counter of this subscription only)."
        },
        "chains": {
          "type": "object",
          "minProperties": 1,
          "propertyNames": {
            "$ref": "#/$defs/ChainName"
          },
          "additionalProperties": {
            "$ref": "#/$defs/ChainState"
          }
        },
        "created_at": {
          "$ref": "#/$defs/Timestamp"
        }
      }
    },
    "SubscriptionId": {
      "type": "integer",
      "minimum": 1,
      "maximum": 2147483647,
      "description": "The subscription id: the one number that identifies a subscription everywhere (PostgreSQL integer identity, fits u32, never reused). A plain JSON integer in bodies, decimal digits in the path."
    },
    "Timestamp": {
      "type": "string",
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"
    },
    "Url": {
      "type": "string",
      "maxLength": 2048,
      "pattern": "^https://",
      "description": "https, port 443, a host name (no IP literal), no userinfo or fragment; stored and returned normalized."
    }
  }
}