AsyncAPI 3.1.0 · specs/sync/gasp-asyncapi.yaml

GASP — Graph Aware Sync Protocol

v1.0.0
AsyncAPI specification for GASP (Graph Aware Sync Protocol), the cross-node UTXO synchronisation protocol implemented in `gasp-core` (`@bsv/gasp-core`). GASP is a bidirectional gossip/sync protocol between overlay nodes. Two parties exchange UTXO lists (the "initial exchange") and then walk the transaction graph in a request/response pattern to transfer any UTXOs the counterparty does not yet hold. ## Protocol flow (normal, bidirectional) ``` Initiator Responder | | |-- GASPInitialRequest ---------------------->| |<- GASPInitialResponse -----------------------| |-- GASPInitialReply ------------------------->| (if not unidirectional) | | | [for each UTXO the counterparty is missing] |-- requestNode(graphID, txid, vout, meta) -->| |<- GASPNode ---------------------------------| | | | [responder may request further inputs] |<- submitNode(GASPNode) ---------------------| |-- GASPNodeResponse ------------------------>| | (repeat until graph is complete) | | ``` Source of truth: /ts/gasp-core/src/GASP.ts
0Servers7Channels7Operations6Messages8Schemas

Channels

7

gaspInitialRequest

gasp/initialRequest

Initiator sends its sync parameters. The responder replies on the `gasp/initialResponse` channel.
address
gasp/initialRequest
description
Initiator sends its sync parameters. The responder replies on the `gasp/initialResponse` channel.
messages
1 field
GASPInitialRequest
1 field
$ref
#/components/messages/GASPInitialRequest

gaspInitialResponse

gasp/initialResponse

Responder sends back its list of known UTXOs and the timestamp from which it wants to receive UTXOs from the initiator.
address
gasp/initialResponse
description
Responder sends back its list of known UTXOs and the timestamp from which it wants to receive UTXOs from the initiator.
messages
1 field
GASPInitialResponse
1 field
$ref
#/components/messages/GASPInitialResponse

gaspInitialReply

gasp/initialReply

Initiator (if operating in bidirectional mode) sends the set of UTXOs it holds that the responder does not. Absent in unidirectional mode.
address
gasp/initialReply
description
Initiator (if operating in bidirectional mode) sends the set of UTXOs it holds that the responder does not. Absent in unidirectional mode.
messages
1 field
GASPInitialReply
1 field
$ref
#/components/messages/GASPInitialReply

gaspRequestNode

gasp/requestNode

Either party requests a specific graph node (transaction + output) from the other. Used when walking the transaction graph to hydrate UTXOs.
address
gasp/requestNode
description
Either party requests a specific graph node (transaction + output) from the other. Used when walking the transaction graph to hydrate UTXOs.
messages
1 field
GASPNodeRequest
1 field
$ref
#/components/messages/GASPNodeRequest

gaspNode

gasp/node

The responding party delivers the requested GASPNode (raw transaction, optional BUMP proof, optional metadata).
address
gasp/node
description
The responding party delivers the requested GASPNode (raw transaction, optional BUMP proof, optional metadata).
messages
1 field
GASPNode
1 field
$ref
#/components/messages/GASPNode

gaspSubmitNode

gasp/submitNode

A party submits a node it is trying to push to the counterparty. The counterparty appends it to the temporary graph and may respond with a list of additional inputs it still needs.
address
gasp/submitNode
description
A party submits a node it is trying to push to the counterparty. The counterparty appends it to the temporary graph and may respond with a list of additional inputs it still needs.
messages
1 field
GASPNode
1 field
$ref
#/components/messages/GASPNode

gaspNodeResponse

gasp/nodeResponse

Response to a submitted node; specifies which additional input transactions (if any) the recipient still needs to complete the graph. An empty / null response means the graph is complete.
address
gasp/nodeResponse
description
Response to a submitted node; specifies which additional input transactions (if any) the recipient still needs to complete the graph. An empty / null response means the graph is complete.
messages
1 field
GASPNodeResponse
1 field
$ref
#/components/messages/GASPNodeResponse

