NUT-17: WebSockets¶
optional
depends on: NUT-07
This NUT defines a websocket protocol that enables bidirectional communication between apps and mints using the JSON-RPC format.
Subscriptions¶
The websocket enables real-time subscriptions that wallets can use to receive notifications for a state change of a MintQuoteResponse
(NUT-04), MeltQuoteResponse
(NUT-05), CheckStateResponse
(NUT-07).
A summary of the subscription flow is the following:
- A wallet connects to the websocket endpoint and sends a
WsRequest
with thesubscribe
command. - The mint responds with a
WsResponse
containing an ok or an error. - If the subscription was accepted, the mint sends a
WsNotification
of the current state of the subscribed objects and whenever there is an update for the wallet's subscriptions. - To close a subscription, the wallet sends
WsRequest
with theunsubscribe
command.
Specifications¶
The websocket is reachable via the mint's URL path /v1/ws
:
https://mint.com/v1/ws
NUT-17
uses the JSON-RPC format for all messages. There are three types of messages defined in this NUT.
Requests¶
All requests from the wallet to the mint are of the form of a WsRequest
:
{
"jsonrpc": "2.0",
"method": <str_enum[WsRequestMethod]>,
"params": <str_WsRequestParams>,
"id": <int>
}
WsRequestMethod
is a enum of strings with the supported commands "subscribe"
and "unsubscribe"
:
enum WsRequestMethod {
sub = "subscribe",
unsub = "unsubscribe",
}
WsRequestParams
is a serialized JSON with the parameters of the corresponding command.
Command: Subscribe¶
To subscribe to updates, the wallet sends a "subscribe"
command with the following params
parameters:
{
"kind": <str_enum[SubscriptionKind]>,
"subId": <string>,
"filters": <string[]>
}
Here, subId
is a unique uuid generated by the wallet and allows the client to map its requests to the mint's responses.
SubscriptionKind
is an enum with the following possible values:
enum SubscriptionKind {
bolt11_melt_quote = "bolt11_melt_quote",
bolt11_mint_quote = "bolt11_mint_quote",
proof_state = "proof_state",
}
The filters
are an array of mint quote IDs (NUT-04), or melt quote IDs (NUT-05), or Y
's (NUT-07) of the corresponding object to receive updates from.
As an example, filters
would be of the following form to subscribe for updates of three different mint quote IDs:
["20385fc7245...", "d06667cda9b...", "e14d8ca96f..."]
Note that id
and subId
are unrelated. The subId
is the ID for each subscription, whereas id
is part of the JSON-RPC spec and is an integer counter that must be incremented for every request sent over the websocket.
Important: If the subscription is accepted by the mint, the mint MUST first respond with the current state of the subscribed object and continue sending any further updates to it.
For example, if the wallet subscribes to a Proof.Y
of a Proof
that has not been spent yet, the mint will first respond with a ProofState
with state == "UNSPENT"
. If the wallet then spends this Proof
, the mint would send a ProofState
with state == "PENDING"
and then one with state == "SPENT"
. In total, the mint would send three notifications to the wallet.
Command: Unsubscribe¶
The wallet should always unsubscribe any subscriptions that is isn't interested in anymore. The parameters for the "unsubscribe"
command is only the subscription ID:
{
"subId": <string>
}
Responses¶
A WsResponse
is returned by the mint to both the "subscribe"
and "unsubscribe"
commands and indicates whether the request was successful:
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"subId": <str>
},
"id": <int>
}
Here, the id
corresponds to the id
in the request (as part of the JSON-RPC spec) and subId
corresponds to the subscription ID.
Notifications¶
WsNotification
's are sent from the mint to the wallet and contain subscription data in the following format
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"subId": <str>,
"payload": NotificationPayload
}
}
subId
is the subscription ID (previously generated by the wallet) this notification corresponds to. NotificationPayload
carries the subscription data which is a MintQuoteResponse
(NUT-04), a MeltQuoteResponse
(NUT-05), or a CheckStateResponse
(NUT-07), depending on what the corresponding SubscriptionKind
was.
Errors¶
WsErrors
for a given WsRequest
are returned in the following format
{
"jsonrpc": "2.0",
"error": {
"code": -32601,
"message": "Human readable error message"
},
"id": "1"
}
Example: ProofState
subscription¶
To subscribe to the ProofState
of a Proof
, the wallet establishes a websocket connection to https://mint.com/v1/ws
and sends a WsRequest
with a filters
chosen to be the a Proof.Y
value of the Proof
(see NUT-00). Note that filters
is an array meaning multiple subscriptions of the same kind
can be made in the same request.
Wallet:
{
"jsonrpc": "2.0",
"id": 0,
"method": "subscribe",
"params": {
"kind": "proof_state",
"filters": [
"02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d"
],
"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T"
}
}
The mint first responds with a WsResponse
confirming that the subscription has been added.
Mint:
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T"
},
"id": 0
}
The mint immediately sends the current ProofState
of the subscription as a WsNotification
.
Mint:
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T",
"payload": {
"Y": "02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d",
"state": "UNSPENT",
"witness": null
}
}
}
While leaving the websocket connection open, the wallet then spends the ecash. The mint sends WsNotification
updating the wallet about state changes of the ProofState
accordingly:
Mint:
{"jsonrpc": "2.0", "method": "subscribe", "params": {"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T", "payload": {"Y": "02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d", "state": "PENDING"}}}
{"jsonrpc": "2.0", "method": "subscribe", "params": {"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T", "payload": {"Y": "02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d", "state": "SPENT"}}}
The wallet then unsubscribes.
Wallet:
{
"jsonrpc": "2.0",
"id": 1,
"method": "unsubscribe",
"params": { "subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T" }
}
Mint info setting¶
Mints signal websocket support via NUT-06 using the following setting:
"nuts": {
"17": {
"supported": [
{
"method": <str>,
"unit": <str>,
"commands": <str[]>
},
...
]
}
}
Here, commands
is an array of the commands that the mint supports. A mint that supports all commands would return ["bolt11_mint_quote", "bolt11_melt_quote", "proof_state"]
. Supported commands are given for each method-unit pair.
Example:
"nuts": {
"17": {
"supported": [
{
"method": "bolt11",
"unit": "sat",
"commands": [
"bolt11_mint_quote",
"bolt11_melt_quote",
"proof_state"
]
},
]
}
}