Skip to content
Niftyhelp 2026.10.2 Support

Remote for developers

How an app pairs with Nifty and reaches its API through Nifty Plus's Remote relay, encrypted end to end. Protocol version 1, in beta.

On this page

Remote carries the Nifty API between a device and your copy of Nifty through Nifty Plus's relay. This page describes protocol version 1, so you can write your own client. Remote is in beta, so the protocol can change in any release.

The relay never sees what's sent. The device and Nifty run TLS 1.3 to each other inside the relay's WebSockets, and each pins the other's key.

The relay

Use the relay that the QR code's relay names. For a typed code, use https://remote.thenifty.app. Keep using the same relay once paired.

A device opens a WebSocket to the relay and waits for its first message, a text frame with {"type":"ready"}. That means Nifty has answered. After that, both sides send only binary frames of up to 1 MiB, which carry the TLS connection's bytes. The relay closes a connection that sends a text frame, a larger frame, or anything before ready.

To WebSocket
Pair wss://<relay>/v1/pair/{tag}
Connect once paired wss://<relay>/v1/connect/{route}

Instead of opening the WebSocket, the relay can answer:

  • 401 when a connection to a route shows no relay pass, or one Nifty doesn't list, such as a revoked device's.
  • 404 for an unknown or expired pairing tag, or a malformed route.
  • 426 when the request isn't a WebSocket.
  • 429 when there are too many requests from your address, or too many connections to that copy of Nifty (32).
  • 503 when Nifty isn't connected to the relay, or has used this month's allowance.

If Nifty doesn't answer within 15 seconds, the relay closes the WebSocket. Its close codes are:

Code Why
4001 Nifty's connection to Nifty Plus ended.
4002 This month's allowance is used up.
4003 The other side left.
4004 Something was sent that the relay doesn't allow.
4005 Nifty didn't answer.
4006 The device was revoked.

Pair

The owner chooses Pair a device, and Nifty shows a code such as ABCD-EFGH-JKMN-PQRS, with a QR code holding nifty-remote:pair?v=1&code=…&relay=…&key=…. A code uses the letters A to Z except I and O, and the digits 2 to 9. Accept a typed code in upper or lower case, with or without the dashes and spaces.

  1. Make a key pair for the device (ECDSA P-256 is fine), in a self-signed certificate. Nifty pins the public key, so keep the key for as long as the device is paired.
  2. Work out the tag: the SHA-256 of nifty remote pairing v1 tag, a zero byte, and the code in upper case without dashes, in base64url without padding.
  3. Open /v1/pair/{tag} and wait for ready.
  4. Run TLS 1.3 inside the WebSocket with your certificate, asking for the ALPN protocol nifty-pair/1. If the QR code gave a key, check that the SHA-256 of the SubjectPublicKeyInfo in Nifty's certificate, in base64url, is that key.
  5. Export 32 bytes of keying material with the label EXPORTER-nifty-remote-pairing-v1 and no context.
  6. Straight away, send your hello as one line of JSON: {"v":1,"tag":"…","name":"Ada's phone","proof":"…"}. The proof is an HMAC-SHA256 in base64url. Its key is the SHA-256 of nifty remote pairing v1 key, a zero byte and the code as in step 2. Its message is nifty remote pairing v1 device, a zero byte, and the exported bytes. Nifty keeps the first 50 characters of name, turns control characters into spaces, and uses "Device" if it's blank.
  7. Read Nifty's answer, a line of JSON. {"type":"proof","proof":"…"} is the same HMAC with the role nifty instead of device. Check it, and stop if it doesn't match. refused means the hello or the proof was wrong. expired means the code no longer works, or another device is already waiting for the owner. Either way, the connection closes.
  8. Keep the connection open while the owner decides. Closing it ends the pairing. The owner must answer within the code's 5 minutes. Then read the last line:
    • approved carries token (the device's API token), relay_pass, device_id, route and nifty_key. Check that nifty_key is the key of this connection's certificate, and the QR code's key if it had one, and stop if not. Pin nifty_key from now on. Keep token and relay_pass as safely as a password.
    • denied, expired or refused ends the pairing.

The proofs are bound to the TLS connection through the exported bytes, so a relay in the middle can't pass them on. Five wrong proofs end a pairing. The TLS handshake for pairing fails while no code is waiting, or while 2 devices are already pairing, and pairing works only through /v1/pair/{tag}. Nifty closes a pairing connection whose hello doesn't arrive within 15 seconds.

Connect

  1. Open /v1/connect/{route} with Authorization: Bearer <relay_pass>, and wait for ready. The relay lets you through only while Nifty lists the pass, so it turns a revoked device away before Nifty hears of it. Straight after pairing, retry a 401 for a few seconds before treating the device as revoked.
  2. Run TLS 1.3 with the device's certificate, asking for h2 or http/1.1. Check Nifty's key against nifty_key.
  3. Send API requests as usual, with Authorization: Bearer <token>. Only the device's own token works, and only through Remote. Anything else gets 401.

Only /api/v1 and file links answer through Remote. Endpoints that only Nifty's web app can use answer 403.

Some answers hold links: a file's address, the Location header of something just made, or the Link header's next page. Through Remote, these start with https://remote.nifty.invalid, an address that doesn't exist on the internet. To follow one, send it through Remote like any other request: keep the path and query, and ignore the address.

A revoked device gets 401 from the relay, and one connected at the time is closed with 4006. If the owner restores a backup or moves Nifty Plus, the old route answers 503 from then on, as it does while Nifty is offline. Pair again if that lasts.

Menu

2026.10.2Contact support