Operations

7

sendInitialRequest

send
Initiator sends sync parameters to the responder.
action
send
channel
1 field
$ref
#/channels/gaspInitialRequest
summary
Initiator sends sync parameters to the responder.
messages
1 item
  1. $ref
    #/channels/gaspInitialRequest/messages/GASPInitialRequest

receiveInitialResponse

receive
Initiator receives the responder's UTXO list and since timestamp.
action
receive
channel
1 field
$ref
#/channels/gaspInitialResponse
summary
Initiator receives the responder's UTXO list and since timestamp.
messages
1 item
  1. $ref
    #/channels/gaspInitialResponse/messages/GASPInitialResponse

sendInitialReply

send
Initiator (bidirectional mode only) sends UTXOs the responder is missing.
action
send
channel
1 field
$ref
#/channels/gaspInitialReply
summary
Initiator (bidirectional mode only) sends UTXOs the responder is missing.
messages
1 item
  1. $ref
    #/channels/gaspInitialReply/messages/GASPInitialReply

requestNode

send
Request a specific transaction node from the counterparty.
action
send
channel
1 field
$ref
#/channels/gaspRequestNode
summary
Request a specific transaction node from the counterparty.
messages
1 item
  1. $ref
    #/channels/gaspRequestNode/messages/GASPNodeRequest

deliverNode

receive
Receive a requested graph node from the counterparty.
action
receive
channel
1 field
$ref
#/channels/gaspNode
summary
Receive a requested graph node from the counterparty.
messages
1 item
  1. $ref
    #/channels/gaspNode/messages/GASPNode

submitNode

send
Push a graph node to the counterparty for ingestion.
action
send
channel
1 field
$ref
#/channels/gaspSubmitNode
summary
Push a graph node to the counterparty for ingestion.
messages
1 item
  1. $ref
    #/channels/gaspSubmitNode/messages/GASPNode

receiveNodeResponse

receive
Receive the counterparty's response to a submitted node, listing any additional input transactions needed to complete the graph.
action
receive
channel
1 field
$ref
#/channels/gaspNodeResponse
summary
Receive the counterparty's response to a submitted node, listing any additional input transactions needed to complete the graph.
messages
1 item
  1. $ref
    #/channels/gaspNodeResponse/messages/GASPNodeResponse

Messages

6

GASPInitialRequest

First message in a GASP sync session. The initiator declares its protocol version, the timestamp of the last sync with this party, and an optional page size limit.
name
GASPInitialRequest
title
GASP Initial Request
summary
First message in a GASP sync session. The initiator declares its protocol version, the timestamp of the last sync with this party, and an optional page size limit.
payload
1 field
$ref
#/components/schemas/GASPInitialRequest

GASPInitialResponse

Responder's reply to GASPInitialRequest. Contains the list of UTXOs the responder has seen since `request.since`, plus the timestamp from which the responder wants UTXOs back from the initiator.
name
GASPInitialResponse
title
GASP Initial Response
summary
Responder's reply to GASPInitialRequest. Contains the list of UTXOs the responder has seen since `request.since`, plus the timestamp from which the responder wants UTXOs back from the initiator.
payload
1 field
$ref
#/components/schemas/GASPInitialResponse

GASPInitialReply

Initiator's follow-up (bidirectional mode). UTXOs the initiator holds that were not in the Initial Response — i.e. UTXOs the responder needs.
name
GASPInitialReply
title
GASP Initial Reply
summary
Initiator's follow-up (bidirectional mode). UTXOs the initiator holds that were not in the Initial Response — i.e. UTXOs the responder needs.
payload
1 field
$ref
#/components/schemas/GASPInitialReply

GASPNodeRequest

