Skip to main content

nodedata — Python SDK

Official Python client for the Node Data API: search and download robotics/physical-AI models and datasets, publish your own, read your payouts, subscribe to webhooks, and run Node Data's paid inference.

Zero runtime dependencies. Standard library only, so it installs onto a Jetson next to whatever pinned torch/numpy stack is already there.

pip install nodedata
pip install -e ".[dev]"       # from this directory, for development

PyPI

Requires Python 3.9+.

Quick start

Create a key at /dashboard/api-keys (nd_test_… or nd_live_…) and export it:

export NODE_DATA_API_KEY=nd_live_...
from nodedata import NodeData

nd = NodeData()                        # reads NODE_DATA_API_KEY

me = nd.me()
print(me.name, me.key.mode, me.key.scopes)

# Search the marketplace
for listing in nd.models.iter_all(q="grasp", type="dataset", max_items=50):
    print(listing.slug, listing.price.dollars, listing.url)

# Download something you own or that's free
path = nd.models.download("acme-panda-grasp-100k", "./cache")

# Publish a build artifact — uploads the file, then creates the listing
listing = nd.models.publish(
    "dist/grasp-policy-v2.onnx",
    title="Grasp policy v2",
    description="Trained on 100k teleop episodes.",
    type="policy",
    price_cents=4900,                  # 0 for free; paid minimum is 100
    frameworks=["pytorch"],
)
print(listing.url)

What's covered

Area Calls
Account nd.me()
Listings nd.models.list() · iter_all() · retrieve() · create() · update() · unpublish()
Files nd.models.download() · download_url() · nd.uploads.upload_file() · create() · confirm() · rules()
Publish nd.models.publish() (upload + create in one call)
Payouts nd.payouts.retrieve()
Usage nd.usage.retrieve(days=30)
Webhooks nd.webhooks.list() · create() · retrieve() · update() · delete() · deliveries() · event_types()
Inference nd.inference.models() · chat() · stream() · stream_text() · ask()
Anything newer nd.request("GET", "/some/new/endpoint")

nd.datasets is an alias of nd.models — one endpoint serves both.

Every returned object keeps the raw response in .raw, so a field the API adds after this release is still readable without upgrading.

Pagination

list() returns one Page; iter_all() walks every page lazily.

page = nd.models.list(limit=100)
print(len(page), page.has_more, page.next_cursor)

for listing in nd.models.iter_all(type="dataset"):   # follows cursors
    ...

Inference

Requires a premium key with the inference:run scope. The endpoint is OpenAI-compatible, so openai pointed at https://www.nodedata.ai/api/v1 works too — these helpers just avoid the dependency.

for model in nd.inference.models():
    print(model.id, model.context_window, model.pricing.input_per_1m)

print(nd.inference.ask("Summarise this dataset card.", model="node-reason-1"))

for text in nd.inference.stream_text(
    model="node-reason-1",
    messages=[{"role": "user", "content": "Explain grasp policies"}],
):
    print(text, end="", flush=True)

The final streamed chunk carries usage and no text — that's the frame to log spend against.

Webhooks

Verify with the raw request body. Re-serialising parsed JSON changes bytes, and the signature won't match.

from nodedata import verify_webhook, WebhookVerificationError

endpoint = nd.webhooks.create(
    "https://example.com/hooks/nodedata",
    events=["listing.purchased", "payout.paid"],
)
print(endpoint.secret)   # returned on create only — store it now

# in your handler
try:
    event = verify_webhook(request.body, request.headers["nd-signature"], SECRET)
except WebhookVerificationError:
    return 400

verify_webhook enforces HMAC-SHA256 with a constant-time compare and a 300s replay window, matching the server.

Errors

Everything raises a subclass of NodeDataError:

Exception Status Typical cause
InvalidRequestError 400 validation failed
AuthenticationError 401 missing, revoked or expired key
PaymentRequiredError 402 premium_required, purchase_required, unpaid key
PermissionDeniedError 403 key lacks the scope
NotFoundError 404 no such object — or not yours
RateLimitError 429 carries retry_after
MaintenanceError 503 platform deliberately closed; carries retry_after
ServerError 5xx API failure
APIConnectionError / APITimeoutError never reached the API

Branch on exc.code (purchase_required, scope_required, price_too_low, …) rather than the message text.

from nodedata import PaymentRequiredError

try:
    nd.models.download("some-paid-asset", "./cache")
except PaymentRequiredError as exc:
    if exc.code == "purchase_required":
        print(f"costs ${exc.body['price_cents'] / 100:.2f}")

Retries

Rate limits and transient failures are retried twice by default with jittered backoff, honouring Retry-After. POST is only retried on a 429 — the server rejected it before doing any work — so a publish can never double-apply.

nd = NodeData(timeout=30, max_retries=5)

CLI

Installing the package also installs a nodedata command:

nodedata whoami
nodedata search grasp --type dataset
nodedata download acme-panda-grasp-100k -o ./cache
nodedata publish dist/policy.onnx --title "Grasp policy" --description "..." --type policy
nodedata payouts
nodedata usage --days 7
nodedata ask "Explain grasp policies" --model node-reason-1

Configuration

Env var Purpose
NODE_DATA_API_KEY API key used when none is passed
NODE_DATA_BASE_URL Override the API base URL (preview deploys, self-host)

Certificates

Because this SDK uses urllib rather than bundling certifi, TLS trust comes from the system store. Some Python builds — notably the macOS python.org installers — ship an empty one, which fails every HTTPS request with CERTIFICATE_VERIFY_FAILED. Three fixes, in order of ease:

pip install certifi                              # used automatically if present
open "/Applications/Python 3.x/Install Certificates.command"
import ssl
nd = NodeData(ssl_context=ssl.create_default_context(cafile="/path/to/ca.pem"))

The SDK detects this specific failure and says so, rather than reporting it as an API outage.

Tests

python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest                      # hermetic; runs a local HTTP server
NODE_DATA_LIVE_KEY=nd_live_... .venv/bin/python -m pytest tests/test_live.py -v

The suite talks to a real socket rather than a patched transport, so retries, SSE framing and streamed downloads are exercised as they run in production. The live suite is read-only.

Versioning

Minor releases may add response fields. Pin in CI and bump deliberately.

MIT © Node, Inc.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nodedata-0.1.1.tar.gz (37.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nodedata-0.1.1-py3-none-any.whl (33.9 kB view details)

Uploaded Python 3

File details

Details for the file nodedata-0.1.1.tar.gz.

File metadata

  • Download URL: nodedata-0.1.1.tar.gz
  • Upload date:
  • Size: 37.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for nodedata-0.1.1.tar.gz
Algorithm Hash digest
SHA256 0976ddf2987b1c1430e0615c60019c20a5aa455a6c25323118788b77b3b86d51
MD5 ffc705d7e06d3d852e137ffbe7ebf98d
BLAKE2b-256 2a7154da2758c5dfdf6c3f7589c2c3ebfe5862895aac00ab07e2ba700e88b379

See more details on using hashes here.

File details

Details for the file nodedata-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: nodedata-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 33.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for nodedata-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9c816f84b049ae33cdd0d70de3556b5d4627c9acffa9cd48d7ecaa3e1ba6d5cb
MD5 abf02a5f91c7ecf89690ab547e40d6a0
BLAKE2b-256 8f0c02c6c9447f98f34aa0e833587238ec4b3b8874362f51ef2ab758822e9156

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page