openapi: 3.1.0
info:
  title: BlockVectra Push API
  version: 1.0.0
  description: BlockVectra Push API. Manage webhook subscriptions and watched
    addresses with the x-api-key header. Each subscription selects its receiving
    HTTPS URL and chains. See the webhook guide for signatures, delivery and
    billing.
  termsOfService: https://blockvectra.com/en/terms/
servers:
  - url: https://api.blockvectra.com/v1
    description: Gateway front door (x-api-key).
tags:
  - name: Chains
    description: Chains open for push, their confirmation ranges and coverage.
  - name: Subscriptions
    description: Subscriptions, their addresses and actions.
x-push-errors:
  - code: invalid_request
    http: 400
    retryable: false
    description: Bad JSON, unknown or immutable field, bad parameter (data.field);
      invalid addresses (data.invalid); page_token with changed parameters;
      history window longer than 24 h or from_block after to_block;
      non-normalized path
  - code: missing_api_key
    http: 401
    retryable: false
    description: No x-api-key
  - code: invalid_api_key
    http: 401
    retryable: false
    description: Key unknown, disabled or revoked
  - code: insufficient_balance
    http: 402
    retryable: false
    description: "History query only: balance used up or no allowance left (data.topup_url, data.deposit_address_url)"
  - code: key_expired
    http: 403
    retryable: false
    description: Key past its expiry
  - code: not_found
    http: 404
    retryable: false
    description: Unknown route or method, or subscription missing, deleted or in
      another account
  - code: limit_reached
    http: 409
    retryable: false
    description: data.limit is subscriptions or address_pairs_per_account; data.max
  - code: request_too_large
    http: 413
    retryable: false
    description: Body over the route limit (64 KiB; 1 MiB for address add and remove)
  - code: chain_not_available
    http: 422
    retryable: false
    description: Chain not open for push, or (replay, history) not a chain of this
      subscription (data.chain)
  - code: chains_required
    http: 422
    retryable: false
    description: chains missing or empty on create (data.available lists the chains
      open for push), or a PATCH would remove the last chain (go offline or
      delete instead)
  - code: confirmations_out_of_range
    http: 422
    retryable: false
    description: Outside the chain minimum to maximum (data.chain, data.min, data.max)
  - code: destination_not_allowed
    http: 422
    retryable: false
    description: data.rule is scheme, port, ip_literal, userinfo, fragment,
      reserved_host, too_long or invalid_url
  - code: block_out_of_range
    http: 422
    retryable: false
    description: replay from_block outside [max(replayable_from_block, start_block),
      delivered_through_block + 1] of that chain, or history from_block older
      than the earliest block kept (data.min_block; at most 30 days, later after
      a storage loss; data.max_block)
  - code: cost_exceeds_burst
    http: 429
    retryable: false
    description: "History query only: request cost exceeds burst capacity"
  - code: rate_limited
    http: 429
    retryable: true
    description: More than 5 requests per second for this key
    the same bucket as GET /v1/account; for the history query the platform-layer key-level CU bucket limit: null
    or more than 2 concurrent history queries per account: null
    or the platform-wide share of concurrent history queries is in use (Retry-After): null
  - code: internal_error
    http: 500
    retryable: false
    description: Internal error
  - code: auth_unavailable
    http: 503
    retryable: true
    description: Key data stale at the front door (Retry-After)
  - code: billing_unavailable
    http: 503
    retryable: true
    description: "History query only: the billing state cannot be confirmed for the moment (Retry-After)"
  - code: upstream_unavailable
    http: 503
    retryable: true
    description: Push service unreachable from the front door (Retry-After)
  - code: service_unavailable
    http: 503
    retryable: true
    description: Push store unavailable, or platform capacity full on an address
      change or on going online (Retry-After)
security:
  - ApiKeyHeader: []