Request for a specific transaction node identified by graphID, txid, outputIndex, and whether transaction/output metadata should be included.
name
GASPNodeRequest
title
GASP Node Request
summary
Request for a specific transaction node identified by graphID, txid, outputIndex, and whether transaction/output metadata should be included.
payload
1 field
$ref
#/components/schemas/GASPNodeRequest

GASPNode

A transaction node: the raw transaction, the output index, an optional BUMP merkle proof, optional metadata strings, and a mapping of input outpoints to metadata hashes so the receiver can request ancestors.
name
GASPNode
title
GASP Node
summary
A transaction node: the raw transaction, the output index, an optional BUMP merkle proof, optional metadata strings, and a mapping of input outpoints to metadata hashes so the receiver can request ancestors.
payload
1 field
$ref
#/components/schemas/GASPNode

GASPNodeResponse

Response to a submitted GASPNode. Lists the input outpoints (in 36-byte `<txid>.<vout>` format) that the recipient still needs to complete the graph. A null / absent response means no further inputs are required and the graph is complete.
name
GASPNodeResponse
title
GASP Node Response
summary
Response to a submitted GASPNode. Lists the input outpoints (in 36-byte `<txid>.<vout>` format) that the recipient still needs to complete the graph. A null / absent response means no further inputs are required and the graph is complete.
payload
1 field
$ref
#/components/schemas/GASPNodeResponse

Schemas

8

GASPInitialRequest

Parameters sent by the initiator to start a GASP sync session. Version mismatch (current version is 1) causes the responder to throw GASPVersionMismatchError and abort the session.
type
object
description
Parameters sent by the initiator to start a GASP sync session. Version mismatch (current version is 1) causes the responder to throw GASPVersionMismatchError and abort the session.
required
2 items
  1. version
  2. since
properties
3 fields
version
4 fields
type
integer
description
GASP protocol version. Currently always 1.
enum
1 item
  1. 1
example
1
since
4 fields
type
integer
minimum
0
description
UNIX timestamp (seconds since epoch) of the last successful sync with this counterparty. Use 0 to request all UTXOs. Must be a non-negative integer.
example
1714000000
limit
4 fields
type
integer
minimum
1
description
Optional maximum number of UTXOs the responder should return per page. When the response contains exactly `limit` items the initiator MUST send another GASPInitialRequest to fetch the next page. Absent means "return all".
example
1000

GASPInitialResponse

Responder's answer to GASPInitialRequest. `UTXOList` contains all UTXOs the responder has seen since `request.since`; unconfirmed (non-timestamped) UTXOs are always included regardless of timestamp.
type
object
description
Responder's answer to GASPInitialRequest. `UTXOList` contains all UTXOs the responder has seen since `request.since`; unconfirmed (non-timestamped) UTXOs are always included regardless of timestamp.
required
2 items
  1. UTXOList
  2. since
properties
2 fields
UTXOList
3 fields
type
array
description
UTXOs the responder knows about (after `request.since`). The initiator will request any of these it does not already hold.
items
1 field
$ref
#/components/schemas/GASPOutput
since
4 fields
type
integer
minimum
0
description
Timestamp from which the responder wants to receive UTXOs back from the initiator (used in the GASPInitialReply filter step).
example
1714001000

GASPInitialReply

Sent by the initiator in bidirectional mode. Contains UTXOs the initiator holds that are newer than `response.since` AND were not already present in the Initial Response (so the responder can ingest them).
type
object
description
Sent by the initiator in bidirectional mode. Contains UTXOs the initiator holds that are newer than `response.since` AND were not already present in the Initial Response (so the responder can ingest them).
required
1 item
  1. UTXOList
properties
1 field
UTXOList
3 fields
type
array
description
UTXOs the responder needs from the initiator.
items
1 field
$ref
#/components/schemas/GASPOutput

GASPOutput

