.. code:: yaml

   type: google.api.Service
   config_version: 3

   http:
     rules:
       - selector: bdware.bdledger.api.Node.ClientVersion
         get: /v0/node/version
       - selector: bdware.bdledger.api.Ledger.CreateLedger
         post: /v0/ledgers
         body: "*"
       - selector: bdware.bdledger.api.Ledger.GetLedgers
         get: /v0/ledgers
       - selector: bdware.bdledger.api.Ledger.SendTransaction
         post: /v0/ledgers/{ledger}/transactions
         body: "*"
       - selector: bdware.bdledger.api.Query.GetBlockByHash
         get: /v0/ledgers/{ledger}/block
       - selector: bdware.bdledger.api.Query.GetBlocks
         post: /v0/ledgers/{ledger}/blocks/query
         body: "*"
       - selector: bdware.bdledger.api.Query.CountBlocks
         post: /v0/ledgers/{ledger}/blocks/count
         body: "*"
       - selector: bdware.bdledger.api.Query.GetRecentBlocks
         get: /v0/ledgers/{ledger}/blocks/recent
       - selector: bdware.bdledger.api.Query.GetTransactionByHash
         get: /v0/ledgers/{ledger}/transaction
       - selector: bdware.bdledger.api.Query.GetTransactionByBlockHashAndIndex
         get: /v0/ledgers/{ledger}/block/transaction
       - selector: bdware.bdledger.api.Query.GetTransactions
         post: /v0/ledgers/{ledger}/transactions/query
         body: "*"
       - selector: bdware.bdledger.api.Query.CountTransactions
         post: /v0/ledgers/{ledger}/transactions/count
         body: "*"

..

   **Note**

   Request/Response data of **bytes** type should/will be encoded with
   `Base64 <https://tools.ietf.org/html/rfc4648#section-4>`__.

   **Note**

   When using hash strings in URL, they need to be encoded with
   `encodeURIComponent <https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent>`__.

