$ curl -x http://user:pass@xxx.nodetonet.com:48888 https://api.ipify.org→ 188.114.96.7$ curl ... -H "X-Session: abc" # sticky→ 188.114.96.7 # same IP (TTL 600s)$ curl ... -H "X-Rotate: 1" # rotate→ 92.184.117.42 # new IP SDK EXAMPLES nodetonet.com
SDK Python Node.js Go Ruby REST API

Nodetonet SDK examples — Python, Node.js, Go, and Ruby in ~20 lines each

Ready-to-run SDK-style clients for Python, Node.js, Go, and Ruby that call the Nodetonet REST API with a Bearer token. No official SDKs yet, but the API surface is small enough that a DIY wrapper is under 30 lines.

N Nodetonet Team
May 15, 2026 8 min read

TL;DR: Nodetonet has a small, stable REST API. Until official SDKs ship you can write a working client in any language in about 20 lines — and this page gives you those 20 lines for Python, Node.js, Go, and Ruby, ready to copy-paste.

This page collects short, working SDK-style examples for the four languages we get asked about most: Python, Node.js, Go, and Ruby. Every example creates a proxy or tunnel against POST /api/v1/proxies, prints the resulting URL, and is short enough to drop into a repo as nodetonet.py, nodetonet.mjs, and so on. If you want more context on what you are calling into, start with REST API: your first call and the overview at understanding your API key.

A note on scope: no first-party SDKs exist yet on PyPI, npm, pkg.go.dev, or RubyGems. The REST API is small — one primary resource, four verbs — so the gap between "no SDK" and "a useful SDK" is roughly 20 lines of code. Once an official SDK lands you will be able to pip install nodetonet and get the same shape with retry logic, pagination, and typed errors baked in.

What the API looks like at a glance

Before diving into language examples, here is the shape of the core resource. Every client below maps to these four operations:

VerbPathWhat it doesAuth
POST/api/v1/proxiesCreate a proxy / tunnelBearer token
GET/api/v1/proxiesList your proxiesBearer token
GET/api/v1/proxies/:idInspect one proxyBearer token
DELETE/api/v1/proxies/:idDelete a proxyBearer token

Your Bearer token lives under /tokens in the panel — keep it in an environment variable, never hard-code it. A POST body takes subdomain, target_host, and target_port; the response body gives you back id and url. That is the whole surface area. The full machine-readable spec lives at /openapi.json.

1 · Python

One file, one dependency (requests). Reads the token from an env var so it can be committed safely. Suitable for scripts, Jupyter notebooks, Django apps, or any Python automation pipeline — for example the patterns shown in programmatic tunnel creation in Python.

# nodetonet.py
import os, requests

BASE = "https://nodetonet.com/api/v1"
TOKEN = os.environ["NTN_TOKEN"]
H = {"Authorization": f"Bearer {TOKEN}",
     "Content-Type": "application/json"}

def create_proxy(subdomain, target_port, target_host="127.0.0.1"):
    r = requests.post(f"{BASE}/proxies", json={
        "subdomain": subdomain,
        "target_host": target_host,
        "target_port": target_port,
    }, headers=H, timeout=10)
    r.raise_for_status()
    return r.json()

def delete_proxy(proxy_id):
    r = requests.delete(f"{BASE}/proxies/{proxy_id}", headers=H, timeout=10)
    r.raise_for_status()

if __name__ == "__main__":
    p = create_proxy("alice-dev", 3000)
    print(p["url"])

That is a functional Python client. Use it as-is, wrap it in a class, or paste it into a Jupyter notebook for one-off integrations. The raise_for_status() call surfaces errors immediately rather than silently swallowing a 4xx.

2 · Node.js

Zero npm dependencies — uses Node 18+ built-in fetch. Drop into a project as nodetonet.mjs. Works equally well in a serverless function, a build script, or a Next.js API route during local development.

// nodetonet.mjs
const BASE  = 'https://nodetonet.com/api/v1';
const TOKEN = process.env.NTN_TOKEN;

async function api(path, opts = {}) {
  const res = await fetch(BASE + path, {
    ...opts,
    headers: {
      Authorization: 'Bearer ' + TOKEN,
      'Content-Type': 'application/json',
      ...(opts.headers || {}),
    },
  });
  if (!res.ok) throw new Error(res.status + ' ' + (await res.text()));
  return res.json();
}

export const createProxy = (subdomain, port, host = '127.0.0.1') =>
  api('/proxies', { method: 'POST', body: JSON.stringify({
    subdomain, target_host: host, target_port: port,
  })});

export const deleteProxy = (id) =>
  api('/proxies/' + id, { method: 'DELETE' });

const p = await createProxy('alice-dev', 3000);
console.log(p.url);

3 · Go

Standard library only — no third-party packages needed. Pair it with a long-running daemon or a one-shot CLI. The struct tags mirror the JSON response shape, so unmarshalling is direct.

// nodetonet.go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

type Proxy struct {
    ID  string `json:"id"`
    URL string `json:"url"`
}