Minimal outpoint descriptor used in the initial exchange phases. `score` is a sortable timestamp (seconds since epoch) assigned when the UTXO was first confirmed; unconfirmed UTXOs may have score 0.
type
object
description
Minimal outpoint descriptor used in the initial exchange phases. `score` is a sortable timestamp (seconds since epoch) assigned when the UTXO was first confirmed; unconfirmed UTXOs may have score 0.
required
3 items
  1. txid
  2. outputIndex
  3. score
properties
3 fields
txid
4 fields
type
string
pattern
^[0-9a-fA-F]{64}$
description
Transaction ID (hex, 64 characters).
example
a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
outputIndex
4 fields
type
integer
minimum
0
description
Output index (vout) within the transaction.
example
0
score
3 fields
type
number
description
Sortable confirmation timestamp (UNIX seconds). 0 for unconfirmed outputs. Used to filter UTXOs by the `since` parameters.
example
1714000000

GASPNodeRequest

Request for a specific graph node. `graphID` is the 36-byte outpoint string (`<txid>.<vout>`) identifying the tip of the graph being walked.
type
object
description
Request for a specific graph node. `graphID` is the 36-byte outpoint string (`<txid>.<vout>`) identifying the tip of the graph being walked.
required
4 items
  1. graphID
  2. txid
  3. outputIndex
  4. metadata
properties
4 fields
graphID
3 fields
type
string
description
Graph identifier — the 36-byte outpoint string (`<txid>.<vout>`) of the UTXO at the tip of this sync graph.
example
a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2.0
txid
4 fields
type
string
pattern
^[0-9a-fA-F]{64}$
description
Transaction ID of the node being requested.
example
a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
outputIndex
4 fields
type
integer
minimum
0
description
Output index within the requested transaction.
example
0
metadata
3 fields
type
boolean
description
Whether the responder should include transaction and output metadata in the returned GASPNode.
example
true

GASPNode

A fully-hydrated graph node. `rawTx` is the complete serialised Bitcoin transaction in hex. `proof` is a hex-encoded BUMP (BRC-74) merkle proof, only present for confirmed transactions. `inputs` maps each input outpoint (`<txid>.<vout>`) to the hash of its metadata, allowing the recipient to detect when it needs updated metadata.
type
object
description
A fully-hydrated graph node. `rawTx` is the complete serialised Bitcoin transaction in hex. `proof` is a hex-encoded BUMP (BRC-74) merkle proof, only present for confirmed transactions. `inputs` maps each input outpoint (`<txid>.<vout>`) to the hash of its metadata, allowing the recipient to detect when it needs updated metadata.
required
3 items
  1. graphID
  2. rawTx
  3. outputIndex
properties
7 fields
graphID
3 fields
type
string
description
Outpoint string (`<txid>.<vout>`) of the UTXO at the graph tip.
example
a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2.0
rawTx
3 fields
type
string
description
Complete Bitcoin transaction serialised as a lowercase hex string.
example
0100000001...
outputIndex
4 fields
type
integer
minimum
0
description
The output index within rawTx that this node represents.
example
0
proof
2 fields
type
string
description
Hex-encoded BUMP merkle proof for the transaction. Present only when the transaction is confirmed in a block.
txMetadata
2 fields
type
string
description
Opaque string of transaction-level metadata. Present only when the request set `metadata: true`.
outputMetadata
2 fields
type
string
description
Opaque string of output-level metadata. Present only when the request set `metadata: true`.
inputs
3 fields
type
object
description
Mapping of input outpoints (`<txid>.<vout>`) to an object containing the hash of their metadata. Present only when `metadata: true` was requested.
additionalProperties
3 fields
type
object
required
1 item
  1. hash
properties
1 field
hash
2 fields
type
string
description
Hash of the input's metadata (hex or base64).

GASPNodeResponse