paths:
  /push/chains:
    get:
      tags:
        - Chains
      operationId: listPushChains
      summary: Chains open for push, with confirmation minimum, default and maximum
        and the earliest block replay accepts.
      responses:
        "200":
          description: Chains open for push.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChainList"
              examples:
                chains:
                  $ref: "#/components/examples/chains"
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions:
    post:
      tags:
        - Subscriptions
      operationId: createSubscription
      summary: Create a subscription (URL and chains); addresses are added afterwards.
      description: >
        `chains` is required and has at least one key; without it (or with an
        empty object) the call is 422 `chains_required` and `data.available`
        lists the chains open for push; there is no default chain, nothing is
        created and nothing is billed. A chain whose value is `{}` uses the
        chain default confirmations. The subscription is `online` at once; every
        chain starts after the chain head at creation (`start_block` is stamped
        by the platform, usually within a second, and is `null` until then);
        events from before creation are not delivered and `replay` cannot bring
        them (there were no matches yet), use the Data API by address. There is
        no verification or test message: the first message carries on-chain
        events. The response carries the signing `secret`, the only time it is
        shown. The calling key becomes the billed key; a key whose CU cap is
        used up can still create it, and the subscription then shows the chain
        condition `insufficient_balance`. The subscription starts with no
        addresses: add them with the address endpoint.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubscriptionCreate"
            examples:
              create:
                $ref: "#/components/examples/createRequest"
      responses:
        "201":
          description: Created.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionCreated"
              examples:
                created:
                  $ref: "#/components/examples/createdResponse"
        "400":
          $ref: "#/components/responses/Error"
        "409":
          $ref: "#/components/responses/Error"
        "422":
          description: chain_not_available, chains_required, confirmations_out_of_range,
            or destination_not_allowed.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                confirmations:
                  $ref: "#/components/examples/errorConfirmations"
                chainsRequired:
                  $ref: "#/components/examples/errorChainsRequired"
        default:
          $ref: "#/components/responses/Error"
    get:
      tags:
        - Subscriptions
      operationId: listSubscriptions
      summary: Subscriptions of the account, oldest first.
      parameters:
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/PageToken"
      responses:
        "200":
          description: One page.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionList"
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions/{subscription_id}:
    parameters:
      - $ref: "#/components/parameters/SubscriptionIdPath"
    get:
      tags:
        - Subscriptions
      operationId: getSubscription
      summary: One subscription with its delivery health.
      responses:
        "200":
          $ref: "#/components/responses/Subscription"
        default:
          $ref: "#/components/responses/Error"
    patch:
      tags:
        - Subscriptions
      operationId: patchSubscription
      summary: Change URL, online/offline status, billed key, chains or confirmation
        depths.
      description: >
        JSON Merge Patch keyed by chain. An object adds a chain or changes its
        confirmations;

        null removes it. An existing chain with omitted confirmations keeps its
        value, a new

        chain uses its default. Repeating the patch changes nothing. Removing
        the last chain

        is 422 chains_required. key_id must be another active key of the same
        account.

        The response includes change_version; compare it with applied_version.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubscriptionPatch"
      responses:
        "200":
          $ref: "#/components/responses/SubscriptionPatched"
        default:
          $ref: "#/components/responses/Error"
    delete:
      tags:
        - Subscriptions
      operationId: deleteSubscription
      summary: Delete permanently (not the same as going offline); delivery stops on
        every chain at once (an attempt in flight may still arrive), the secret
        and addresses are destroyed, nothing more is billed.
      responses:
        "204":
          description: Deleted; the id is never reused and later calls are 404.
          headers: {}
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions/{subscription_id}/addresses:
    parameters:
      - $ref: "#/components/parameters/SubscriptionIdPath"
    get:
      tags:
        - Subscriptions
      operationId: listSubscriptionAddresses
      summary: Watched addresses in ascending order.
      parameters:
        - name: limit
          in: query
          required: false
          description: 1 to 10000 (else 400).
          schema:
            type: integer
            minimum: 1
            maximum: 10000
            default: 1000
        - $ref: "#/components/parameters/PageToken"
      responses:
        "200":
          description: One page.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddressPage"
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions/{subscription_id}/addresses/add:
    parameters:
      - $ref: "#/components/parameters/SubscriptionIdPath"
    post:
      tags:
        - Subscriptions
      operationId: addSubscriptionAddresses
      summary: Add up to 10,000 addresses.
      description: >
        All or nothing: one invalid address makes the whole batch 400
        (`data.invalid`, the first 100; reasons format, checksum); a batch that
        would take the account past its address-pair limit is 409
        `limit_reached`; when the platform capacity is full the call is a
        synchronous 503 `service_unavailable` and nothing is written. Set
        semantics: an address already watched, or repeated inside the request,
        counts as `unchanged` (the same address in different spellings is one
        address), so a resend is safe. After validation no item can fail, so the
        outcome of each item is reported as counts. The address applies to every
        chain listed in `chains` of the subscription and to no other chain.
        Changes apply within about a second; a chain matches the new addresses
        from its `applied_from_block`, not retroactively (`replay` cannot bring
        earlier events: it re-delivers stored matches and these addresses had
        none; use the Data API by address). `change_version` is applied on every
        chain once `applied_version` of the subscription reaches it.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddressBatch"
            examples:
              add:
                $ref: "#/components/examples/addressBatch"
      responses:
        "200":
          description: Applied.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddResult"
              examples:
                added:
                  $ref: "#/components/examples/addResult"
        "400":
          $ref: "#/components/responses/Error"
        "409":
          $ref: "#/components/responses/Error"
        "413":
          $ref: "#/components/responses/Error"
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions/{subscription_id}/addresses/remove:
    parameters:
      - $ref: "#/components/parameters/SubscriptionIdPath"
    post:
      tags:
        - Subscriptions
      operationId: removeSubscriptionAddresses
      summary: Remove up to 10,000 addresses.
      description: All or nothing on invalid input (400 with `data.invalid`). An
        address not watched counts as `unchanged`. Blocks from the effective
        block on no longer match the removed addresses; events already matched
        for earlier blocks (queued, retrying, left from before an offline
        period) are still delivered, an attempt already in flight may contain
        them, and events already delivered are not withdrawn. The result carries
        `change_version`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddressBatch"
      responses:
        "200":
          description: Applied.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RemoveResult"
        "400":
          $ref: "#/components/responses/Error"
        "413":
          $ref: "#/components/responses/Error"
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions/{subscription_id}/replay:
    parameters:
      - $ref: "#/components/parameters/SubscriptionIdPath"
    post:
      tags:
        - Subscriptions
      operationId: replaySubscription
      summary: Replay stored matches of one chain from a retained block.
      description: >
        chain must belong to the subscription. from_block is in the inclusive
        range

        [max(replayable_from_block, start_block), delivered_through_block + 1],
        otherwise

        422 block_out_of_range with min_block and max_block. The command is
        asynchronous;

        it advances replay_epoch when applied and re-deliveries are billed.
        Offline

        subscriptions accept replay commands; delivery continues after going
        online.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReplayRequest"
      responses:
        "200":
          $ref: "#/components/responses/Subscription"
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions/{subscription_id}/rotate-secret:
    parameters:
      - $ref: "#/components/parameters/SubscriptionIdPath"
    post:
      tags:
        - Subscriptions
      operationId: rotateSubscriptionSecret
      summary: Replace the signing secret immediately on every chain, without an
        overlap period.
      description: No request body. The new secret is shown once; an in-flight request
        may still carry the old signature.
      responses:
        "200":
          description: New signing secret.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RotateSecretResult"
        default:
          $ref: "#/components/responses/Error"
  /push/subscriptions/{subscription_id}/events:
    parameters:
      - $ref: "#/components/parameters/SubscriptionIdPath"
    get:
      tags:
        - Subscriptions
      operationId: listDeliveredSubscriptionEvents
      summary: Delivered data events of one chain; each successful page costs 25 CU.
      description: >
        Only delivered data events, ordered by (block, position in block,
        replay_epoch).

        Both block bounds omitted selects the last hour by block time up to
        delivered_through_block;

        one omitted bound selects an hour relative to the other. A window longer
        than 24 hours

        or from_block after to_block is 400 invalid_request. History is retained
        for at most

        30 days and may restart after storage loss; an older from_block is 422
        block_out_of_range.

        Offline subscriptions can read history. Tokens bind all query
        parameters. Each

        account has at most two concurrent queries; the platform storage share
        is also bounded.
      parameters:
        - name: chain
          in: query
          required: true
          schema:
            $ref: "#/components/schemas/ChainName"
        - name: from_block
          in: query
          required: false
          schema:
            $ref: "#/components/schemas/BlockNumber"
        - name: to_block
          in: query
          required: false
          schema:
            $ref: "#/components/schemas/BlockNumber"
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 100
        - $ref: "#/components/parameters/PageToken"
      responses:
        "200":
          description: One page of delivered events.
          headers: {}
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EventHistoryPage"
        default:
          $ref: "#/components/responses/Error"
