Nixtla TimeGPT Documentation Audit
A capable time-series product buried under a documentation layer that disagrees with itself at almost every seam: the REST quickstart targets an endpoint and auth scheme the OpenAPI spec doesn't define, the API reference omits every error the API actually returns, the models the tutorials tell you to use don't appear in the spec or the SDK, and one response schema requires three fields it never defines. The reference is also split across at least three advertised hostnames and two conflicting version numbers. Numbered findings below.
1. REST quickstart uses a nonexistent endpoint and the wrong auth header (critical)
Location: /docs/introduction/faq (REST API section)
Problem: The FAQ's only REST example is curl -X POST "https://api.nixtla.io/timegpt" -H "x-api-key: your_api_key". The OpenAPI spec defines no /timegpt path — the forecast path is /v2/forecast (openapi.json paths) — and the only declared security scheme is HTTPBearer (Authorization: Bearer <token>, per securitySchemes.HTTPBearer with scheme: bearer), not an x-api-key header. The request body also uses {"df": [...], "h": 7}, but the input schemas the spec does show — CrossValidationInput and FinetuneInput — both require series and freq (not df), so the forecast input almost certainly does the same.
Consequence: A developer (or an AI agent) that copies the canonical REST snippet sends the wrong path, the wrong auth header, and a body shape the spec doesn't use. Best case it 404s; worst case it 401s on the auth header and the developer wastes time debugging a credential that is actually valid.
The fix: Rewrite the FAQ REST example to POST https://api.nixtla.io/v2/forecast with Authorization: Bearer $NIXTLA_API_KEY and a body matching the forecast input schema (series, freq, h). Generate REST examples from the same OpenAPI spec that powers the reference so they can't drift.
2. API reference documents only 200/422 — every real error is missing (critical)
Location: /docs/api-reference/foundational-time-series-model-multi-series (and every other operation page)
Problem: Each operation documents only '200': Successful Response and '422': Validation Error. There is no 401, 429, or 5xx. Yet the FAQ explicitly documents 401 (code: 'A12', "Invalid API key") and 429 (code: 'A21', "Too many requests / add a payment method"), proving those responses exist and carry a structured body (message, details, code, requestID).
Consequence: The error contract — status codes, the code/requestID body shape, and what triggers a 429 — lives only in a prose FAQ, invisible to anything parsing the reference or the OpenAPI spec. Agents and SDK-generators build clients that handle success and validation errors but silently mishandle auth failure and rate limiting, the two errors a production caller hits most.
The fix: Add 401, 429, and a generic 5xx response to every authenticated operation in the spec, each referencing a shared error schema (message, details, code, requestID). Document the A12/A21 codes in the reference, not just the FAQ.
3. FAQ Python examples call SDK parameters that don't exist (critical)
Location: /docs/introduction/faq vs /docs/reference/sdk_reference
Problem: The FAQ shows client.forecast(df, h=7, finetune_steps=100, return_model=True), then client.forecast(new_df, h=7, model=fine_tuned_parameters), and client.cross_validation(df, h=7, k=3, test_size=7). The SDK reference signature has no return_model argument, model is Literal['azureai','timegpt-1','timegpt-1-long-horizon'] (it cannot take a fine-tuned-parameters object), and cross_validation takes n_windows/step_size — there is no k or test_size.
Consequence: Every one of these snippets raises TypeError: unexpected keyword argument on the current SDK. The fine-tune-and-reuse workflow — arguably the product's headline feature — is demonstrated with an API that doesn't exist, so a developer following the FAQ cannot save and reload a fine-tuned model.
The fix: Rewrite the FAQ examples against the current SDK: use finetuned_model_id for save/reuse (matching the /v2/finetune + /v2/finetuned_models endpoints) and cross_validation(df, h=7, n_windows=3, step_size=7). Add a doctest/CI check that executes FAQ snippets.
4. The current-generation models and their base URL are absent from the API reference and SDK (critical)
Location: /docs/forecasting/timegpt_2_family vs /docs/openapi.json and /docs/reference/sdk_reference
Problem: The TimeGPT-2 page tells users to call model="timegpt-2.1" (also timegpt-2-pro, timegpt-2-lab, timegpt-2-mini) against a different base URL, https://api-preview.nixtla.io. But openapi.json lists only servers: https://api.nixtla.io, and the SDK model argument is pinned to Literal['azureai','timegpt-1','timegpt-1-long-horizon']. The REST model field is an open string ("Common options are (but not restricted to)… Full options vary by different users"), so timegpt-2.1 would likely be accepted over raw REST — but the type-checked SDK rejects it, and neither the preview host nor the TimeGPT-2 model names appear anywhere in the spec or SDK. The SDK Literal also includes azureai, a value the REST spec never mentions.
Consequence: The API reference — the artifact agents and integrators trust as ground truth — does not describe the models Nixtla actively markets, nor the preview host they run on. A user who passes model="timegpt-2.1" to a type-checked SDK call gets flagged as invalid; a user reading only the reference never learns the preview endpoint exists. The reference documents a previous generation while the tutorials sell the current one.
The fix: Register api-preview.nixtla.io under servers, document the TimeGPT-2 model names in the model field's description (and/or enum), widen the SDK Literal (or make it an open str), and cross-link the TimeGPT-2 page from the reference. Reconcile azureai between SDK and spec.
5. Spec declares security: [] at the top level while operations require a bearer token (significant)
Location: /docs/api-reference/* (rendered pages) and /docs/openapi.json
Problem: Every rendered API-reference page shows security: [] at the document root, which in OpenAPI means "no authentication required by default." Individual operations then override with security: - HTTPBearer: []. The aggregate openapi.json omits the top-level security field entirely, so the two representations of the same API disagree on the global default.
Consequence: A spec-compliant parser honors the per-operation override and authenticates correctly, so the blast radius is narrower than the missing-error findings. But a top-level security: [] is a known trap: naive tools that read the global default and ignore operation overrides emit clients or "try it" consoles that call with no Authorization header, producing 401s the developer can't explain. The mismatch between the per-page security: [] and the spec's absent field also means tooling behaves differently depending on which artifact it consumes.
The fix: Set a single top-level security: [{ HTTPBearer: [] }] consistently across the rendered pages and openapi.json, and drop the empty per-document override.
6. OnlineAnomalyOutput requires three fields it never defines (significant)
Location: /docs/api-reference/foundational-time-series-model-online-multi-series-anomaly-detector
Problem: The OnlineAnomalyOutput schema's required array lists input_tokens, output_tokens, and finetune_tokens — none of which are defined as properties of the schema. Its actual properties are mean, sizes, idxs, anomaly, anomaly_score, and accumulated_anomaly_score. Separately, mean, sizes, and idxs carry only a title and no type, leaving their wire representation unspecified.
Consequence: A schema that requires fields it doesn't define is invalid to strict validators and breaks codegen: a generated client would expect input_tokens/output_tokens/finetune_tokens on every response, fail validation when they're absent, and have no typing for mean/sizes/idxs. This is a hard, objective spec defect, not a prose slip.
The fix: Either define input_tokens/output_tokens/finetune_tokens as properties (if the API actually returns them) or remove them from required, and add type to mean, sizes, and idxs.
7. OpenAPI version is 0.2.4 in the spec but 2025.8.3 on every reference page (significant)
Location: /docs/openapi.json vs /docs/api-reference/*
Problem: openapi.json reports info.version: "0.2.4", while every rendered API-reference page embeds version: 2025.8.3 under the same title: Nixtla Forecast API.
Consequence: There is no single answer to "what version of the API am I reading?" Anyone pinning behavior to a version, filing a bug, or diffing spec revisions can't tell which number is authoritative, and cache/CDN validation against version strings becomes unreliable.
The fix: Emit the reference pages from openapi.json so both share one info.version. Pick one versioning scheme (semver or calendar) and use it everywhere.
8. llms.txt links a deprecated page that 404s (significant)
Location: /docs/llms.txt → /docs/api-reference/foundational-time-series-model-multi-series-historic-deprecated
Problem: The docs index lists "Foundational Time Series Model Multi Series Historic (Deprecated)" and links its .md page. All three fetchers (kernel, WebFetch, exa) return HTTP 404 for that URL. The deprecation blurb also points readers to /v2/cross_validation via an in-page anchor (#tag/default/POST/v2/cross_validation) that assumes a single-page reference layout.
Consequence: llms.txt is the machine-readable index agents use to crawl the docs; a dead entry in it means an agent following the index hits a 404 (served, notably, with a full app-shell HTML body of ~127 KB — so a naive crawler may ingest the shell as if it were content). Humans looking for the historic-forecast migration path land on nothing.
The fix: Remove the dead entry from llms.txt or restore the page with a proper redirect to the cross-validation docs, and replace the fragment anchor with a real page URL.
9. Docs contradict themselves on polars support (significant)
Location: /docs/introduction/faq vs /docs/data_requirements/data_requirements
Problem: The FAQ states flatly: "Currently, TimeGPT does not support polars." The Data Requirements page states: "TimeGPT accepts pandas and polars dataframes in long format." Same product, opposite answers, no version qualifier on either.
Consequence: A polars user can't tell whether their stack is supported. One page tells them to rewrite everything in pandas; the other tells them to proceed. Whichever they trust, the other page undermines it.
The fix: Decide the current answer, state it once in Data Requirements, and delete or correct the FAQ entry. If support was added in a specific SDK version, say so.
10. FAQ flatly denies missing-value / irregular-timestamp handling the docs otherwise support (significant)
Location: /docs/introduction/faq
Problem: The FAQ answers "Can TimeGPT handle missing values?" with an absolute: "TimeGPT cannot handle missing values or series with irregular timestamps." This conflicts with the product's dedicated tutorial coverage for exactly those scenarios (referenced in the same FAQ evidence). The statement carries no version or context qualifier — it reads as a blanket capability denial.
Consequence: A user with real-world data (gaps, uneven sampling) reads the FAQ, concludes TimeGPT is unusable for their data, and abandons it — even though the docs elsewhere walk through handling both cases. It's the same class of self-contradiction as the polars entry, and it's more damaging because it discourages adoption outright.
The fix: Replace the flat denial with the accurate answer and link the missing-value / irregular-timestamp tutorials directly from the FAQ. If there are genuine constraints (e.g., requires imputation or resampling first), state them precisely instead of "cannot."
11. finetune_loss enum, prose, and SDK disagree on poisson (significant)
Location: /docs/api-reference/foundational-time-series-model-multi-series (and cross-validation, finetune, online-anomaly pages) vs /docs/reference/sdk_reference
Problem: The finetune_loss schema enum lists ['default','mae','mse','rmse','mape','smape','poisson'], but the human-readable description immediately below says "Select from ['default', 'mae', 'mse', 'rmse', 'mape', 'smape']" — poisson omitted. The SDK pins finetune_loss: Literal['default','mae','mse','rmse','mape','smape'] — no poisson either. Yet the FinetunedModel.loss enum (GET /v2/finetuned_models) includes poisson, confirming it is a real, accepted value.
Consequence: poisson is a supported loss the docs actively hide: the prose tells you it's not an option, and the type-checked SDK rejects it, so no one using the documented surface can select it — despite the API accepting it. This is a genuine capability gap, not a guardrail.
The fix: Add poisson to every finetune_loss prose description and to the SDK Literal, or, if it's intentionally restricted, remove it from the request enums. Make the enum, prose, and SDK type generate from one source.
12. freq is documented as D/M/H/W-only, but the docs' own examples use MS (significant)
Location: /docs/api-reference/foundational-time-series-model-multi-series-finetuning and /docs/setup/azureai vs the shared freq description
Problem: Every freq description says "'D' for daily, 'M' for monthly, 'H' for hourly, and 'W' for weekly frequencies are available." But the finetune endpoint's own example passes freq: MS (month-start), and the Azure quickstart uses freq='MS'. MS is not in the "available" list.
Consequence: A developer reading the parameter doc believes only four frequencies work and may reject MS, business-day, or quarterly data — or, conversely, distrust the examples. The docs simultaneously teach MS and claim it isn't allowed.
The fix: Correct the freq description to state that any pandas-compatible offset alias is accepted (or enumerate the real supported set including MS, Q, B, etc.). Align the description with the examples.
13. finetune_steps cannot be 0 on the finetune endpoint despite its own description saying it can (significant)
Location: /docs/api-reference/foundational-time-series-model-multi-series-finetuning
Problem: On /v2/finetune, finetune_steps is type: integer, exclusiveMinimum: 0, default: 10 — it must be ≥ 1. But the description text on that same parameter reads "Set this value to 0 for zero-shot inference, i.e., to make predictions without any further model tuning." The constraint and the instruction directly contradict each other on one page. (The SDK signature shows finetune_steps=0 as the forecast default, indicating 0 is valid on the forecast path — so the prose was written for a different endpoint and reused here.)
Consequence: A developer copies the description's advice, sends finetune_steps: 0 to /v2/finetune, and gets a 422 — the documented instruction is impossible on the very endpoint it appears on.
The fix: Give /v2/finetune a description that reflects exclusiveMinimum: 0 ("must be ≥ 1; use the forecast endpoint for zero-shot"), and stop reusing forecast-endpoint prose verbatim where the constraint differs.
14. Online anomaly detection promises a z_score field the schema doesn't have (significant)
Location: /docs/api-reference/foundational-time-series-model-online-multi-series-anomaly-detector
Problem: The description says the response "reports the associated z-score for each point." The OnlineAnomalyOutput schema has no z_score/zscore property — it exposes anomaly_score and accumulated_anomaly_score instead.
Consequence: A developer parsing the response for z_score (as the prose instructs) finds nothing and can't tell whether anomaly_score is the same statistic under a different name or something else entirely. Anomaly-flagging logic keyed on the documented field name silently reads undefined.
The fix: Either add a z_score field or rename the prose to match anomaly_score, and document what anomaly_score vs accumulated_anomaly_score mean and their scale.
15. validate_api_key has no description, an empty response schema, and no failure response (significant)
Location: /docs/api-reference/validate-api-key
Problem: The page is blank under the title (no description). The documented 200 response is schema: {} — the body is entirely unspecified. Being the only auth-check endpoint, it documents no response for an invalid key, even though the SDK's validate_api_key() "returns True if your API key is valid, or False otherwise."
Consequence: The endpoint whose entire job is to tell you whether auth works doesn't document what a success or failure looks like on the wire. A developer calling /validate_api_key directly (not via the SDK) can't tell whether an invalid key yields 200 {"valid": false}, a 401, or something else — so they can't write the check the endpoint exists to enable.
The fix: Add a description and a concrete 200 response schema, and document the invalid-key response (status + body). Align it with the SDK's boolean semantics.
16. The same product advertises at least three documentation hostnames (significant)
Location: pypi.org/project/nixtla (Documentation + docs badge) vs nixtla.io/docs
Problem: The PyPI page's "Documentation" link points to https://nixtlaverse.nixtla.io/, its README docs badge points to https://docs.nixtla.io, and the docs actually audited here live at nixtla.io/docs, which 301-redirects to www.nixtla.io/docs. llms.txt itself mixes bare nixtla.io and www.nixtla.io hosts.
Consequence: A developer installing from PyPI (version 0.7.4) is sent to two different doc sites, neither of which is the www.nixtla.io/docs site containing the TimeGPT-2 and API-reference material audited here. Agents indexing "the Nixtla docs" have no canonical host, and the bare-vs-www redirect adds a hop that can strip or break fragment anchors.
The fix: Choose one canonical docs host, 301 the others to it, and update the PyPI Documentation/Homepage metadata and the README badge to point there. Normalize llms.txt to a single host.
17. "Private beta" vs "30-day free trial, no credit card" — conflicting access models (significant)
Location: /docs/api-reference/* vs /docs/introduction/timegpt_subscription_plans
Problem: Every API-reference page says "Get your token for private beta at …/free-trial." The Subscription Plans page says "When you create your account, you receive a 30-day free trial with no credit card required." Private-beta (gated, invite-style) and self-serve 30-day trial are different access models.
Consequence: A prospective user can't tell whether they can sign up right now or must request access. The "private beta" framing on every reference page may deter self-serve users the subscription page is trying to convert.
The fix: Pick the current access model and state it consistently. If it's now self-serve, purge the "private beta" language from the reference pages' descriptions.
18. Historical exogenous features use two incompatible interfaces with no mapping explained (significant)
Location: /docs/api-reference/foundational-time-series-model-multi-series-cross-validation vs /docs/reference/sdk_reference
Problem: The REST hist_exog parameter takes "zero-based indices of the exogenous features" (array of integer, minimum: 0). The SDK exposes the same capability as a separate parameter, hist_exog_list. The two interfaces are shaped differently (integer indices vs. a list argument), and no page cross-references them or explains how the SDK's list relates to the API's positional indices.
Consequence: A developer moving between the SDK and raw REST (or reading both) has no documented way to know how hist_exog_list translates to the hist_exog integer indices the API expects, or how ordering is determined. Getting the index order wrong feeds the model the wrong features with no validation error.
The fix: Document the relationship between hist_exog_list (SDK) and hist_exog (REST indices), including how index order is derived from the input DataFrame columns, and link the two parameter references to each other.
19. Subscription page points to the FAQ for pricing, but the FAQ has no pricing (significant)
Location: /docs/introduction/timegpt_subscription_plans vs /docs/introduction/faq
Problem: The Subscription Plans page says "Additional pricing details … can be found on our FAQ page." The FAQ page's content covers error messages, capability Q&As (missing values, polars), and code examples — but contains no pricing figures. The only money-adjacent line anywhere is the 429 error's "You need to add a payment method to continue," which is not pricing.
Consequence: Pricing is a purchase-blocking question, and the docs' own pointer for it dead-ends. A prospective buyer follows the explicit "see the FAQ" instruction and finds no numbers, forcing them to "book a call" for information the docs implied was self-serve.
The fix: Put actual pricing (or a link to a real pricing page) where the Subscription Plans page promises it, or remove the FAQ pointer and state where pricing actually lives.
20. Spelling error "perdiod" in the anomaly-detector description (minor)
Location: /docs/api-reference/foundational-time-series-model-multi-series-anomaly-detector
Problem: The operation description reads "detects the anomalies in the historical perdiod of multiple time series." Because reference pages typically emit the operation description into page/OpenGraph metadata, the misspelling likely surfaces in link previews and search snippets as well as the body.
Consequence: A visible typo on a reference page — and potentially in shared link previews — is a small but public credibility ding on the API's canonical documentation.
The fix: Fix "perdiod" → "period" at the source description so both the body and any derived metadata update.
21. The AirPassengers dataset is described two different (and one incorrect) ways (minor)
Location: /docs/setup/azureai vs /docs/forecasting/timegpt_quickstart
Problem: The TimeGPT-1 quickstart calls AirPassengers "international airline passengers from 1949 to 1960." The Azure quickstart says the same dataset "shows monthly passenger counts in Australia between 1949 and 1960." The classic AirPassengers dataset is international airline totals, not Australia-specific.
Consequence: A reader comparing the two onboarding pages gets contradictory descriptions of the canonical example dataset, and the Azure version is factually wrong — minor, but it undermines trust in the very first example a new user runs.
The fix: Use one correct description of AirPassengers ("monthly totals of international airline passengers, 1949–1960") on both pages.
22. Output column labeled TimeGPT even on the TimeGEN-1 endpoint, and the Azure product has three names (minor)
Location: /docs/setup/azureai
Problem: The Azure page introduces "TimeGEN-1" ("TimeGPT optimized for Azure infrastructure"), the SDK exposes it as model='azureai', and the example's forecast output column is labeled TimeGPT even for a TimeGEN-1 deployment. That's three names — TimeGEN-1, azureai, TimeGPT — for one offering.
Consequence: A developer post-processing results can't predict the output column name (TimeGPT vs the model they requested), and the three-way naming makes it hard to search docs or write code that references "the Azure model" consistently.
The fix: Standardize on one Azure product name in prose, map it explicitly to the azureai SDK value, and document the actual output column name.
23. /model_params is exposed in the spec but has no documentation (minor)
Location: /docs/openapi.json (paths) vs /docs/llms.txt
Problem: openapi.json lists a GET /model_params path, but llms.txt (the docs index) has no page for it — it appears in no human- or agent-facing documentation.
Consequence: An agent crawling the spec discovers an endpoint with no description, parameters, or response schema documented anywhere, so it can neither use it safely nor know whether it's public.
The fix: Either document /model_params (purpose, params, response) and add it to llms.txt, or mark it internal/hidden in the spec if it isn't meant for public use.
24. Install command is unpinned in the quickstart but requires >=0.7.0 for current models (minor)
Location: /docs/forecasting/timegpt_quickstart vs /docs/forecasting/timegpt_2_family
Problem: The TimeGPT-1 quickstart shows pip install nixtla (unpinned). The TimeGPT-2 page requires pip install nixtla>=0.7.0 because "the client version must be >= 0.7.0." PyPI currently serves 0.7.4, so a fresh install happens to work — but the quickstart never states the floor.
Consequence: A user who pip-installed earlier, or who pins to an older release, follows the TimeGPT-2 instructions and gets confusing failures with no version guidance on the primary quickstart page.
The fix: State the minimum supported version on the main quickstart (pip install "nixtla>=0.7.0") and note which features require which versions.
25. Docker/self-host page documents no image name, tags, or run command (minor)
Location: /docs/setup/docker
Problem: The Docker page lists benefits of self-hosting but never gives the image name, available tags, a docker run command, or configuration — access is gated entirely behind "book a call with us." It also contains a typo, "entreprise."
Consequence: A developer evaluating self-hosting can't assess feasibility (image size, GPU flags, env vars) without a sales call. For a page titled "Docker Image for TimeGPT," there is no Docker usage on it.
The fix: Document at least the reference docker run invocation, required env vars (API key, base URL), and hardware options behind the paid tier, even if the image itself requires credentials to pull. Fix "entreprise" → "enterprise."
26. Required columns are ds/y, but the examples use timestamp/value with no bridge (minor)
Location: /docs/data_requirements/data_requirements vs /docs/setup/azureai and /docs/forecasting/timegpt_2_family
Problem: The Data Requirements page lists the minimum required columns as ds and y, yet the Azure and TimeGPT-2 examples call forecast(..., time_col='timestamp', target_col='value'), and the Data Requirements page itself renames its example columns to timestamp/value. It is legal (via time_col/target_col), but nothing explains that to a first-time reader.
Consequence: A beginner who reads "required columns: ds, y" and then sees examples built on timestamp/value can't tell whether the requirement was wrong, the example is wrong, or something maps between them — a needless stumble on the first data-loading step.
The fix: State once that ds/y are the defaults and any column names work via time_col/target_col, and make the required-columns doc and the examples use the same convention (or explicitly show the override).
What they do well
- A real machine-readable surface exists — a single aggregate
openapi.jsonplus anllms.txtindex, which is more agent-friendly than most peers; the problems are drift and dead entries, not absence. - The canonical auth setup is clean — /docs/setup/setting_up_your_api_key clearly documents
NIXTLA_API_KEYenv-var auto-detection and avalidate_api_key()check, giving a correct baseline (the FAQ'sx-api-keyexample is the outlier, not the norm). - Onboarding narrative is complete — dashboard → create API key → install → validate → forecast is a coherent, followable path with a standard example dataset.
Top 3 recommendations
- Generate REST examples, the API reference, and the SDK types from one source of truth. Nearly every high-severity finding (endpoint/auth mismatch, missing errors, the
OnlineAnomalyOutputrequired-vs-defined bug,poisson,freq, missing TimeGPT-2 models, version 0.2.4 vs 2025.8.3) is drift between artifacts that should be generated from the OpenAPI spec. - Document the full error contract in the reference, not the FAQ. Add
401/429/5xxwith thecode/requestIDbody shape to every authenticated operation, and fix the top-levelsecurity: []so tooling doesn't emit unauthenticated clients. - Consolidate to one canonical docs host and one access story. Redirect
nixtlaverse.nixtla.io,docs.nixtla.io, and barenixtla.ioto a single host; update PyPI/README metadata; reconcile "private beta" with the "30-day free trial" self-serve messaging; and make the pricing pointer actually lead to pricing.