Response to a submitted GASPNode. `requestedInputs` lists outpoints the recipient still needs in order to complete the graph and whether metadata is required for each. If null or omitted, the graph is complete and will be validated and finalised.
type
object
description
Response to a submitted GASPNode. `requestedInputs` lists outpoints the recipient still needs in order to complete the graph and whether metadata is required for each. If null or omitted, the graph is complete and will be validated and finalised.
properties
1 field
requestedInputs
3 fields
type
object
description
Mapping of input outpoints (`<txid>.<vout>`) to their metadata requirement. An empty object or absent field signals completion.
additionalProperties
3 fields
type
object
required
1 item
  1. metadata
properties
1 field
metadata
2 fields
type
boolean
description
Whether the submitter should include metadata for this input.

GASPVersionMismatchError

Thrown (and serialised into the response) when the responder's GASP version differs from the version declared in GASPInitialRequest.
type
object
description
Thrown (and serialised into the response) when the responder's GASP version differs from the version declared in GASPInitialRequest.
required
4 items
  1. code
  2. message
  3. currentVersion
  4. foreignVersion
properties
4 fields
code
2 fields
type
string
enum
1 item
  1. ERR_GASP_VERSION_MISMATCH
message
2 fields
type
string
example
GASP version mismatch. Current version: 1, foreign version: 2
currentVersion
3 fields
type
integer
description
The responder's supported GASP version.
example
1
foreignVersion
3 fields
type
integer
description
The version declared by the initiator.
example
2
Raw YAML source
asyncapi: "3.1.0"

info:
  title: GASP — Graph Aware Sync Protocol
  version: "1.0.0"
  description: |
    AsyncAPI specification for GASP (Graph Aware Sync Protocol), the
    cross-node UTXO synchronisation protocol implemented in
    `gasp-core` (`@bsv/gasp-core`).

    GASP is a bidirectional gossip/sync protocol between overlay nodes.
    Two parties exchange UTXO lists (the "initial exchange") and then
    walk the transaction graph in a request/response pattern to transfer
    any UTXOs the counterparty does not yet hold.

    ## Protocol flow (normal, bidirectional)

    ```
    Initiator                                   Responder
       |                                             |
       |-- GASPInitialRequest ---------------------->|
       |<- GASPInitialResponse -----------------------|
       |-- GASPInitialReply ------------------------->|   (if not unidirectional)
       |                                             |
       |  [for each UTXO the counterparty is missing]
       |-- requestNode(graphID, txid, vout, meta) -->|
       |<- GASPNode ---------------------------------|
       |                                             |
       |  [responder may request further inputs]
       |<- submitNode(GASPNode) ---------------------|
       |-- GASPNodeResponse ------------------------>|
       |          (repeat until graph is complete)
       |                                             |
    ```

    Source of truth: /ts/gasp-core/src/GASP.ts
  license:
    name: Open BSV Licence

defaultContentType: application/json

# ---------------------------------------------------------------------------
# Channels
# ---------------------------------------------------------------------------
channels:
  gaspInitialRequest:
    address: gasp/initialRequest
    description: |
      Initiator sends its sync parameters.  The responder replies on the
      `gasp/initialResponse` channel.
    messages:
      GASPInitialRequest:
        $ref: "#/components/messages/GASPInitialRequest"

  gaspInitialResponse:
    address: gasp/initialResponse
    description: |
      Responder sends back its list of known UTXOs and the timestamp from
      which it wants to receive UTXOs from the initiator.
    messages:
      GASPInitialResponse:
        $ref: "#/components/messages/GASPInitialResponse"

  gaspInitialReply:
    address: gasp/initialReply
    description: |
      Initiator (if operating in bidirectional mode) sends the set of UTXOs
      it holds that the responder does not.  Absent in unidirectional mode.
    messages:
      GASPInitialReply:
        $ref: "#/components/messages/GASPInitialReply"

  gaspRequestNode:
    address: gasp/requestNode
    description: |
      Either party requests a specific graph node (transaction + output) from
      the other.  Used when walking the transaction graph to hydrate UTXOs.
    messages:
      GASPNodeRequest:
        $ref: "#/components/messages/GASPNodeRequest"

  gaspNode:
    address: gasp/node
    description: |
      The responding party delivers the requested GASPNode (raw transaction,
      optional BUMP proof, optional metadata).
    messages:
      GASPNode:
        $ref: "#/components/messages/GASPNode"

  gaspSubmitNode:
    address: gasp/submitNode
    description: |
      A party submits a node it is trying to push to the counterparty.
      The counterparty appends it to the temporary graph and may respond
      with a list of additional inputs it still needs.
    messages:
      GASPNode:
        $ref: "#/components/messages/GASPNode"

  gaspNodeResponse:
    address: gasp/nodeResponse
    description: |
      Response to a submitted node; specifies which additional input transactions
      (if any) the recipient still needs to complete the graph.  An empty / null
      response means the graph is complete.
    messages:
      GASPNodeResponse:
        $ref: "#/components/messages/GASPNodeResponse"