Request Examples {#_request_examples} ================

Node.ClientVersion {#_node_clientversion} ——————

Get BDLedger node version

::

   GET http://{{IP}}:{{PORT}}/v0/node/version

**Response.**

.. code:: json

   {
     "version": "dev-210119.a88bf4eb"
   }

Ledger.CreateLedger {#_ledger_createledger} ——————-

Create a new ledger

::

   POST http://{{IP}}:{{PORT}}/v0/ledgers

**Request body.**

.. code:: json

   {
     "name": "test"
   }

**Response.**

.. code:: json

   {
     "ok": true
   }

Ledger.GetLedgers {#_ledger_getledgers} —————–

Get all ledgers

::

   GET http://{{IP}}:{{PORT}}/v0/ledgers

**Response.**

.. code:: json

   {
     "ledgers": [
       "default",
       "test"
     ]
   }

Ledger.SendTransaction {#_ledger_sendtransaction} ———————-

Send a new transaction

::

   POST http://{{IP}}:{{PORT}}/v0/ledgers/test/transactions

**Request body.**

.. code:: json

   {
     "transaction": {
       "type": 0,
       "from": "8A3K/vANyv7wDcr+8A3K/vANyv4=",
       "nonce": 52,
       "data": "lQItWZKS5hlUn6V/DMKKwvZXxvM="
     }
   }

**Response.**

.. code:: json

   {
     "hash": "VQBeA5Ee0Y5hqEileoQuYMHbOSE="
   }

Query.GetBlockByHash {#_query_getblockbyhash} ——————–

Get a block identified by its hash

::

   GET http://{{IP}}:{{PORT}}/v0/ledgers/test/block?hash=LSKr%2BK079Ax%2BrKdlyYN5ze2YGzo%3D

**hash** has to be encoded with
`encodeURIComponent <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent>`__

**Response.**

.. code:: json

   {
     "block": {
       "hash": "LSKr+K079Ax+rKdlyYN5ze2YGzo=",
       "creator": "",
       "nonce": "0",
       "parentHashes": [
         "fLX5pMY8M1qSAGZdKT1rWBkdEMo=",
         "rk0DWMaUpRG82yVX+cFhbfhPFdw=",
         "3XkwkuMBearq8uavN76Te7Zdpl8="
       ],
       "witnesses": [],
       "timestamp": "1611038043",
       "size": "0",
       "transactionCount": 1,
       "transactionsRoot": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
       "transactions": [
         {
           "blockHash": "",
           "blockTimestamp": "0",
           "index": 0,
           "hash": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
           "type": "RECORD",
           "from": "8A3K/vANyv7wDcr+8A3K/vANyv4=",
           "nonce": "0",
           "to": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
           "data": "lQItWZKS5hlUn6V/DMKKwvZXxvM="
         }
       ],
       "transactionHashes": [
         "VQBeA5Ee0Y5hqEileoQuYMHbOSE="
       ]
     }
   }

Query.GetBlocks {#_query_getblocks} —————

Get blocks in a timestamp range

::

   POST http://{{IP}}:{{PORT}}/v0/ledgers/test/blocks/query

.. code:: protobuf

   enum IncludeTransactions {
     NONE = 0; // Don't include transaction data
     HASH = 1; // Include transactions hashes
     FULL = 2; // Include full transactions
   }

Requirement: asciimath:["start_timestamp"⇐"end_timestamp"]

If only **end_timestamp** is not specified, or
asciimath:["end_timestamp"-"start_timestamp">"query.maxDuration"], then
**end_timestamp** will be set to
asciimath:["start_timestamp"+"query.maxDuration"].

If only **start_timestamp** is not specified, then **start_timestamp**
will be set to asciimath:["end_timestamp"-"query.maxDuration"].

In all cases, **start_timestamp** will never be earlier than the genesis
block’s timestamp, and **end_timestamp** will never be later than the
current timestamp when the node process the query request.

**Request body 1.**

.. code:: json

   {
     "start_timestamp": 1611038000,
     "end_timestamp": 1611039000,
     "include_transactions": 0
   }

**Response 1.**

.. code:: json

   {
     "blocks": [
       {
         "hash": "LSKr+K079Ax+rKdlyYN5ze2YGzo=",
         "creator": "",
         "nonce": "0",
         "parentHashes": [
           "fLX5pMY8M1qSAGZdKT1rWBkdEMo=",
           "rk0DWMaUpRG82yVX+cFhbfhPFdw=",
           "3XkwkuMBearq8uavN76Te7Zdpl8="
         ],
         "witnesses": [],
         "timestamp": "1611038043",
         "size": "0",
         "transactionCount": 1,
         "transactionsRoot": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
         "transactions": [],
         "transactionHashes": []
       }
     ],
     "startTimestamp": "1611038043",
     "endTimestamp": "1611038043"
   }

**Request body 2.**

.. code:: json

   {
     "start_timestamp": 1611038000,
     "end_timestamp": 1611039000,
     "include_transactions": 1
   }

**Response 2.**

.. code:: json

   {
     "blocks": [
       {
         "hash": "LSKr+K079Ax+rKdlyYN5ze2YGzo=",
         "creator": "",
         "nonce": "0",
         "parentHashes": [
           "fLX5pMY8M1qSAGZdKT1rWBkdEMo=",
           "rk0DWMaUpRG82yVX+cFhbfhPFdw=",
           "3XkwkuMBearq8uavN76Te7Zdpl8="
         ],
         "witnesses": [],
         "timestamp": "1611038043",
         "size": "0",
         "transactionCount": 1,
         "transactionsRoot": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
         "transactions": [],
         "transactionHashes": [
           "VQBeA5Ee0Y5hqEileoQuYMHbOSE="
         ]
       }
     ],
     "startTimestamp": "1611038043",
     "endTimestamp": "1611038043"
   }

**Request body 3.**

.. code:: json

   {
     "start_timestamp": 1611038000,
     "end_timestamp": 1611039000,
     "include_transactions": 2
   }

**Response 3.**

.. code:: json

   {
     "blocks": [
       {
         "hash": "LSKr+K079Ax+rKdlyYN5ze2YGzo=",
         "creator": "",
         "nonce": "0",
         "parentHashes": [
           "fLX5pMY8M1qSAGZdKT1rWBkdEMo=",
           "rk0DWMaUpRG82yVX+cFhbfhPFdw=",
           "3XkwkuMBearq8uavN76Te7Zdpl8="
         ],
         "witnesses": [],
         "timestamp": "1611038043",
         "size": "0",
         "transactionCount": 1,
         "transactionsRoot": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
         "transactions": [
           {
             "blockHash": "",
             "blockTimestamp": "0",
             "index": 0,
             "hash": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
             "type": "RECORD",
             "from": "8A3K/vANyv7wDcr+8A3K/vANyv4=",
             "nonce": "0",
             "to": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
             "data": "lQItWZKS5hlUn6V/DMKKwvZXxvM="
           }
         ],
         "transactionHashes": [
           "VQBeA5Ee0Y5hqEileoQuYMHbOSE="
         ]
       }
     ],
     "startTimestamp": "1611038043",
     "endTimestamp": "1611038043"
   }

Query.CountBlocks {#_query_countblocks} —————–

Count all blocks in a ledger, or blocks in a timestamp range

::

   POST http://{{IP}}:{{PORT}}/v0/ledgers/test/blocks/count

Requirement: asciimath:["start_timestamp"⇐"end_timestamp"]

If neither **start_timestamp** nor **end_timestamp** is specified, then
count all blocks in the specified ledger.

If only **end_timestamp** is not specified, then count all blocks with
timestamps later than **start_timestamp**.

If only **start_timestamp** is not specified, then count all blocks with
timestamps earlier than **end_timestamp**.

In all cases, **start_timestamp** will never be earlier than the genesis
block’s timestamp, and **end_timestamp** will never be later than the
current timestamp when the node process the query request.

**Request body 1.**

.. code:: json

   {}

**Response 1.**

.. code:: json

   {
     "count": "5",
     "startTimestamp": "0",
     "endTimestamp": "1611039957"
   }

**Request body 2.**

.. code:: json

   {
     "start_timestamp": 1611038000,
     "end_timestamp": 1611039000
   }

**Response 2.**

.. code:: json

   {
     "count": "1",
     "startTimestamp": "1611038000",
     "endTimestamp": "1611039000"
   }

Query.GetRecentBlocks {#_query_getrecentblocks} ———————

Get recent **count** blocks (Only support IncludeTransactions=NONE for
now)

::

   GET http://{{IP}}:{{PORT}}/v0/ledgers/test/blocks/recent?count=2

**Response.**

.. code:: json

   {
     "blocks": [
       {
         "hash": "LSKr+K079Ax+rKdlyYN5ze2YGzo=",
         "creator": "",
         "nonce": "0",
         "parentHashes": [
           "fLX5pMY8M1qSAGZdKT1rWBkdEMo=",
           "rk0DWMaUpRG82yVX+cFhbfhPFdw=",
           "3XkwkuMBearq8uavN76Te7Zdpl8="
         ],
         "witnesses": [],
         "timestamp": "1611038043",
         "size": "0",
         "transactionCount": 1,
         "transactionsRoot": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
         "transactions": [],
         "transactionHashes": []
       },
       {
         "hash": "rk0DWMaUpRG82yVX+cFhbfhPFdw=",
         "creator": "",
         "nonce": "0",
         "parentHashes": [
           "fLX5pMY8M1qSAGZdKT1rWBkdEMo=",
           "3XkwkuMBearq8uavN76Te7Zdpl8=",
           "8pZPR74OALIbps5XFb4dL/s0j0M="
         ],
         "witnesses": [],
         "timestamp": "1610968019",
         "size": "0",
         "transactionCount": 1,
         "transactionsRoot": "LuxttCm/pSHVMOKF0sJExk+DJXc=",
         "transactions": [],
         "transactionHashes": []
       }
     ],
     "startTimestamp": "1610968019",
     "endTimestamp": "1611038043"
   }

Query.GetTransactionByHash {#_query_gettransactionbyhash} ————————–

Get a transaction identified by its hash

::

   GET http://{{IP}}:{{PORT}}/v0/ledgers/test/transaction?hash=VQBeA5Ee0Y5hqEileoQuYMHbOSE%3D

**hash** has to be encoded with
`encodeURIComponent <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent>`__

**Response.**

.. code:: json

   {
     "transaction": {
       "blockHash": "LSKr+K079Ax+rKdlyYN5ze2YGzo=",
       "blockTimestamp": "1611038043",
       "index": 0,
       "hash": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
       "type": "RECORD",
       "from": "8A3K/vANyv7wDcr+8A3K/vANyv4=",
       "nonce": "0",
       "to": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
       "data": "lQItWZKS5hlUn6V/DMKKwvZXxvM="
     }
   }

Query.GetTransactionByBlockHashAndIndex
{#_query_gettransactionbyblockhashandindex} —————————————

Get a transaction identified by hash of the block it belongs to and its
index inside the block

::

   GET http://{{IP}}:{{PORT}}/v0/ledgers/test/block/transaction?blockHash=LSKr%2BK079Ax%2BrKdlyYN5ze2YGzo%3D&index=0

**blockHash** has to be encoded with
`encodeURIComponent <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent>`__

**Response.**

.. code:: json

   {
     "transaction": {
       "blockHash": "LSKr+K079Ax+rKdlyYN5ze2YGzo=",
       "blockTimestamp": "1611038043",
       "index": 0,
       "hash": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
       "type": "RECORD",
       "from": "8A3K/vANyv7wDcr+8A3K/vANyv4=",
       "nonce": "0",
       "to": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
       "data": "lQItWZKS5hlUn6V/DMKKwvZXxvM="
     }
   }

Query.GetTransactions {#_query_gettransactions} ———————

Get transactions in a timestamp range

::

   POST http://{{IP}}:{{PORT}}/v0/ledgers/test/transactions/query

**start_timestamp** and **end_timestamp** follow the same requirements
and rules as in `??? <#Query.GetBlocks>`__.

**Request body.**

.. code:: json

   {
     "start_timestamp": 1611038000,
     "end_timestamp": 1611039000
   }

**Response.**

.. code:: json

   {
     "transactions": [
       {
         "blockHash": "",
         "blockTimestamp": "0",
         "index": 0,
         "hash": "VQBeA5Ee0Y5hqEileoQuYMHbOSE=",
         "type": "RECORD",
         "from": "8A3K/vANyv7wDcr+8A3K/vANyv4=",
         "nonce": "0",
         "to": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
         "data": "lQItWZKS5hlUn6V/DMKKwvZXxvM="
       }
     ],
     "startTimestamp": "1611038043",
     "endTimestamp": "1611038043"
   }

Query.CountTransactions {#_query_counttransactions} ———————–

Count all transactions in a ledger, or transactions in a timestamp range

::

   POST http://{{IP}}:{{PORT}}/v0/ledgers/test/transactions/count

**start_timestamp** and **end_timestamp** follow the same requirements
and rules as in `??? <#Query.CountBlocks>`__.

**Request body 1.**

.. code:: json

   {}

**Response 1.**

.. code:: json

   {
     "count": "4",
     "startTimestamp": "0",
     "endTimestamp": "1611039957"
   }

**Request body 2.**

.. code:: json

   {
     "start_timestamp": 1611038000,
     "end_timestamp": 1611039000
   }

**Response 2.**

.. code:: json

   {
     "count": "1",
     "startTimestamp": "1611038000",
     "endTimestamp": "1611039000"
   }