webhooks:
  push.events:
    post:
      summary: Ordered message of one subscription, carrying data and control events.
      description: >
        Authenticate with the `webhook-signature` check, not our API
        credentials: pick the secret by `bv-subscription-id` only among
        subscriptions you created, reject unknown ids before any processing,
        verify over the raw body in constant time, and allow about 5 minutes of
        timestamp skew. A retry of the same batch (same block range, positions
        and events) keeps `webhook-id` and only re-signs the headers; when the
        boundaries or content change (batch recut after a crash, catch-up after
        a failure, re-delivery after an incident) the `webhook-id` changes, so
        deduplicate by event `id`, not by `webhook-id`. One URL receives up to
        as many concurrent requests as the subscription has chains; keep
        progress per `data.chain`.

        Record progress per chain with `complete_through_block` (a block can
        span messages). Deduplicate within a subscription by event `id`, across
        subscriptions by `ref` and `type`; after `chain.incident` reconcile the
        range `from_block` to `to_block` by `tx_hash`; `complete_through_block`
        goes back only after `replay` or after an incident recovery. Ignore
        event types you do not know. A message you cannot process can be
        answered 2xx and handled later; there is no skip operation.
      security: []
      parameters:
        - name: webhook-id
          in: header
          required: true
          schema:
            $ref: "#/components/schemas/WebhookId"
        - name: webhook-timestamp
          in: header
          required: true
          description: Unix seconds of this attempt; only for the receiver replay check.
          schema:
            type: string
            pattern: ^[0-9]{10}$
        - name: webhook-signature
          in: header
          required: true
          description: "v1,<base64>: HMAC-SHA256 of webhook-id.webhook-timestamp.raw-body, one signature per batch."
          schema:
            type: string
            pattern: ^v1,[A-Za-z0-9+/=]+$
        - name: bv-subscription-id
          in: header
          required: true
          description: Only to pick the secret; untrusted until verified.
          schema:
            $ref: "#/components/schemas/SubscriptionIdText"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PushEventsMessage"
            examples:
              transfers:
                $ref: "#/components/examples/msgTransfers"
              gap:
                $ref: "#/components/examples/msgGap"
              incident:
                $ref: "#/components/examples/msgIncident"
      responses:
        2XX:
          description: Any 2xx within 10 s, after durable processing. 3xx is a failure;
            410 is retried like any failure; 429 Retry-After is honored;
            anything else is retried.