# ---------------------------------------------------------------------------
# Operations
# ---------------------------------------------------------------------------
operations:
  sendInitialRequest:
    action: send
    channel:
      $ref: "#/channels/gaspInitialRequest"
    summary: Initiator sends sync parameters to the responder.
    messages:
      - $ref: "#/channels/gaspInitialRequest/messages/GASPInitialRequest"

  receiveInitialResponse:
    action: receive
    channel:
      $ref: "#/channels/gaspInitialResponse"
    summary: Initiator receives the responder's UTXO list and since timestamp.
    messages:
      - $ref: "#/channels/gaspInitialResponse/messages/GASPInitialResponse"

  sendInitialReply:
    action: send
    channel:
      $ref: "#/channels/gaspInitialReply"
    summary: |
      Initiator (bidirectional mode only) sends UTXOs the responder is missing.
    messages:
      - $ref: "#/channels/gaspInitialReply/messages/GASPInitialReply"

  requestNode:
    action: send
    channel:
      $ref: "#/channels/gaspRequestNode"
    summary: Request a specific transaction node from the counterparty.
    messages:
      - $ref: "#/channels/gaspRequestNode/messages/GASPNodeRequest"

  deliverNode:
    action: receive
    channel:
      $ref: "#/channels/gaspNode"
    summary: Receive a requested graph node from the counterparty.
    messages:
      - $ref: "#/channels/gaspNode/messages/GASPNode"

  submitNode:
    action: send
    channel:
      $ref: "#/channels/gaspSubmitNode"
    summary: Push a graph node to the counterparty for ingestion.
    messages:
      - $ref: "#/channels/gaspSubmitNode/messages/GASPNode"

  receiveNodeResponse:
    action: receive
    channel:
      $ref: "#/channels/gaspNodeResponse"
    summary: |
      Receive the counterparty's response to a submitted node, listing any
      additional input transactions needed to complete the graph.
    messages:
      - $ref: "#/channels/gaspNodeResponse/messages/GASPNodeResponse"