func CreateProxy(sub string, port int) (*Proxy, error) {
    body, _ := json.Marshal(map[string]interface{}{
        "subdomain": sub, "target_host": "127.0.0.1", "target_port": port,
    })
    req, _ := http.NewRequest("POST",
        "https://nodetonet.com/api/v1/proxies", bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("NTN_TOKEN"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    if err != nil { return nil, err }
    defer res.Body.Close()
    if res.StatusCode >= 300 {
        return nil, fmt.Errorf("status %d", res.StatusCode)
    }
    p := &Proxy{}
    return p, json.NewDecoder(res.Body).Decode(p)
}

func main() {
    p, _ := CreateProxy("alice-dev", 3000)
    fmt.Println(p.URL)
}

That is the whole Go client — no go.mod beyond module nodetonet. The idiomatic Go approach pairs well with context.WithTimeout if you need deadline propagation in a larger service.

4 · Ruby

Standard library again — uses net/http and json. Drop into a Rails app or a Sinatra script without adding a gem dependency.

# nodetonet.rb
require 'net/http'
require 'json'
require 'uri'

TOKEN = ENV.fetch('NTN_TOKEN')

def create_proxy(subdomain, target_port, target_host: '127.0.0.1')
  uri = URI('https://nodetonet.com/api/v1/proxies')
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  req = Net::HTTP::Post.new(uri)
  req['Authorization'] = "Bearer #{TOKEN}"
  req['Content-Type']  = 'application/json'
  req.body = {
    subdomain: subdomain,
    target_host: target_host,
    target_port: target_port,
  }.to_json
  res = http.request(req)
  raise "HTTP #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
  JSON.parse(res.body)
end

if __FILE__ == $PROGRAM_NAME
  puts create_proxy('alice-dev', 3000)['url']
end

5 · Error handling that scales

The DIY clients above surface errors on a non-2xx, but they do not retry. Once you start using them in production, wrap the call in a retry with exponential backoff: 409 means the subdomain is already taken (regenerate), 429 means rate-limited (back off), 5xx is transient (retry up to three times). Treat 401 as a permanent failure — your token is wrong or revoked.

# Python — retry helper
import time

def create_with_retry(sub, port, attempts=3):
    for i in range(attempts):
        try:
            return create_proxy(sub, port)
        except requests.HTTPError as e:
            code = e.response.status_code
            if code == 409:
                sub = f"{sub}-{int(time.time()) % 1000}"
            elif code in (429, 500, 502, 503, 504):
                time.sleep(2 ** i)
            else:
                raise
    raise RuntimeError("gave up after retries")

For a full worked example of production-grade error handling alongside tunnel lifecycle management, see programmatic tunnel creation in Python. For operational tips on keeping proxies healthy in automation, see monitoring your tunnel health.

6 · Generating a typed client from the OpenAPI spec

If you need a language not covered above — Java, C#, Swift, Kotlin, Rust, PHP — use openapi-generator against the spec we publish at /openapi.json. The generator produces a complete typed client with models, request builders, and basic error handling:

npx @openapitools/openapi-generator-cli generate   -i https://nodetonet.com/openapi.json   -g python   -o ./nodetonet-client

Swap python for any of the generator's supported targets. The generated code is verbose but correct, and gives you IDE autocomplete and request-shape validation while you wait for the official SDK.

7 · Official SDKs are on the roadmap

The REST API is, and will remain, the canonical interface. SDKs are conveniences on top: they handle retries, pagination, structured errors, and let your IDE autocomplete the request shape. We are shipping them in this order:

Migration from the DIY wrappers above to the official SDKs will be a one-line import swap — the function names and field names are intentionally aligned. See the changelog and the roadmap to track progress.

Related resources

Frequently asked questions

Why does Nodetonet ship a REST API before official SDKs?
A REST API serves every language at once. Officially-supported SDKs each cover one language and require dedicated maintenance per release cycle. By shipping the API first we unblock all users immediately; SDKs then layer on top in order of demand. Python and Node.js lead the queue for Q3 2026.
Can I generate a typed client from the OpenAPI spec today?
Yes. Run openapi-generator generate -i https://nodetonet.com/openapi.json -g python -o ./client (swap python for any supported language). The generated client is verbose but correct — it gives you autocomplete and request-shape validation while you wait for the official SDK.
Will migrating from DIY examples to the official SDK break my code?
No. The function names (create_proxy, delete_proxy, list_proxies) and field names are intentionally aligned with the REST shape, so migration will mostly be a one-line import swap. The official SDK adds retries, pagination iterators, and typed error classes — none of which break existing call sites.
Where do I find my API token?
Under /tokens in your panel. Treat it like a password: store it in an environment variable (never in source control), rotate it if you think it was exposed, and create separate tokens for separate applications so you can revoke one without affecting the others. See understanding your API key for full security guidance.
Which resource types can I manage through the API?
The primary resource today is proxies — the same objects that back HTTP tunnels and mobile proxy endpoints. You can create, list, inspect, and delete them. Device management, token groups and billing sit in the panel UI for now; the API surface will expand as we ship new versions.
Do the SDK examples work with rotating and sticky proxies?
Yes — the API creates the proxy endpoint, and rotating vs sticky is controlled by a username modifier at connection time, not at creation time. Append -session-XXXX to the proxy username for a sticky session. See sticky session and rotating proxy in the glossary for full details.

Build your own SDK in 20 lines

Grab a token from /tokens and paste any of the examples above. First tunnel takes 60 seconds.