Developers
Standalone Clients
Usage

Using Your Client

The Nym native client exposes a websocket interface that your code connects to. The default websocket port is 1977, you can override that in the client config if you want.

Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening for incoming messages.

Message Requests

The message types you can send up the websocket are defined here (opens in a new tab).

Getting your own address

When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files . If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send:

{
  "type": "selfAddress"
}

You'll receive a response of the format:

{
  "type": "selfAddress",
  "address": "your address" // e.g. "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
}

See here (opens in a new tab) for an example of this being used.

All native client example code begins with printing the selfAddress. Examples exist for Rust, Go, Javascript, and Python.

Sending text

If you want to send text information through the mixnet, format a message like this one and poke it into the websocket:

{
  "type": "send",
  "message": "the message",
  "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
}

In some applications, e.g. where people are chatting with friends who they know, you might want to include unencrypted reply information in the message field. This provides an easy way for the receiving chat to then turn around and send a reply message:

{
  "type": "send",
  "message": {
    "sender": "198427b63ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
    "chatMessage": "hi julia!"
  },
  "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
}

If that fits your security model, good. Otherwise, send anonymous replies using Single Use Reply Blocks (SURBs).

More on SURBs in the anonymous replies docs. In short, they let the receiver of a message reply to you without needing to know your client address.

Your client will send some replySurbs along to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write response data into, but cannot see the final destination of. If the recipient cannot fit its response into the bucket of SURBs sent to it, it will use a SURB to request more SURBs from your client.

{
    "type": "sendAnonymous",
    "message": "something you want to keep secret",
    "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
    "replySurbs": 20 // however many reply SURBs to send along with your message
}

See 'Replying to SURB Messages' below for an example of how to deal with incoming messages that have SURBs attached.

How many SURBs to generate and send with outgoing messages depends on the expected size of the reply. Send many SURBs to get the response as quickly as possible (accepting minor additional latency at send time, since your client has to generate and encrypt the packets), or send a few (e.g. 20) and let the recipient request more if needed (accepting additional latency in receiving the response).

Sending binary data

You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded Nym ClientRequest (opens in a new tab) containing the same information.

As a response the native-client will send a ServerResponse to be decoded. See Message Responses below for more.

You can find examples of sending and receiving binary data in the code examples (opens in a new tab), and an example project from the Nym community BTC-BC (opens in a new tab): Bitcoin transaction transmission via Nym, a client and service provider written in Rust.

Replying to SURB messages

Each bucket of replySURBs, when received as part of an incoming message, has a unique session identifier, which only identifies the bucket of pre-addressed packets. This is necessary to make sure that your app is replying to the correct people with the information meant for them in a situation where multiple clients are sending requests to a single service.

Constructing a reply with SURBs looks something like this (where senderTag was parsed from the incoming message)

{
    "type": "reply",
    "message": "reply you also want to keep secret",
    "senderTag": "the sender tag you parsed from the incoming message"
}

Error messages

Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format:

{
  "type": "error",
  "message": "string message"
}

LaneQueueLength

This is currently only used in the Socks Client to keep track of the number of Sphinx packets waiting to be sent to the mixnet via being slotted amongst cover traffic. As this value becomes larger, the client signals to the application it should slow down the speed with which it writes to the proxy. This is to stop situations arising whereby an app connected to the client appears as if it has sent (e.g.) a bunch of messages and is awaiting a reply, when they in fact have not been sent through the mixnet yet.

Message Responses

Responses to your messages are defined here (opens in a new tab):

#[derive(Debug)]
pub enum ServerResponse {
    Received(ReconstructedMessage),
    SelfAddress(Box<Recipient>),
    LaneQueueLength { lane: u64, queue_length: usize },
    Error(error::Error),
}