# Overview

The `five-bells-ledger` WebSocket API provides a way for real-time access to the ledger.


## Endpoint

The URL for the websocket endpoint is available by `GET`ting the ledger's main URI (metadata endpoint) and inspecting the `urls.websocket` property. Example:

###### Request
``` http
GET / HTTP/1.1
Host: ledger.example
```

###### Response (irrelevant fields omitted)
``` http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "urls": {
    "websocket": "wss://ledger.example/websocket"
  }
}
```

## Authentication

Unfortunately, browsers do not support setting a custom auth header (for `Basic` auth from a browser client) for websocket connections. So in order to support any type of client, we need to use [token-based authentication](https://auth0.com/blog/auth-with-socket-io/).

The client first makes a regular HTTP request to obtain a token:

``` http
POST /authenticate HTTP/1.1
Accept: application/json
Authorization: Basic c3RlZmFuOnN0ZWZhbg==
```
``` http
HTTP 200 OK
Content-Type: application/json

{ "token": "...xyz..." }
```

Note that the authenticate request fails if the user does not successfully authenticate. Anonymous requests are not allowed.

The client then uses this token as a query parameter when initiating the websocket connection:

``` http
GET /websocket?token=...xyz... HTTP/1.1
Connection: Upgrade
Upgrade: websocket
```
``` http
HTTP 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
```

The websocket client is now treated as the user who initiated the `/authenticate` request. Anonymous connections (without token) are disallowed.

The token is simply an opaque string from the client's perspective. The server may use a technology like [JWT](https://jwt.io/) to generate the token.

## Bidirectional JSON-RPC 2.0

In JSON-RPC 2.0 requests always go from "client" to "server" and responses always go from "server" to "client". Each response must be solicited by a prior request. In order to implement a publish/subscribe flow, the ledger must be able to send unsolicited messages. Therefore, the ledger and the TCP client must be acting as both JSON-RPC client and JSON-RPC server.

## Legend

The examples in this document use the following convention:

``` json
--> data sent from Client to Ledger
<-- data sent from Ledger to Client
```

# Commands

#### subscribe_account
<code>subscribe_account({ eventType: String, accounts: String[] }) ⇒ null</code>

Subscribe to events related to zero or more accounts.

Parameters

* `eventType` - Scope of the subscription. Valid scopes are:

  * `"transfer.create"` - Triggered for newly created transfer
  * `"transfer.update"` - Triggered for transfer changes (e.g. state changes)

  Note that a wildcard may be used to refer to multiple events, e.g. `transfer.*` would subscribe to all transfer events.

* `accounts` - List of accounts to subscribe to. 

  Admins are allowed to subscribe to any account whereas regular users are allowed only to subscribe to their own account.

###### Example
```json
--> {
      "jsonrpc": "2.0",
      "method": "subscribe_account",
      "params": [{
        "eventType": "transfer.*",
        "accounts": ["https://ledger.example/accounts/alice"]
      }],
      "id": 1
    }
<-- {
      "jsonrpc": "2.0",
      "result": 19,
      "id": 1
    }
<-- {
      "jsonrpc": "2.0",
      "method": "notify",
      "params": [{
        "id": "https://ledger.example/notifications/c92f2a2c-b21d-4e6c-96e7-4f6d6df4bee9",
        "event": "transfer.update",

        "resource": {
          "id": "https://ledger.example/transfers/155dff3f-4915-44df-a707-acc4b527bcbd",
          "ledger": "http://localhost",
          "debits": [{
            "account": "https://ledger.example/accounts/alice",
            "amount": "10",
            "authorized": true
          }],
          "credits": [{
            "account": "https://ledger.example/accounts/bob",
            "amount": "10"
          }],
          "state": "executed"
        }
      }],
      "id": null
    }
<-- {
      "jsonrpc": "2.0",
      "method": "notify",
      "params": [{
        "id": "https://ledger.example/notifications/52a42d6f-8d9c-4c05-b31c-cccc8bbdb30d",
        "event": "transfer.update",
        "resource": { /* transfer resource */ },
        "related_resources": {
          "execution_condition_fulfillment": "[ fulfillment ]",
          "cancellation_condition_fulfillment": "[ fulfillment ]"
        }
      }],
      "id": null
    }
```


#### subscribe_all_accounts
<code>subscribe_all_accounts({ eventType: String }) ⇒ null</code>

Subscribe to account-related events from all accounts. Requires admin permission.