Skip to main content

Python client for the Neudata Developer API with automatic retries and rate-limit backoff.

Project description

neudata-api-client

A Python client for the Neudata Developer API. It lets you search and retrieve dataset metadata, additional datasets, filters, and DDQs — and ships with resilient defaults: it retries dropped connections, backs off and honours Retry-After on rate limits (429), and auto-paginates list endpoints.

Installation

pip install neudata-api-client

For development (using uv):

git clone https://github.com/neudata/neudata-api-client
cd neudata-api-client
uv sync

Authentication

The API authenticates with two headers, Email and Api-Token. Your token is available at https://www.neudata.co/users/edit.

Provide them via environment variables (recommended):

export NEUDATA_EMAIL="you@example.com"
export NEUDATA_API_TOKEN="your-api-token"

…or pass them directly to the client:

from neudata import NeudataClient

client = NeudataClient(email="you@example.com", api_token="your-api-token")

A .env.example is included as a template.

Quickstart

from neudata import NeudataClient

with NeudataClient() as client:
    # Search a single page of datasets
    results = client.search_datasets(q="satellite", per_page=10)

    # Or iterate over *every* matching dataset (pagination handled for you)
    for dataset in client.iter_datasets(equity_region=["uk", "europe"]):
        print(dataset["id"], dataset["title"])

    # Fetch the full detail record for one dataset
    detail = client.get_dataset(1234)

API reference

Method Endpoint Description
search_datasets(**filters) GET /datasets One page of dataset search results
iter_datasets(per_page=99, **filters) GET /datasets Iterate all datasets across pages
get_dataset(id) GET /datasets/{id} Full dataset detail
list_filters() GET /filters Available filter parameter names
get_filter_options(name) GET /filters/{name} Allowable options for a filter
search_additional_datasets(**filters) GET /additional-datasets One page of additional datasets
iter_additional_datasets(per_page=99, **filters) GET /additional-datasets Iterate all additional datasets
get_additional_dataset(id) GET /additional-datasets/{id} Full additional-dataset detail
list_ddqs(page, per_page) GET /ddqs List DDQs (Sentry subscribers)
iter_ddqs(per_page=99) GET /ddqs Iterate all DDQs
get_ddq(id) GET /ddqs/{id} DDQ detail + 10-minute download URL

Filters

Search methods accept the documented query parameters as keyword arguments, e.g. q, page, per_page, sort, sort_by, source, from_date, data_provider_id, and the array filters equity_region, asset_class, combined_dataset_types, frequency, history, subscription_price, report_type, feed_type, output_format, esg_topics, filter_labels, ticker_indices, and more.

Array filters are passed as Python lists and serialized into the repeated name[] form the API expects:

client.search_datasets(asset_class=["public-equity", "fixed-income"])
# -> GET /datasets?asset_class[]=public-equity&asset_class[]=fixed-income

Use client.list_filters() and client.get_filter_options(name) to discover the valid values for each filter at runtime.

Resilience: retries, backoff & rate limits

The client is configured on construction:

NeudataClient(
    timeout=30,                  # per-request timeout (seconds)
    max_retries=5,               # retries for dropped connections / 5xx
    backoff_factor=0.5,          # exponential backoff base
    max_backoff=60,              # cap on any single backoff sleep
    max_rate_limit_retries=10,   # retries specifically for 429 responses
    requests_per_minute=90,      # client-side throttle (0 disables it)
)
  • Dropped/closed connections (and timeouts and 5xx server errors) are retried up to max_retries times with jittered exponential backoff.
  • 429 rate limits are retried up to max_rate_limit_retries times. The Retry-After header is honoured when present; otherwise exponential backoff is used. When retries are exhausted a RateLimitError is raised.
  • A built-in client-side throttle keeps the sustained request rate below requests_per_minute (the API guideline is ~100/min) so bulk jobs avoid tripping the limiter in the first place.

Enable logging to see retry/backoff activity:

import logging
logging.getLogger("neudata").setLevel(logging.INFO)

Exceptions

All exceptions derive from neudata.NeudataError:

  • AuthenticationError401/403 (bad credentials; not retried)
  • NotFoundError404
  • RateLimitError429 retries exhausted (carries retry_after)
  • NeudataAPIError — other unexpected API responses (carries status_code, response_body)

Example: download the whole catalogue

A console script is installed with the package:

# Dump all datasets + additional datasets to neudata_export.json
neudata-download

# Custom output, only datasets, with full per-item detail records
neudata-download --output datasets.json --datasets-only --details

# Filter by date or free text
neudata-download --from-date 2026-01-01 --query "credit card"

Run neudata-download --help for all options. A minimal, readable version using the library directly is in examples/download_all.py:

python examples/download_all.py out.json

The output JSON has the shape:

{
  "datasets": [ ... ],
  "additional_datasets": [ ... ]
}

Development

uv sync             # create the venv and install deps + dev tools
uv run pytest       # run the test suite (no network calls)

Tests use responses to mock the API and a monkeypatched sleep, so they run instantly and offline.

There is also an opt-in live smoke test that hits every endpoint against the real API. It is excluded from the default run and requires credentials:

export NEUDATA_EMAIL="you@example.com"
export NEUDATA_API_TOKEN="your-api-token"
uv run pytest -m smoke -v      # hits the real Neudata API

(The DDQ checks skip automatically if your account isn't a Sentry subscriber.)

Releasing to PyPI

uv build                          # build sdist + wheel into dist/
uvx twine check dist/*            # validate metadata / long description

# Test upload first
uv publish --publish-url https://test.pypi.org/legacy/ --token "$TEST_PYPI_TOKEN"

# Then the real thing
uv publish --token "$PYPI_TOKEN"

License

MIT

Project details


Download files

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

Source Distribution

neudata_api_client-0.1.0.tar.gz (11.4 kB view details)

Uploaded Source

Built Distribution

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

neudata_api_client-0.1.0-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file neudata_api_client-0.1.0.tar.gz.

File metadata

  • Download URL: neudata_api_client-0.1.0.tar.gz
  • Upload date:
  • Size: 11.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.2

File hashes

Hashes for neudata_api_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fe8c7f1a8f8d78178a1dc091537472674d5a9b9e94c4fa1f51e69464bc730b66
MD5 ed628742b9f46a0c046e6d0916cfc504
BLAKE2b-256 085d58242b908631faa2353dab4bd09f0e3122b425c1f4e6008ad4fca16b49c8

See more details on using hashes here.

File details

Details for the file neudata_api_client-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for neudata_api_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6ad141376f9a2e3f4817cdfb00f0b8b2a586f47d44ee00743f858f3c3a01289f
MD5 29c19d24c114c158472c0d50fa3cb076
BLAKE2b-256 40f77af045856b5e0bc092168b52fb835df41be1b15720df23e58154f29a53dd

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