Skip to main content

Synthefy Python Client

Branch Status
dev Tests
main Tests

A Python client for the Synthefy API. It provides time series forecasting (synchronous and asynchronous) and tabular in-context regression via SynthefyNoriClient — which runs against the hosted endpoint, a named AWS SageMaker endpoint, or fully locally — with an easy-to-use interface, full type hints, and pydantic validation.

Features

  • Tabular In-Context Regression: SynthefyNoriClient predicts from labeled context rows in a single forward pass — hosted on Baseten or SageMaker, or fully local, no training step
  • Free Prediction Intervals: the same forward pass carries a full predictive distribution, so output_type="quantiles" returns calibrated bands at no extra cost
  • Sync & Async Support: Separate clients for synchronous and asynchronous operations
  • Professional Error Handling: Comprehensive exception hierarchy with detailed error messages
  • Retry Logic: Built-in exponential backoff for transient errors (rate limits, server errors)
  • Context Managers: Automatic resource cleanup with with and async with statements
  • Pandas Integration: Built-in support for pandas DataFrames
  • Type Safety: Full type hints and Pydantic validation

Installation

pip install synthefy

For optional fully-local tabular inference (no API key, runs in-process), install the extra:

pip install "synthefy[local]"

For signed invocation of your own Amazon SageMaker endpoint, install the AWS extra:

pip install "synthefy[aws]"

Quick Start

Basic Usage

from synthefy import SynthefyAPIClient, SynthefyAsyncAPIClient
import pandas as pd

# Synchronous client
with SynthefyAPIClient(api_key="your_api_key_here") as client:
    # Make requests...
    pass

# Asynchronous client
async with SynthefyAsyncAPIClient() as client:  # Uses SYNTHEFY_API_KEY env var
    # Make async requests...
    pass

Making a Forecast Request

from synthefy import SynthefyAPIClient
import pandas as pd
import numpy as np

# Create sample data with numeric metadata
history_data = {
    'date': pd.date_range('2024-01-01', periods=100, freq='D'),
    'sales': np.random.normal(100, 10, 100),
    'store_id': 1,
    'category_id': 101,
    'promotion_active': 0
}

target_data = {
    'date': pd.date_range('2024-04-11', periods=30, freq='D'),
    'sales': np.nan,  # Values to forecast
    'store_id': 1,
    'category_id': 101,
    'promotion_active': 1  # Promotion active in forecast period
}

history_df = pd.DataFrame(history_data)
target_df = pd.DataFrame(target_data)

# Synchronous forecast
with SynthefyAPIClient() as client:
    forecast_dfs = client.forecast_dfs(
        history_dfs=[history_df],
        target_dfs=[target_df],
        target_col='sales',
        timestamp_col='date',
        metadata_cols=['store_id', 'category_id', 'promotion_active'],
        leak_cols=[],
        model='sfm-moe-v1'
    )

# Result is a list of DataFrames with forecasts
forecast_df = forecast_dfs[0]
print(forecast_df[['timestamps', 'sales']].head())

Asynchronous Usage

import asyncio
from synthefy.api_client import SynthefyAsyncAPIClient

async def main():
    async with SynthefyAsyncAPIClient() as client:
        # Single async forecast
        forecast_dfs = await client.forecast_dfs(
            history_dfs=[history_df],
            target_dfs=[target_df],
            target_col='sales',
            timestamp_col='date',
            metadata_cols=['store_id', 'category_id', 'promotion_active'],
            leak_cols=[],
            model='sfm-moe-v1'
        )

        # Concurrent forecasts for multiple datasets
        tasks = []
        for i in range(3):
            # Create variations of your data
            modified_history = history_df.copy()
            modified_target = target_df.copy()
            modified_history['store_id'] = i + 1
            modified_target['store_id'] = i + 1

            task = client.forecast_dfs(
                history_dfs=[modified_history],
                target_dfs=[modified_target],
                target_col='sales',
                timestamp_col='date',
                metadata_cols=['store_id', 'category_id', 'promotion_active'],
                leak_cols=[],
                model='sfm-moe-v1'
            )
            tasks.append(task)

        # Execute all forecasts concurrently
        results = await asyncio.gather(*tasks)

        for i, forecast_dfs in enumerate(results):
            print(f"Forecast for store {i+1}: {len(forecast_dfs[0])} predictions")