components:
  securitySchemes:
    ApiKeyHeader:
      type: apiKey
      in: header
      name: x-api-key
      description: API key from the console; checked by the gateway front door.
  parameters:
    SubscriptionIdPath:
      name: subscription_id
      in: path
      required: true
      schema:
        $ref: "#/components/schemas/SubscriptionId"
    Limit:
      name: limit
      in: query
      required: false
      description: 1 to 100 (else 400).
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 50
    PageToken:
      name: page_token
      in: query
      required: false
      description: Opaque; the other parameters must not change between pages.
      schema:
        type: string
        minLength: 1
        maxLength: 512
  headers:
    RequestId:
      required: true
      description: 32 hex characters generated by the gateway; repeated as
        error.data.request_id.
      schema:
        type: string
        pattern: ^[0-9a-f]{32}$
    RetryAfter:
      required: false
      description: Whole seconds; on 429 and 503.
      schema:
        type: integer
        minimum: 1
  responses:
    Subscription:
      description: The subscription after the call.
      headers: {}
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Subscription"
          examples:
            offline:
              $ref: "#/components/examples/subscriptionOffline"
            chainFailing:
              $ref: "#/components/examples/subscriptionChainFailing"
    SubscriptionPatched:
      description: The subscription after the patch, with the version of this change.
      headers: {}
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/SubscriptionPatched"
    Error:
      description: Error envelope; the codes, statuses and retry rules are in root
        x-push-errors. 429 and 503 carry Retry-After.
      headers:
        Retry-After:
          $ref: "#/components/headers/RetryAfter"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
  schemas:
    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."
    SubscriptionIdText:
      type: string
      pattern: ^[1-9][0-9]{0,9}$
      description: The subscription id as decimal text, for the bv-subscription-id
        header. The value range is the same as SubscriptionId (1 to 2147483647).
    EventId:
      type: string
      pattern: ^evt_[a-z2-7]{26}$
    WebhookId:
      type: string
      pattern: ^msg_[a-z2-7]{26}$
    KeyId:
      type: string
      pattern: ^k_[0-9a-f]{12}$
    ChainName:
      type: string
      pattern: ^[a-z][a-z0-9]*(_[a-z0-9]+)+$
      description: lower(chain_slug), ES-030 rule 10.
    Address:
      type: string
      pattern: ^0x[0-9a-f]{40}$
    AddressInput:
      type: string
      pattern: ^0x[0-9a-fA-F]{40}$
      description: Lower case
      or mixed case that passes the EIP-55 checksum.: null
    Hash32:
      type: string
      pattern: ^0x[0-9a-f]{64}$
    HexData:
      type: string
      pattern: ^0x([0-9a-f]{2})*$
    Amount:
      type: string
      pattern: ^(0|[1-9][0-9]*)$
    Timestamp:
      type: string
      pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$
    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$
    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.
    Secret:
      type: string
      pattern: ^whsec_[A-Za-z0-9+/]{43}=$
      description: Shown once
      at creation and at rotation.: null
    BlockNumber:
      type: integer
      minimum: 0
    ErrorCode:
      type: string
      enum:
        - invalid_request
        - missing_api_key
        - invalid_api_key
        - insufficient_balance
        - key_expired
        - not_found
        - limit_reached
        - request_too_large
        - chain_not_available
        - chains_required
        - confirmations_out_of_range
        - destination_not_allowed
        - block_out_of_range
        - rate_limited
        - cost_exceeds_burst
        - internal_error
        - auth_unavailable
        - billing_unavailable
        - upstream_unavailable
        - service_unavailable
    ErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
            - data
          properties:
            code:
              $ref: "#/components/schemas/ErrorCode"
            message:
              type: string
            data:
              type: object
              additionalProperties: false
              required:
                - reason
                - docs_url
                - retryable
                - request_id
              properties:
                reason:
                  $ref: "#/components/schemas/ErrorCode"
                docs_url:
                  type: string
                retryable:
                  type: boolean
                field:
                  type: string
                invalid:
                  type: array
                  maxItems: 100
                  items:
                    type: object
                    additionalProperties: false
                    required:
                      - field
                      - reason
                    properties:
                      field:
                        type: string
                      reason:
                        type: string
                        enum:
                          - format
                          - checksum
                limit:
                  type: string
                  enum:
                    - subscriptions
                    - address_pairs_per_account
                chain:
                  $ref: "#/components/schemas/ChainName"
                available:
                  type: array
                  items:
                    $ref: "#/components/schemas/ChainName"
                  description: "On chains_required at create: the chains open for push."
                min:
                  type: integer
                max:
                  type: integer
                rule:
                  type: string
                  enum:
                    - scheme
                    - port
                    - ip_literal
                    - userinfo
                    - fragment
                    - reserved_host
                    - too_long
                    - invalid_url
                min_block:
                  $ref: "#/components/schemas/BlockNumber"
                max_block:
                  $ref: "#/components/schemas/BlockNumber"
                topup_url:
                  type: string
                  description: "On insufficient_balance: the console billing page."
                request_id:
                  type: string
                  pattern: ^[0-9a-f]{32}$
    Chain:
      type: object
      additionalProperties: false
      required:
        - chain
        - chain_id
        - min_confirmations
        - default_confirmations
        - max_confirmations
        - replayable_from_block
        - halted
      properties:
        chain:
          $ref: "#/components/schemas/ChainName"
        chain_id:
          type: integer
          minimum: 1
        min_confirmations:
          type: integer
          minimum: 1
          description: Smallest N a subscription may choose on this chain (1).
        default_confirmations:
          type: integer
          minimum: 1
          description: N used when a request omits confirmations for this chain.
        max_confirmations:
          type: integer
          minimum: 1
          description: Largest N a subscription may choose on this chain.
        replayable_from_block:
          $ref: "#/components/schemas/BlockNumber"
        halted:
          type: boolean
          description: true while the chain is stopped after a chain incident;
            subscriptions stay online; once operators restore the chain, each
            affected stream re-delivers canonical events from the fork point.
    ChainList:
      type: object
      additionalProperties: false
      required:
        - chains
      properties:
        chains:
          type: array
          items:
            $ref: "#/components/schemas/Chain"
    ChainSettings:
      type: object
      additionalProperties: false
      properties:
        confirmations:
          type: integer
          minimum: 1
          description: N for this chain, from min_confirmations to max_confirmations;
            omitted means default_confirmations.
    SubscriptionCreate:
      type: object
      additionalProperties: false
      required:
        - url
        - chains
      properties:
        url:
          $ref: "#/components/schemas/Url"
        chains:
          type: object
          minProperties: 1
          propertyNames:
            $ref: "#/components/schemas/ChainName"
          additionalProperties:
            $ref: "#/components/schemas/ChainSettings"
    SubscriptionPatch:
      type: object
      additionalProperties: false
      minProperties: 1
      properties:
        url:
          $ref: "#/components/schemas/Url"
        status:
          type: string
          enum:
            - online
            - offline
        key_id:
          $ref: "#/components/schemas/KeyId"
        chains:
          type: object
          minProperties: 1
          propertyNames:
            $ref: "#/components/schemas/ChainName"
          description: "Merge patch keyed by chain: an object adds the chain or changes its N, null removes it."
          additionalProperties:
            oneOf:
              - $ref: "#/components/schemas/ChainSettings"
              - type: "null"
    SubscriptionFields:
      type: object
      required:
        - id
        - url
        - status
        - key_id
        - address_count
        - applied_version
        - chains
        - created_at
      properties:
        id:
          $ref: "#/components/schemas/SubscriptionId"
        url:
          $ref: "#/components/schemas/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.
        key_id:
          $ref: "#/components/schemas/KeyId"
        address_count:
          type: integer
          minimum: 0
          description: Distinct addresses of this subscription.
        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: "#/components/schemas/ChainName"
          additionalProperties:
            $ref: "#/components/schemas/ChainState"
        created_at:
          $ref: "#/components/schemas/Timestamp"
    Subscription:
      allOf:
        - $ref: "#/components/schemas/SubscriptionFields"
      unevaluatedProperties: false
    SubscriptionPatched:
      allOf:
        - $ref: "#/components/schemas/SubscriptionFields"
      required:
        - change_version
      properties:
        change_version:
          type: integer
          minimum: 1
          description: "Compare with applied_version: the change is in effect on every chain once applied_version reaches it."
      unevaluatedProperties: false
    SubscriptionCreated:
      allOf:
        - $ref: "#/components/schemas/SubscriptionFields"
      required:
        - secret
      properties:
        secret:
          $ref: "#/components/schemas/Secret"
      unevaluatedProperties: false
    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: "#/components/schemas/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: "#/components/schemas/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: "#/components/schemas/BlockNumber"
            - type: "null"
          description: Events up to this block are delivered (or there were none); null
            until start_block is stamped.
        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 for as long as the subscription is online (see last_error, next_attempt_at). insufficient_balance: billing admission is refused (balance used up, the cu_cap of the key used up or the billed key expired); continues by itself once admission works again. 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: "#/components/schemas/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: "#/components/schemas/Timestamp"
    SubscriptionList:
      type: object
      additionalProperties: false
      required:
        - subscriptions
        - next_page_token
      properties:
        subscriptions:
          type: array
          items:
            $ref: "#/components/schemas/Subscription"
        next_page_token:
          type:
            - string
            - "null"
    AddressBatch:
      type: object
      additionalProperties: false
      required:
        - addresses
      properties:
        addresses:
          type: array
          minItems: 1
          maxItems: 10000
          items:
            $ref: "#/components/schemas/AddressInput"
    AddResult:
      type: object
      additionalProperties: false
      required:
        - added
        - unchanged
        - address_count
        - change_version
      properties:
        added:
          type: integer
          minimum: 0
        unchanged:
          type: integer
          minimum: 0
        address_count:
          type: integer
          minimum: 0
          description: Addresses of the subscription after the call.
        change_version:
          type: integer
          minimum: 1
    RemoveResult:
      type: object
      additionalProperties: false
      required:
        - removed
        - unchanged
        - address_count
        - change_version
      properties:
        removed:
          type: integer
          minimum: 0
        unchanged:
          type: integer
          minimum: 0
        address_count:
          type: integer
          minimum: 0
          description: Addresses of the subscription after the call.
        change_version:
          type: integer
          minimum: 1
    AddressPage:
      type: object
      additionalProperties: false
      required:
        - addresses
        - next_page_token
      properties:
        addresses:
          type: array
          items:
            $ref: "#/components/schemas/Address"
        next_page_token:
          type:
            - string
            - "null"
    ReplayRequest:
      type: object
      additionalProperties: false
      required:
        - chain
        - from_block
      properties:
        chain:
          $ref: "#/components/schemas/ChainName"
        from_block:
          $ref: "#/components/schemas/BlockNumber"
    RotateSecretResult:
      type: object
      additionalProperties: false
      required:
        - secret
      properties:
        secret:
          $ref: "#/components/schemas/Secret"
    DeliveredEvent:
      type: object
      additionalProperties: false
      required:
        - event
        - replay_epoch
        - orphaned
        - delivered_at
      properties:
        event:
          oneOf:
            - $ref: "#/components/schemas/NativeTransfer"
            - $ref: "#/components/schemas/TokenTransfer"
            - $ref: "#/components/schemas/LogEvent"
        replay_epoch:
          type: integer
          minimum: 0
          description: "Replay epoch of the stream: 0 at first, plus one at each replay, at each automatic re-delivery after a reorg and at each re-delivery after a chain incident is cleared."
        orphaned:
          type: boolean
          description: true when the block of this row was later replaced by a reorg and
            is no longer canonical.
        delivered_at:
          $ref: "#/components/schemas/Timestamp"
    EventHistoryPage:
      type: object
      additionalProperties: false
      required:
        - events
        - next_page_token
      properties:
        events:
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/DeliveredEvent"
        next_page_token:
          type:
            - string
            - "null"
    PushEventsMessage:
      type: object
      additionalProperties: false
      required:
        - type
        - created_at
        - data
      properties:
        type:
          const: push.events
        created_at:
          $ref: "#/components/schemas/Timestamp"
        data:
          type: object
          additionalProperties: false
          required:
            - subscription_id
            - chain
            - complete_through_block
            - events
          properties:
            subscription_id:
              $ref: "#/components/schemas/SubscriptionId"
            chain:
              $ref: "#/components/schemas/ChainName"
            complete_through_block:
              $ref: "#/components/schemas/BlockNumber"
            events:
              type: array
              minItems: 1
              maxItems: 100
              items:
                $ref: "#/components/schemas/Event"
    Event:
      oneOf:
        - $ref: "#/components/schemas/NativeTransfer"
        - $ref: "#/components/schemas/TokenTransfer"
        - $ref: "#/components/schemas/LogEvent"
        - $ref: "#/components/schemas/SubscriptionGap"
        - $ref: "#/components/schemas/ChainIncident"
      discriminator:
        propertyName: type
        mapping:
          native.transfer: "#/components/schemas/NativeTransfer"
          token.transfer: "#/components/schemas/TokenTransfer"
          log: "#/components/schemas/LogEvent"
          subscription.gap: "#/components/schemas/SubscriptionGap"
          chain.incident: "#/components/schemas/ChainIncident"
    TransferMatch:
      type: object
      additionalProperties: false
      required:
        - address
        - role
      properties:
        address:
          $ref: "#/components/schemas/Address"
        role:
          type: string
          enum:
            - from
            - to
    NativeTransfer:
      type: object
      additionalProperties: false
      description: Successful top-level transaction with value > 0 where a watched
        address is from or to (for a contract creation, to is the new contract).
        Internal transfers are not delivered.
      required:
        - id
        - type
        - ref
        - from
        - to
        - amount
        - block_number
        - block_hash
        - block_timestamp
        - tx_hash
        - tx_index
        - matched
      properties:
        id:
          $ref: "#/components/schemas/EventId"
        type:
          const: native.transfer
        ref:
          type: string
          pattern: ^eip155:[0-9]+:0x[0-9a-f]{64}:tx$
        from:
          $ref: "#/components/schemas/Address"
        to:
          $ref: "#/components/schemas/Address"
        amount:
          $ref: "#/components/schemas/Amount"
        block_number:
          $ref: "#/components/schemas/BlockNumber"
        block_hash:
          $ref: "#/components/schemas/Hash32"
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
        tx_index:
          type: integer
          minimum: 0
        matched:
          type: array
          minItems: 1
          maxItems: 2
          items:
            $ref: "#/components/schemas/TransferMatch"
    TokenTransfer:
      type: object
      additionalProperties: false
      description: ERC-20 Transfer (3 topics), ERC-721 Transfer (4 topics) or ERC-1155
        TransferSingle / TransferBatch of any contract, where a watched address
        is from or to. One event per (id, value) of a TransferBatch (batch_index
        from 0).
      required:
        - id
        - type
        - ref
        - standard
        - token
        - from
        - to
        - token_id
        - amount
        - batch_index
        - block_number
        - block_hash
        - block_timestamp
        - tx_hash
        - tx_index
        - log_index
        - matched
      properties:
        id:
          $ref: "#/components/schemas/EventId"
        type:
          const: token.transfer
        ref:
          type: string
          pattern: ^eip155:[0-9]+:0x[0-9a-f]{64}:[0-9]+(:[0-9]+)?$
        standard:
          type: string
          enum:
            - erc20
            - erc721
            - erc1155
        token:
          $ref: "#/components/schemas/Address"
        from:
          $ref: "#/components/schemas/Address"
        to:
          $ref: "#/components/schemas/Address"
        token_id:
          type:
            - string
            - "null"
          pattern: ^(0|[1-9][0-9]*)$
          description: null for erc20.
        amount:
          $ref: "#/components/schemas/Amount"
        batch_index:
          type:
            - integer
            - "null"
          minimum: 0
          description: Only for an ERC-1155 TransferBatch.
        block_number:
          $ref: "#/components/schemas/BlockNumber"
        block_hash:
          $ref: "#/components/schemas/Hash32"
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
        tx_index:
          type: integer
          minimum: 0
        log_index:
          type: integer
          minimum: 0
        matched:
          type: array
          minItems: 1
          maxItems: 2
          items:
            $ref: "#/components/schemas/TransferMatch"
    LogEvent:
      type: object
      additionalProperties: false
      description: Any other log that names a watched address, as the emitting
        contract or in topics[1] to topics[3] (left-padded to 32 bytes).
      required:
        - id
        - type
        - ref
        - address
        - topics
        - data
        - block_number
        - block_hash
        - block_timestamp
        - tx_hash
        - tx_index
        - log_index
        - matched
      properties:
        id:
          $ref: "#/components/schemas/EventId"
        type:
          const: log
        ref:
          type: string
          pattern: ^eip155:[0-9]+:0x[0-9a-f]{64}:[0-9]+$
        address:
          $ref: "#/components/schemas/Address"
        topics:
          type: array
          maxItems: 4
          items:
            $ref: "#/components/schemas/Hash32"
        data:
          $ref: "#/components/schemas/HexData"
        block_number:
          $ref: "#/components/schemas/BlockNumber"
        block_hash:
          $ref: "#/components/schemas/Hash32"
        block_timestamp:
          $ref: "#/components/schemas/Timestamp"
        tx_hash:
          $ref: "#/components/schemas/Hash32"
        tx_index:
          type: integer
          minimum: 0
        log_index:
          type: integer
          minimum: 0
        matched:
          type: array
          minItems: 1
          maxItems: 4
          items:
            type: object
            additionalProperties: false
            required:
              - address
              - role
            properties:
              address:
                $ref: "#/components/schemas/Address"
              role:
                type: string
                enum:
                  - emitter
                  - topic1
                  - topic2
                  - topic3
    SubscriptionGap:
      type: object
      additionalProperties: false
      description: No valid delivery for from_block..to_block on this chain; rescan it
        yourself or replay. Free.
      required:
        - id
        - type
        - from_block
        - to_block
        - reason
      properties:
        id:
          $ref: "#/components/schemas/EventId"
        type:
          const: subscription.gap
        from_block:
          $ref: "#/components/schemas/BlockNumber"
        to_block:
          $ref: "#/components/schemas/BlockNumber"
        reason:
          type: string
          enum:
            - retention_expired
    ChainIncident:
      type: object
      additionalProperties: false
      description: The delivered blocks from_block to to_block of this stream are no
        longer on the canonical chain. For shallow reorgs (depth at least N, at
        most 1,024 blocks), the stream automatically rolls back to the fork
        point and re-delivers the canonical events from from_block as new events
        without stopping the chain or requiring operator intervention. For deep
        reorgs (more than 1,024 blocks) or when a restart finds the stored
        progress block changed, the chain stops releasing blocks (halted) until
        operators restore it, after which the canonical events from from_block
        are delivered again as new events. expected_hash and observed_hash are
        the hash delivered for from_block and the hash the source now reports.
        Free; does not advance complete_through_block.
      required:
        - id
        - type
        - from_block
        - to_block
        - expected_hash
        - observed_hash
      properties:
        id:
          $ref: "#/components/schemas/EventId"
        type:
          const: chain.incident
        from_block:
          $ref: "#/components/schemas/BlockNumber"
        to_block:
          $ref: "#/components/schemas/BlockNumber"
        expected_hash:
          $ref: "#/components/schemas/Hash32"
        observed_hash:
          $ref: "#/components/schemas/Hash32"
  examples:
    chains:
      value:
        chains:
          - chain: bsc_mainnet
            chain_id: 56
            min_confirmations: 1
            default_confirmations: 1
            max_confirmations: 2
            replayable_from_block: 63424000
            halted: false
          - chain: eth_mainnet
            chain_id: 1
            min_confirmations: 1
            default_confirmations: 6
            max_confirmations: 82
            replayable_from_block: 23480100
            halted: false
          - chain: base_mainnet
            chain_id: 8453
            min_confirmations: 1
            default_confirmations: 1
            max_confirmations: 519
            replayable_from_block: 38120000
            halted: false
          - chain: arb_mainnet
            chain_id: 42161
            min_confirmations: 1
            default_confirmations: 120
            max_confirmations: 120
            replayable_from_block: 390000000
            halted: false
          - chain: polygon_mainnet
            chain_id: 137
            min_confirmations: 1
            default_confirmations: 200
            max_confirmations: 200
            replayable_from_block: 80000000
            halted: false
    createRequest:
      value:
        url: https://hooks.example.com/push
        chains:
          bsc_mainnet:
            confirmations: 1
          base_mainnet: {}
    createdResponse:
      value:
        id: 48213
        url: https://hooks.example.com/push
        status: online
        key_id: k_0123456789ab
        address_count: 0
        applied_version: 0
        chains:
          bsc_mainnet:
            confirmations: 1
            start_block: null
            applied_from_block: null
            delivered_through_block: null
            condition: null
            next_attempt_at: null
            last_error: null
          base_mainnet:
            confirmations: 1
            start_block: null
            applied_from_block: null
            delivered_through_block: null
            condition: null
            next_attempt_at: null
            last_error: null
        created_at: 2026-10-02T03:00:00Z
        secret: whsec_bzzV7VOlK/dJEEYrtQVe21CwsIcLdEaMY84G0J5dDOg=
    subscriptionOffline:
      value:
        id: 48213
        url: https://hooks.example.com/push
        status: offline
        key_id: k_0123456789ab
        address_count: 100000
        applied_version: 12
        chains:
          bsc_mainnet:
            confirmations: 1
            start_block: 64000100
            applied_from_block: 64009990
            delivered_through_block: 64010000
            condition: null
            next_attempt_at: null
            last_error: null
          base_mainnet:
            confirmations: 1
            start_block: 38120500
            applied_from_block: 38124900
            delivered_through_block: 38125000
            condition: null
            next_attempt_at: null
            last_error: null
        created_at: 2026-10-02T03:00:00Z
    subscriptionChainFailing:
      value:
        id: 48213
        url: https://hooks.example.com/push
        status: online
        key_id: k_0123456789ab
        address_count: 100000
        applied_version: 12
        chains:
          bsc_mainnet:
            confirmations: 1
            start_block: 64000100
            applied_from_block: 64000100
            delivered_through_block: 64010000
            condition: receiver_failing
            next_attempt_at: 2026-10-02T05:10:00Z
            last_error:
              result: http_status
              http_status: 500
              at: 2026-10-02T04:10:00Z
          base_mainnet:
            confirmations: 1
            start_block: 38120500
            applied_from_block: 38120500
            delivered_through_block: 38190000
            condition: null
            next_attempt_at: null
            last_error: null
        created_at: 2026-09-20T03:00:00Z
    patchRequest:
      value:
        chains:
          eth_mainnet:
            confirmations: 6
          bsc_mainnet: null
    addResult:
      value:
        added: 2
        unchanged: 0
        address_count: 2
        change_version: 4711
    addressBatch:
      value:
        addresses:
          - "0x9725db73f2cd8657f3e1841e5689f210ee54a92d"
          - "0x99d47bB552ae095159C251836De6A5d524076872"
    errorConfirmations:
      value:
        error:
          code: confirmations_out_of_range
          message: confirmations must be within the chain minimum and maximum
          data:
            reason: confirmations_out_of_range
            docs_url: https://docs.blockvectra.com/en/errors/#confirmations_out_of_range
            retryable: false
            chain: bsc_mainnet
            min: 1
            max: 2
            request_id: 4f0c2a9d7e3b41a8b6c5d0e1f2a3b4c5
    errorChainsRequired:
      value:
        error:
          code: chains_required
          message: chains is required; choose at least one of the available chains
          data:
            reason: chains_required
            docs_url: https://docs.blockvectra.com/en/errors/#chains_required
            retryable: false
            available:
              - bsc_mainnet
              - eth_mainnet
              - base_mainnet
              - arb_mainnet
              - polygon_mainnet
            request_id: 7a1b2c3d4e5f60718293a4b5c6d7e8f9
    historyPage:
      value:
        events:
          - event:
              id: evt_qrirplrzttdrf4a5azk47zavei
              type: token.transfer
              ref: eip155:56:0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76:7
              standard: erc20
              token: "0x55d398326f99059ff775485246999027b3197955"
              from: "0x0f94e5283c41c29a8f4dff8c17f68bdfb59f07df"
              to: "0x99d47bb552ae095159c251836de6a5d524076872"
              token_id: null
              amount: "25000000000000000000"
              batch_index: null
              block_number: 64000121
              block_hash: "0x6a8146159162f182c091d17eac7d03e95dc92ce80de704c958ca2528306aff15"
              block_timestamp: 2026-10-02T03:00:00Z
              tx_hash: "0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76"
              tx_index: 5
              log_index: 7
              matched:
                - address: "0x99d47bb552ae095159c251836de6a5d524076872"
                  role: to
            replay_epoch: 0
            orphaned: true
            delivered_at: 2026-10-02T03:00:05Z
          - event:
              id: evt_wnmjvckm7yxlzfzm3a53nmkazy
              type: token.transfer
              ref: eip155:56:0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76:7
              standard: erc20
              token: "0x55d398326f99059ff775485246999027b3197955"
              from: "0x0f94e5283c41c29a8f4dff8c17f68bdfb59f07df"
              to: "0x99d47bb552ae095159c251836de6a5d524076872"
              token_id: null
              amount: "25000000000000000000"
              batch_index: null
              block_number: 64000121
              block_hash: "0xdc91ef0e8783fe2c42cb218161df44450ced95575230a628b9f982174610cd7a"
              block_timestamp: 2026-10-02T03:00:00Z
              tx_hash: "0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76"
              tx_index: 5
              log_index: 7
              matched:
                - address: "0x99d47bb552ae095159c251836de6a5d524076872"
                  role: to
            replay_epoch: 1
            orphaned: false
            delivered_at: 2026-10-02T03:01:02Z
        next_page_token: null
    msgTransfers:
      value:
        type: push.events
        created_at: 2026-10-02T03:00:05Z
        data:
          subscription_id: 48213
          chain: bsc_mainnet
          complete_through_block: 64000121
          events:
            - id: evt_ak5pcuhp27nqor33ghe5rksiu4
              type: native.transfer
              ref: eip155:56:0x7b19944dc683c33e8dedba259cb6939f7271f70f2eeb6ca5e456cccb57cc1eff:tx
              from: "0xe0a2100d7dad33f70c4bb765323cb96b2400c844"
              to: "0x9725db73f2cd8657f3e1841e5689f210ee54a92d"
              amount: "150000000000000000"
              block_number: 64000120
              block_hash: "0x327892a3e5699a43981f0fbcc5e490628641d92c040eb0429fb550ba3a73c3bf"
              block_timestamp: 2026-10-02T03:00:00Z
              tx_hash: "0x7b19944dc683c33e8dedba259cb6939f7271f70f2eeb6ca5e456cccb57cc1eff"
              tx_index: 3
              matched:
                - address: "0x9725db73f2cd8657f3e1841e5689f210ee54a92d"
                  role: to
            - id: evt_qrirplrzttdrf4a5azk47zavei
              type: token.transfer
              ref: eip155:56:0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76:7
              standard: erc20
              token: "0x55d398326f99059ff775485246999027b3197955"
              from: "0x0f94e5283c41c29a8f4dff8c17f68bdfb59f07df"
              to: "0x99d47bb552ae095159c251836de6a5d524076872"
              token_id: null
              amount: "25000000000000000000"
              batch_index: null
              block_number: 64000121
              block_hash: "0x6a8146159162f182c091d17eac7d03e95dc92ce80de704c958ca2528306aff15"
              block_timestamp: 2026-10-02T03:00:00Z
              tx_hash: "0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76"
              tx_index: 5
              log_index: 7
              matched:
                - address: "0x99d47bb552ae095159c251836de6a5d524076872"
                  role: to
            - id: evt_ccdxyd2g7pldjo4clal3oh63vi
              type: log
              ref: eip155:56:0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76:8
              address: "0xb54ffbe723264b84cf74947127a6914cf87fc593"
              topics:
                - "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"
                - "0x00000000000000000000000099d47bb552ae095159c251836de6a5d524076872"
                - "0x000000000000000000000000b54ffbe723264b84cf74947127a6914cf87fc593"
              data: "0x0000000000000000000000000000000000000000000000000000000000000000"
              block_number: 64000121
              block_hash: "0x6a8146159162f182c091d17eac7d03e95dc92ce80de704c958ca2528306aff15"
              block_timestamp: 2026-10-02T03:00:00Z
              tx_hash: "0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76"
              tx_index: 5
              log_index: 8
              matched:
                - address: "0x99d47bb552ae095159c251836de6a5d524076872"
                  role: topic1
    msgGap:
      value:
        type: push.events
        created_at: 2026-10-05T08:00:00Z
        data:
          subscription_id: 48213
          chain: bsc_mainnet
          complete_through_block: 64100000
          events:
            - id: evt_w4dxb6vaewhavexn2rwbd7paeq
              type: subscription.gap
              from_block: 64000122
              to_block: 64100000
              reason: retention_expired
    msgIncident:
      value:
        type: push.events
        created_at: 2026-10-02T03:01:00Z
        data:
          subscription_id: 48213
          chain: bsc_mainnet
          complete_through_block: 64000121
          events:
            - id: evt_wv64jhysqqce7g345s3k5ygx6e
              type: chain.incident
              from_block: 64000120
              to_block: 64000121
              expected_hash: "0x6a8146159162f182c091d17eac7d03e95dc92ce80de704c958ca2528306aff15"
              observed_hash: "0xdc91ef0e8783fe2c42cb218161df44450ced95575230a628b9f982174610cd7a"