# ---------------------------------------------------------------------------
# Components
# ---------------------------------------------------------------------------
components:
  messages:
    GASPInitialRequest:
      name: GASPInitialRequest
      title: GASP Initial Request
      summary: |
        First message in a GASP sync session.  The initiator declares its
        protocol version, the timestamp of the last sync with this party, and
        an optional page size limit.
      payload:
        $ref: "#/components/schemas/GASPInitialRequest"

    GASPInitialResponse:
      name: GASPInitialResponse
      title: GASP Initial Response
      summary: |
        Responder's reply to GASPInitialRequest.  Contains the list of UTXOs
        the responder has seen since `request.since`, plus the timestamp from
        which the responder wants UTXOs back from the initiator.
      payload:
        $ref: "#/components/schemas/GASPInitialResponse"

    GASPInitialReply:
      name: GASPInitialReply
      title: GASP Initial Reply
      summary: |
        Initiator's follow-up (bidirectional mode).  UTXOs the initiator holds
        that were not in the Initial Response — i.e. UTXOs the responder needs.
      payload:
        $ref: "#/components/schemas/GASPInitialReply"

    GASPNodeRequest:
      name: GASPNodeRequest
      title: GASP Node Request
      summary: |
        Request for a specific transaction node identified by graphID, txid,
        outputIndex, and whether transaction/output metadata should be included.
      payload:
        $ref: "#/components/schemas/GASPNodeRequest"

    GASPNode:
      name: GASPNode
      title: GASP Node
      summary: |
        A transaction node: the raw transaction, the output index, an optional
        BUMP merkle proof, optional metadata strings, and a mapping of input
        outpoints to metadata hashes so the receiver can request ancestors.
      payload:
        $ref: "#/components/schemas/GASPNode"

    GASPNodeResponse:
      name: GASPNodeResponse
      title: GASP Node Response
      summary: |
        Response to a submitted GASPNode.  Lists the input outpoints (in
        36-byte `<txid>.<vout>` format) that the recipient still needs to
        complete the graph.  A null / absent response means no further inputs
        are required and the graph is complete.
      payload:
        $ref: "#/components/schemas/GASPNodeResponse"

  schemas:
    # -----------------------------------------------------------------------
    GASPInitialRequest:
      type: object
      description: |
        Parameters sent by the initiator to start a GASP sync session.
        Version mismatch (current version is 1) causes the responder to throw
        GASPVersionMismatchError and abort the session.
      required:
        - version
        - since
      properties:
        version:
          type: integer
          description: GASP protocol version.  Currently always 1.
          enum: [1]
          example: 1
        since:
          type: integer
          minimum: 0
          description: |
            UNIX timestamp (seconds since epoch) of the last successful sync
            with this counterparty.  Use 0 to request all UTXOs.
            Must be a non-negative integer.
          example: 1714000000
        limit:
          type: integer
          minimum: 1
          description: |
            Optional maximum number of UTXOs the responder should return per
            page.  When the response contains exactly `limit` items the
            initiator MUST send another GASPInitialRequest to fetch the next
            page.  Absent means "return all".
          example: 1000

    GASPInitialResponse:
      type: object
      description: |
        Responder's answer to GASPInitialRequest.  `UTXOList` contains all
        UTXOs the responder has seen since `request.since`; unconfirmed
        (non-timestamped) UTXOs are always included regardless of timestamp.
      required:
        - UTXOList
        - since
      properties:
        UTXOList:
          type: array
          description: |
            UTXOs the responder knows about (after `request.since`).  The
            initiator will request any of these it does not already hold.
          items:
            $ref: "#/components/schemas/GASPOutput"
        since:
          type: integer
          minimum: 0
          description: |
            Timestamp from which the responder wants to receive UTXOs back
            from the initiator (used in the GASPInitialReply filter step).
          example: 1714001000

    GASPInitialReply:
      type: object
      description: |
        Sent by the initiator in bidirectional mode.  Contains UTXOs the
        initiator holds that are newer than `response.since` AND were not
        already present in the Initial Response (so the responder can ingest
        them).
      required:
        - UTXOList
      properties:
        UTXOList:
          type: array
          description: UTXOs the responder needs from the initiator.
          items:
            $ref: "#/components/schemas/GASPOutput"

    GASPOutput:
      type: object
      description: |
        Minimal outpoint descriptor used in the initial exchange phases.
        `score` is a sortable timestamp (seconds since epoch) assigned when
        the UTXO was first confirmed; unconfirmed UTXOs may have score 0.
      required:
        - txid
        - outputIndex
        - score
      properties:
        txid:
          type: string
          pattern: "^[0-9a-fA-F]{64}$"
          description: Transaction ID (hex, 64 characters).
          example: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
        outputIndex:
          type: integer
          minimum: 0
          description: Output index (vout) within the transaction.
          example: 0
        score:
          type: number
          description: |
            Sortable confirmation timestamp (UNIX seconds).  0 for unconfirmed
            outputs.  Used to filter UTXOs by the `since` parameters.
          example: 1714000000

    GASPNodeRequest:
      type: object
      description: |
        Request for a specific graph node.  `graphID` is the 36-byte outpoint
        string (`<txid>.<vout>`) identifying the tip of the graph being walked.
      required:
        - graphID
        - txid
        - outputIndex
        - metadata
      properties:
        graphID:
          type: string
          description: |
            Graph identifier — the 36-byte outpoint string (`<txid>.<vout>`)
            of the UTXO at the tip of this sync graph.
          example: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2.0"
        txid:
          type: string
          pattern: "^[0-9a-fA-F]{64}$"
          description: Transaction ID of the node being requested.
          example: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
        outputIndex:
          type: integer
          minimum: 0
          description: Output index within the requested transaction.
          example: 0
        metadata:
          type: boolean
          description: |
            Whether the responder should include transaction and output metadata
            in the returned GASPNode.
          example: true

    GASPNode:
      type: object
      description: |
        A fully-hydrated graph node.  `rawTx` is the complete serialised
        Bitcoin transaction in hex.  `proof` is a hex-encoded BUMP (BRC-74)
        merkle proof, only present for confirmed transactions.  `inputs` maps
        each input outpoint (`<txid>.<vout>`) to the hash of its metadata,
        allowing the recipient to detect when it needs updated metadata.
      required:
        - graphID
        - rawTx
        - outputIndex
      properties:
        graphID:
          type: string
          description: |
            Outpoint string (`<txid>.<vout>`) of the UTXO at the graph tip.
          example: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2.0"
        rawTx:
          type: string
          description: Complete Bitcoin transaction serialised as a lowercase hex string.
          example: "0100000001..."
        outputIndex:
          type: integer
          minimum: 0
          description: The output index within rawTx that this node represents.
          example: 0
        proof:
          type: string
          description: |
            Hex-encoded BUMP merkle proof for the transaction.  Present only
            when the transaction is confirmed in a block.
        txMetadata:
          type: string
          description: |
            Opaque string of transaction-level metadata.  Present only when
            the request set `metadata: true`.
        outputMetadata:
          type: string
          description: |
            Opaque string of output-level metadata.  Present only when the
            request set `metadata: true`.
        inputs:
          type: object
          description: |
            Mapping of input outpoints (`<txid>.<vout>`) to an object
            containing the hash of their metadata.  Present only when
            `metadata: true` was requested.
          additionalProperties:
            type: object
            required:
              - hash
            properties:
              hash:
                type: string
                description: Hash of the input's metadata (hex or base64).

    GASPNodeResponse:
      type: object
      description: |
        Response to a submitted GASPNode.  `requestedInputs` lists outpoints
        the recipient still needs in order to complete the graph and whether
        metadata is required for each.  If null or omitted, the graph is
        complete and will be validated and finalised.
      properties:
        requestedInputs:
          type: object
          description: |
            Mapping of input outpoints (`<txid>.<vout>`) to their metadata
            requirement.  An empty object or absent field signals completion.
          additionalProperties:
            type: object
            required:
              - metadata
            properties:
              metadata:
                type: boolean
                description: Whether the submitter should include metadata for this input.

  # -----------------------------------------------------------------------
  # Error shapes
  # -----------------------------------------------------------------------
    GASPVersionMismatchError:
      type: object
      description: |
        Thrown (and serialised into the response) when the responder's GASP
        version differs from the version declared in GASPInitialRequest.
      required:
        - code
        - message
        - currentVersion
        - foreignVersion
      properties:
        code:
          type: string
          enum:
            - "ERR_GASP_VERSION_MISMATCH"
        message:
          type: string
          example: "GASP version mismatch. Current version: 1, foreign version: 2"
        currentVersion:
          type: integer
          description: The responder's supported GASP version.
          example: 1
        foreignVersion:
          type: integer
          description: The version declared by the initiator.
          example: 2