# Run the async function
asyncio.run(main())

Backtesting

import asyncio
import pandas as pd
import numpy as np
from synthefy.data_models import ForecastV2Request
from synthefy.api_client import SynthefyAsyncAPIClient

async def main():

    # Create sample time series data
    dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
    data = {
        'date': dates,
        'sales': np.random.normal(100, 10, len(dates)),
        'store_id': 1,
        'category_id': 101,
        'promotion_active': np.random.choice([0, 1], len(dates), p=[0.7, 0.3])
    }
    df = pd.DataFrame(data)

    print(f"Created dataset with {len(df)} rows from {df['date'].min()} to {df['date'].max()}")

    # Use from_dfs_pre_split for backtesting with date-based windows
    request = ForecastV2Request.from_dfs_pre_split(
        dfs=[df],
        timestamp_col='date',
        target_cols=['sales'],
        model='sfm-moe-v1',
        cutoff_date='2023-06-01',  # Start backtesting from June 1st
        forecast_window='7D',      # 7-day forecast windows
        stride='14D',              # Move forward 14 days between windows
        metadata_cols=['store_id', 'category_id', 'promotion_active'],
        leak_cols=['promotion_active']  # Promotion data may leak into target
    )

    print(f"Created {len(request.samples)} forecast windows for backtesting")
    print("Window details:")
    for i, sample in enumerate(request.samples):
        history_start = sample[0].history_timestamps[0]
        history_end = sample[0].history_timestamps[-1]
        target_start = sample[0].target_timestamps[0]
        target_end = sample[0].target_timestamps[-1]
        print(f"  Window {i+1}: History {history_start} to {history_end}, Target {target_start} to {target_end}")

    # Make async forecast request
    async with SynthefyAsyncAPIClient() as client:
        response = await client.forecast(request)

        print(f"\nBacktesting completed with {len(response.samples)} forecast windows")

        # Process results for each window
        for i, sample in enumerate(response.samples):
            print(f"Window {i+1}: {len(sample.history_timestamps)} history points, "
                f"{len(sample.target_timestamps)} target points")

            # Access forecast values
            if hasattr(sample, 'forecast_values') and sample.forecast_values:
                print(f"  Forecast values: {sample.forecast_values[:3]}...")  # First 3 values
asyncio.run(main())

Advanced Configuration

from synthefy import SynthefyAPIClient
from synthefy.api_client import BadRequestError, RateLimitError

# Client with custom configuration
with SynthefyAPIClient(
    api_key="your_key",
    timeout=600.0,  # 10 minutes
    max_retries=3,
    organization="your_org_id",
    base_url="https://custom.synthefy.com"  # For enterprise customers
) as client:
    try:
        # Per-request configuration
        forecast_dfs = client.forecast_dfs(
            history_dfs=[history_df],
            target_dfs=[target_df],
            target_col='sales',
            timestamp_col='date',
            metadata_cols=['store_id'],
            leak_cols=[],
            model='sfm-moe-v1',
            timeout=120.0,  # Override client timeout for this request
            idempotency_key="unique-request-id",  # Prevent duplicate processing
            extra_headers={"X-Custom-Header": "value"}
        )
    except BadRequestError as e:
        print(f"Invalid request: {e}")
        print(f"Status code: {e.status_code}")
        print(f"Request ID: {e.request_id}")
    except RateLimitError as e:
        print(f"Rate limited: {e}")
        # Client automatically retries with exponential backoff
    except Exception as e:
        print(f"Unexpected error: {e}")

Nori — Tabular In-Context Regression

SynthefyNoriClient is a standalone client for Synthefy Nori, an in-context learning regressor. Each call supplies labeled context rows (X_train, y_train) and query rows (X_test); the model returns one predicted value per query row in a single forward pass — there is no training step.

It is independent of the forecasting client above (different model, different endpoint, different credential) but is exported from the same package. A single SynthefyNoriClient runs predictions against the hosted endpoint, a named AWS SageMaker endpoint, or locally, selected with the mode argument ("remote" (default), "aws", "local", or "auto").

Use it from your AI coding assistant

Paste this into Claude Code, Cursor, or any AI coding assistant and it will wire Nori into your own project:

Look at my code/task/report here and figure out where Nori would best fit — it's
Synthefy's tabular foundation model for regression, used through the `synthefy`
client with no training loop and no hyperparameters. It runs fully on your own
machine (local mode, uses your GPU when one's available), or against the hosted
Synthefy API if you'd rather not run it locally.

1. Install it with this project's package manager, with the local extra
   (e.g. `uv add "synthefy[local]"`, or `pip install -U "synthefy[local]"`).

2. Use it wherever a tabular regression / prediction step fits:

   ```python
   from synthefy import SynthefyNoriClient

   # model is required -- name a size: "nori-30m" (~29.2M) or "nori-6m" (~6M base).
   client = SynthefyNoriClient(mode="local", model="nori-30m")   # runs on this machine, no API key

   y_pred = client.predict(
       X_train=X_train,   # lists, numpy arrays, or pandas — NaNs OK, imputed for you
       y_train=y_train,   # continuous target
       X_test=X_test,     # rows to score
   )                      # -> list of floats, one per X_test row (as_pandas=True for a Series)

   # Prediction intervals come free — no conformal/quantile add-ons:
   lo, mid, hi = client.predict(X_train, y_train, X_test,
                                output_type="quantiles", quantiles=[0.1, 0.5, 0.9])
   ```

X is a numeric feature matrix (or a pandas DataFrame — non-numeric columns are
encoded for you); y is a continuous target. If I already have a model, wire Nori
up alongside it on the same train/test split and metric so I can compare them. If
the best place to plug Nori in isn't obvious, show me where you'd put it and
confirm with me before making changes.

Prefer not to run it locally? Use the hosted API instead — create a key at
https://docs.synthefy.com/setup/api_key, then:
`client = SynthefyNoriClient(api_key="YOUR_API_KEY", model="nori-30m")` (or set
SYNTHEFY_NORI_API_KEY).

Hosted Usage (mode="remote")

from synthefy import SynthefyNoriClient

# The key is sent as `Authorization: Bearer <key>` (gateway default).
# Pass it explicitly or set the SYNTHEFY_NORI_API_KEY environment variable.
client = SynthefyNoriClient(api_key="your_api_key", model="nori-30m")

predictions = client.predict(
    X_train=[[0.0, 1.0], [1.0, 0.0], [1.0, 1.0]],  # context features
    y_train=[1.0, 1.0, 2.0],                        # context targets
    X_test=[[2.0, 2.0], [0.5, 0.5]],                # query features
)
print(predictions)  # -> [<float>, <float>]  (one per X_test row)

X_train, y_train, and X_test accept Python lists, numpy arrays, or pandas objects (a DataFrame for the feature matrices; a Series or single-column DataFrame for y_train). When both X_train and X_test are DataFrames, non-numeric columns are encoded for you — fit on X_train and applied to X_test — so you can pass raw categorical columns directly:

import pandas as pd

X_train = pd.DataFrame({"price": [9.99, 4.50, 7.25], "region": ["NW", "SE", "NW"]})
y_train = pd.Series([120.0, 305.0, 180.0])
X_test  = pd.DataFrame({"region": ["SE"], "price": [5.00]})  # order need not match

predictions = client.predict(X_train, y_train, X_test)  # 'region' is encoded

By default each categorical column becomes a single column of ordinal codes (categories from X_train in sorted order — the model's own server-side convention): a value seen only in X_test maps to -1, and a missing value (NaN) stays NaN for server-side imputation. Pass categorical_encoding="onehot" for the previous one-hot behavior (indicator columns per category; missing values get their own indicator; unseen values map to an all-zeros group). Datetime columns and categorical columns with more than max_categorical_cardinality (default 100) distinct training values are dropped with a warning; timedelta columns are unsupported and raise (convert them to a number or string first). Numeric columns (including bool) pass through unchanged, with NaN imputed server-side. Any object-dtype column is treated as categorical (including numeric-looking strings such as IDs or zip codes, and object date values) — cast genuine numeric columns to a numeric dtype if you want them kept as magnitudes. (Plain lists/numpy arrays must already be numeric — encoding needs column names.)

For raw text columns, install pip install "synthefy[text]" and name them with text_columns=. The client embeds those columns and optionally reduces them with SVD before sending the resulting numeric matrix, so this works in both local and remote modes:

predictions = client.predict(
    X_train,
    y_train,
    X_test,
    text_columns=["review"],
    svd_dim=128,
)

Text embedding always happens on the client machine. By default, text_device="auto" uses CUDA/ROCm when available, then Apple MPS, and falls back to CPU. Pass text_device="cpu" (or another PyTorch device such as "cuda:1") to override automatic selection. The remote service receives only the widened numeric features; remote mode does not move the sentence encoder to the server.

Shapes are validated client-side: X_train and y_train must have the same number of rows, and X_test must have the same number of features as X_train. When both X_train and X_test are DataFrames, X_test is aligned to X_train's columns by name (so column order is irrelevant), and a mismatch in the column sets raises. Missing values (NaN) are allowed — you don't need to fill them in beforehand; the model imputes them server-side.

predict returns a plain list[float] by default. Pass as_pandas=True to get a pandas Series instead — one value per X_test row, named after y_train and indexed by X_test's index (when X_test is a DataFrame), so predictions join straight back:

preds = client.predict(X_train, y_train, X_test, as_pandas=True)
# preds is a pd.Series named after y_train, sharing X_test's index

The client targets the Baseten inference gateway (https://inference.baseten.co/predict); model= is required and names a size — "nori-30m" (→ synthefy/nori-30m) or "nori-6m" (→ synthefy/nori-6m). The gateway resolves that slug to a deployment, so you never name a deployment yourself.

timeout and max_retries are also configurable on the constructor.

Authentication

  • The only credential is your Synthefy Nori API key, created in the Synthefy Console. It authenticates against the Baseten-hosted gateway, but you do not need a Baseten account.
  • Provide it via the api_key argument or the SYNTHEFY_NORI_API_KEY environment variable. It is sent as the header Authorization: Bearer <key>, which is what the gateway requires.

Errors

The Nori client reuses the package's exception hierarchy:

  • HTTP 400BadRequestError, carrying the server's error string as the message (e.g. a missing field or unsupported task).
  • HTTP 401AuthenticationError (bad or missing key).
  • Transient errors (timeouts, connection errors, 429, 5xx) are retried with exponential backoff, then surface as RateLimitError / InternalServerError / APITimeoutError / APIConnectionError.

Amazon SageMaker Usage (mode="sagemaker")

Install the optional AWS transport and invoke a named real-time endpoint:

pip install "synthefy[aws]"
from synthefy import SynthefyNoriClient

client = SynthefyNoriClient(
    mode="sagemaker",
    model="nori-30m",
    endpoint_name="nori-30m-prod",
    region_name="us-east-1",
)
predictions = client.predict(
    X_train=[[0.0], [1.0]],
    y_train=[0.0, 1.0],
    X_test=[[2.0]],
)

The client creates an argument-free boto3.Session() and therefore uses boto3's standard credential chain: environment/shared config, web identity (including GitHub OIDC), container or instance roles, and SSO profiles. It does not accept AWS access keys. model= and endpoint_name= are required: the endpoint selects the deployed model specification, while the request model is checked against it so a routing mistake fails closed. auto mode never selects SageMaker.

SageMaker's request is the same Nori JSON contract used by the hosted transport, sent through InvokeEndpointWithResponseStream with application/json for all three models. The server emits 15-second heartbeat chunks and one final JSON result, which the client buffers into the normal predict() return value. This lets large 30M requests use SageMaker's streaming processing window (up to eight minutes) instead of the regular invocation's 60-second limit. Container errors retain their original status/message through the normal Synthefy exception hierarchy; AWS credential, signing, region, quota, and throttling errors remain native AWS SDK exceptions. The constructor timeout is SageMaker's per-read inactivity timeout, not a total stream deadline. Set timeout/retries on the constructor. HTTP-only extra_headers= are rejected for SageMaker. Per-call timeout= is ignored with a warning.

Streaming does not increase AWS Marketplace's 25,000,000-byte SageMaker endpoint request-body limit. The client checks the final encoded JSON before invoking the endpoint. It does not split oversized tables because every query must use the same complete in-context training set, so splitting can change the prediction. The planned large-input path is an explicit S3-backed SageMaker Asynchronous Inference API rather than a silent fallback; AWS documents payloads up to 1 GB and processing up to one hour for that service.

Local Usage (mode="local", Optional, No Network)

The same prediction can run locally — no network call and no API key — via the optional synthefy-nori package. Install the extra:

pip install "synthefy[local]"

The local extra uses synthefy-nori>=0.13.1, which makes recoverable SVD fallbacks visible while supporting Python >= 3.9, the same floor as the base package.

from synthefy import SynthefyNoriClient

client = SynthefyNoriClient(mode="local", model="nori-30m")  # no API key needed
predictions = client.predict(
    X_train=[[0.0, 1.0], [1.0, 0.0], [1.0, 1.0]],
    y_train=[1.0, 1.0, 2.0],
    X_test=[[2.0, 2.0]],
)

predict has the same signature in every mode. The synthefy-nori dependency is imported lazily on first use; if it is not installed, a clear ImportError is raised telling you to pip install "synthefy[local]".

Local mode also preserves synthefy-nori's degradation warnings and their messages. With synthefy-nori>=0.13.1, an SVD failure warns under SvdFallbackWarning while still returning a prediction. Scored or audited runs can turn that warning into an exception around the client call; the client does not catch, wrap, or rewrite it:

from synthefy_nori import SvdFallbackWarning, strict_pipeline

with strict_pipeline(SvdFallbackWarning):
    predictions = client.predict(X_train, y_train, X_test)

Use mode="auto" to prefer local when synthefy-nori is installed and transparently fall back to the hosted endpoint (which then requires an API key) otherwise:

client = SynthefyNoriClient(api_key="your_api_key", mode="auto", model="nori-30m")
print(client.mode)  # "local" if synthefy-nori is installed, else "remote"

Large Tables and Memory (memory_policy=)

Nori does in-context regression, so your table is input: one prediction keeps a per-layer key/value cache over every context row, and that cache — not the ~6M-parameter model — is what exhausts GPU memory on a big table. memory_policy= decides what to do about it. Omit it and the defaults handle almost every request.

# A preset...
preds = client.predict(X_train, y_train, X_test, memory_policy="exact")        # never quantize
preds = client.predict(X_train, y_train, X_test, memory_policy="max_context")  # fit the largest table

# ...individual fields...
preds = client.predict(X_train, y_train, X_test, memory_policy={"cache_dtype": "int8"})

# ...or the typed model, which ships with the client — no synthefy-nori needed. Validated
# before the request goes out, so a typo or an out-of-range value costs no round trip.
from synthefy import MemoryPolicy
preds = client.predict(X_train, y_train, X_test,
                       memory_policy=MemoryPolicy(cache_dtype="int8", gpu_budget_frac=0.5))

print(client.last_memory_report["rung"])  # e.g. "resident_bf16"

last_memory_report is how you learn what actually happened, and it is worth reading: the fallback chosen depends on the replica's free VRAM at that moment, not on your request, so it is not knowable from your side.

field meaning
rung which fallback served it — resident_bf16resident_int8offload_bf16offload_int8plain_loopno_cache
est_cache_gb / resident_gb the cache's full-precision size, and what stayed in GPU memory
query_chunk query rows per forward pass
dropped_context_rows context rows discarded to fit — the one accuracy loss worth checking, 0 unless subsampling engaged
clamped fields the server capped (host-RAM budgets only)
notes remarks about the policy you sent, e.g. a budget that cannot take effect

Only the int8 rungs trade accuracy, and they are reached only when full precision will not fit. offload_* moves bytes to host RAM rather than approximating, so it is bit-identical to staying resident. Set memory_policy={"allow_subsample": False} to turn a silently shortened context into an error instead.

One field behaves differently over the network: elements_budget. The cache is only built when the query set spans more than one chunk, and at default settings that needs far more query rows than the hosted request-body limit (~64 MiB) allows — so lowering elements_budget is what lets a hosted request reach the cached path at all.

In mode="local" the same argument works, but needs synthefy-nori >= 0.13.0; older builds raise ImportError with an upgrade hint. last_memory_report stays None locally — use NoriRegressor and read memory_report_ if you need it there.

Prediction Intervals (output_type= / quantiles=)

Nori's forward pass produces a whole predictive distribution, not just a point estimate, so prediction intervals cost nothing extra — no conformal wrapper, no separate quantile models:

lo, mid, hi = client.predict(
    X_train, y_train, X_test,
    output_type="quantiles", quantiles=[0.1, 0.5, 0.9],   # an 80% interval
)

output_type selects what comes back. Shared selectors use the same meanings as synthefy-nori's NoriRegressor.predict:

output_type Returns Shape
"mean" (default) distribution mean — optimal for squared error / R² list[float], one per X_test row
"median" distribution median — optimal for MAE list[float]
"quantiles" quantiles at the levels in quantiles= (n_levels, n_query)level-major, so lo, mid, hi = ... unpacks
"full" the whole quantile bank dict with "quantiles" (n_query, K), "taus" (K,), "mean" (n_query,)

quantiles= takes tau levels strictly inside (0, 1); it is required by — and valid only with — output_type="quantiles". The returned rows follow your order, so quantiles=[0.9, 0.1] gives you high-then-low. Values come back in original-y units, sorted to a valid (monotone) quantile function per row.

as_pandas=True returns a DataFrame instead: one row per X_test row (indexed by X_test, so the bands join straight back) and one column per level, named "<target>[<level>]" — the same convention the forecasting client uses:

bands = client.predict(X_train, y_train, X_test, output_type="quantiles",
                       quantiles=[0.1, 0.9], as_pandas=True)
bands.columns   # ['price[0.1]', 'price[0.9]']  (named after y_train)

Use "full" for CRPS / interval scoring and calibration work; the bank is the checkpoint's full quantile head (K = 999 on the default checkpoint), so prefer "quantiles" when you only need a few levels — it keeps the response small.

Capability differs by mode:

  • Local (pip install "synthefy[local]"): every output_type works. Needs synthefy-nori >= 0.6.0 for output_type (the local extra already pins >= 0.10.0, so an extras install is always new enough); an older build raises ImportError with an upgrade hint. "quantiles"/"full" need the default pinball checkpoint — a bar_distribution checkpoint raises NotImplementedError.

  • Remote: needs a hosted deployment that serves distribution output. The server echoes back the output_type it honored, and the client raises rather than accept a mismatch:

    ValueError: The hosted deployment did not serve output_type='median': it omitted
    the output_type field entirely, so it predates distribution output. Such a
    deployment answers with the distribution mean, which is indistinguishable from a
    real 'median' result, so this is raised rather than returning means as if they
    were what you asked for. Use local mode (pip install "synthefy[local]", then
    mode="local"), or point base_url/endpoint at a deployment that serves
    distribution output.
    

    That handshake is the point: a deployment that ignores output_type answers with means, which look exactly like a valid "median" result — so silence here would be a confidently wrong answer, not a missing feature.

output_type/quantiles= cannot be combined with discretize= / categorical_levels= (below): discrete labels and a distribution summary are different answers, so asking for both raises ValueError. An ordinary predict(...) call is unaffected by any of this — the request body it sends is byte-for-byte what it always was.

Categorical / Ordinal Targets (discretize= / categorical_levels=)

When the target only takes a small set of discrete values (a 1–5 rating, a count, a quality score), pass discretize= and every returned prediction is one of the target's own levels instead of a continuous estimate:

labels = client.predict(X_train, y_train, X_test, discretize="snap-mean")
labels = client.predict(
    X_train, y_train, X_test,
    discretize="snap-mean",
    categorical_levels=[1, 2, 3, 4, 5],   # the full scale, if the context may under-cover it
)

Discretization is strictly opt-in — nothing is snapped unless you ask. categorical_levels is the set of values the target can take (numeric; order and duplicates don't matter); it defaults to the distinct values of y_train, which is leak-safe. A NaN prediction stays NaN rather than becoming a confident label.

Capability differs by mode:

  • Remote: the hosted endpoint returns point predictions (the distribution mean), so the supported strategy is discretize="snap-mean" — the nearest level to the point prediction, computed client-side and identical to local "snap-mean". Other strategies raise a ValueError pointing here.
  • Local (pip install "synthefy[local]", with a synthefy-nori recent enough to ship synthefy_nori.discretize): the full strategy set is forwarded — "map-cell" (accuracy-optimal), "median-cell" (MAE-optimal), "snap-mean" (QWK), "snap-median", "expected-level", "prior-match". Choose by the metric you are scored on; see the synthefy-nori docs. An older synthefy-nori raises an ImportError with an upgrade hint.

If your task is scored by squared error / R², don't discretize — the continuous mean is already optimal for those metrics.

API Reference

SynthefyNoriClient (Tabular Regression)

  • SynthefyNoriClient(api_key=None, *, mode="remote", timeout=300.0, max_retries=2, base_url=..., endpoint=..., model, user_agent=None, endpoint_name=None, region_name=None)model is required everywhere and accepts the three released Nori variants (nori-6m, nori-30m, and nori-30m-thinking-medium) or an explicit custom HTTP slug; there is no None/default model path. SageMaker uses response streaming for all three so large 30M requests can run beyond the regular-response limit while predict() still returns one normal result.
    • mode: "remote" (hosted, default), "local" (in-process via synthefy-nori), "auto" (local if installed, else remote), or "sagemaker" (a named SageMaker endpoint using the AWS credential chain).
    • api_key (remote mode) falls back to the SYNTHEFY_NORI_API_KEY environment variable. Not required in local mode.
    • Hosted Nori is reached by gateway slug — that is the path Synthefy meters, rate-limits and grants per key. To target a single-model endpoint you host yourself, pass your own base_url/endpoint and an explicit custom model slug.
  • predict(X_train, y_train, X_test, task="regression", *, output_type="mean", quantiles=None, text_columns=None, svd_dim=128, embedder="minilm", text_device="auto", timeout=None, extra_headers=None) -> List[float]
    • Returns one predicted value per row of X_test. timeout/extra_headers apply to remote mode only.
    • output_type= picks what comes back from the predictive distribution: "mean" (default), "median", "quantiles" (with quantiles=[...], returns (n_levels, n_query)), or "full" (the whole quantile bank as a dict). See Prediction Intervals. Everything other than "mean" needs local mode or a hosted deployment that serves distribution output.
    • Inputs accept Python lists, numpy arrays, or pandas DataFrames/Series. Feature columns must be numeric; DataFrame X_test is aligned to X_train by column name; non-numeric columns are encoded (fit on X_train; categorical_encoding="ordinal" by default, "onehot" available); missing values (NaN) are imputed server-side.
    • max_categorical_cardinality (default 100): non-numeric columns with more distinct training values than this — and datetime columns — are dropped with a warning instead of encoded.
    • text_columns embeds named raw-text DataFrame columns client-side. The default text_device="auto" prefers CUDA/ROCm, then Apple MPS, then CPU; install the text extra and pass text_device="cpu" or another PyTorch device string to override it.
    • as_pandas=True returns a pandas Series (named after y_train, indexed by X_test) instead of the default list[float] — or a DataFrame with one column per level ("<target>[<level>]") for output_type="quantiles"/"full".
    • discretize= / categorical_levels= map predictions onto a discrete target's levels (see Categorical / Ordinal Targets); remote mode supports discretize="snap-mean", local mode the full strategy set of the installed synthefy-nori.
  • mode: the resolved mode ("auto" becomes "local"/"remote" at construction).
  • close() / context manager support (with SynthefyNoriClient(...) as client:).

SynthefyAPIClient (Synchronous)

The synchronous client class for interacting with the Synthefy API.

Constructor Parameters

  • api_key: Your Synthefy API key (can also be set via SYNTHEFY_API_KEY environment variable)
  • timeout: Request timeout in seconds (default: 300.0 / 5 minutes)
  • max_retries: Number of retries for transient errors (default: 2)
  • base_url: API base URL (default: "https://forecast.synthefy.com")
  • organization: Optional organization ID for multi-tenant setups
  • user_agent: Custom user agent string

Methods

  • forecast(request, *, timeout=None, idempotency_key=None, extra_headers=None) -> ForecastV2Response
    • Make a direct forecast request with a ForecastV2Request object
  • forecast_dfs(history_dfs, target_dfs, target_col, timestamp_col, metadata_cols, leak_cols, model) -> List[pd.DataFrame]
    • Convenience method for working directly with pandas DataFrames
  • close(): Manually close the HTTP client
  • Context manager support: Use with with SynthefyAPIClient() as client:

SynthefyAsyncAPIClient (Asynchronous)

The asynchronous client class for non-blocking operations and concurrent requests.

Constructor Parameters

Same as SynthefyAPIClient.

Methods

  • async forecast(request, *, timeout=None, idempotency_key=None, extra_headers=None) -> ForecastV2Response
    • Async version of forecast method
  • async forecast_dfs(history_dfs, target_dfs, target_col, timestamp_col, metadata_cols, leak_cols, model) -> List[pd.DataFrame]
    • Async version of forecast_dfs method
  • async aclose(): Manually close the async HTTP client
  • Async context manager support: Use with async with SynthefyAsyncAPIClient() as client:

Exception Hierarchy

All exceptions inherit from SynthefyError:

  • APITimeoutError: Request timed out
  • APIConnectionError: Network/connection issues
  • APIStatusError: Base class for HTTP status errors
    • BadRequestError (400, 422): Invalid request data
    • AuthenticationError (401): Invalid API key
    • PermissionDeniedError (403): Access denied
    • NotFoundError (404): Resource not found
    • RateLimitError (429): Rate limit exceeded
    • InternalServerError (5xx): Server errors

Each status error includes:

  • status_code: HTTP status code
  • request_id: Request ID for debugging (if available)
  • error_code: API-specific error code (if available)
  • response_body: Raw response body

Configuration

Environment Variables

  • SYNTHEFY_API_KEY: Your Synthefy API key (forecasting client)
  • SYNTHEFY_NORI_API_KEY: Your hosted-Nori API key (SynthefyNoriClient)

Support

For support and questions:

License

MIT License - see LICENSE file for details.

Download files

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

Source Distribution

synthefy-6.3.0.tar.gz (83.2 kB view details)

Uploaded Source

Built Distribution

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

synthefy-6.3.0-py3-none-any.whl (67.0 kB view details)

Uploaded Python 3

File details

Details for the file synthefy-6.3.0.tar.gz.

File metadata

  • Download URL: synthefy-6.3.0.tar.gz
  • Upload date:
  • Size: 83.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for synthefy-6.3.0.tar.gz
Algorithm Hash digest
SHA256 653772cd54159b705e79ed9f51ef1748d556c7faf4626d488eabd2b89714cb5b
MD5 9bc79409aeec54468419d3d20f138529
BLAKE2b-256 c6b0676ff50ca511eb7f74cdebd657e45cb96ee1cae8d4c67a2e5792c6b425bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for synthefy-6.3.0.tar.gz:

Publisher: publish.yaml on Synthefy/synthefy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file synthefy-6.3.0-py3-none-any.whl.

File metadata

  • Download URL: synthefy-6.3.0-py3-none-any.whl
  • Upload date:
  • Size: 67.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for synthefy-6.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7ab0134b61775b027544735570ba94dffcfdcb38abbe613c44872faf661ac6f2
MD5 867ee08522a74780002e8355dbfbb6d8
BLAKE2b-256 05eb7738fcbecd99a467f9edc1e0b8a7a825e8937031674df7b08011e11580d5

See more details on using hashes here.

Provenance

The following attestation bundles were made for synthefy-6.3.0-py3-none-any.whl:

Publisher: publish.yaml on Synthefy/synthefy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

7.1.3

2 files

7.1.2

2 files

7.1.1

2 files

7.1.0

2 files

7.0.4

2 files

7.0.3

2 files

7.0.2

2 files

7.0.1

2 files

7.0.0

2 files

This release

6.3.0 This release

2 files

6.2.1

2 files

6.1.0

2 files

6.0.0

2 files

5.0.0

2 files

4.7.0

2 files

4.6.0

2 files

4.5.0

2 files

4.4.0

2 files

4.3.0

2 files

4.2.2

2 files

4.2.0

2 files

4.1.3

2 files

4.1.2

2 files

4.1.1

2 files

4.1.0

2 files

4.0.1

2 files

4.0.0

2 files

3.1.2

2 files

3.1.1

2 files

3.1.0

2 files

3.0.0

2 files

2.2.0

2 files

2.1.2

2 files

2.1.1

2 files

2.1.0

2 files

2.0.5

2 files

2.0.4

2 files

2.0.3

2 files

2.0.2

2 files

2.0.1

2 files

2.0.0

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page