DOCS · concepts · REST · MCP · SDKs · datasets

Veracle documentation

Everything you need to read Veracle's cited, bitemporal reference data from your software or an LLM agent — the provenance model, the full REST API, the remote MCP server, the typed SDKs and the dataset catalog.

Open the Explorer ▸Read the guided tour ▸openapi.json

Overview & concepts

The model behind every Veracle datapoint — cited, bitemporal and quarantine-gated.

🧭

What Veracle is

An AI-ready golden source for Thai & SEA energy and macro reference data. Public-but-painful figures (electricity Ft, oil price structure, FX, macro, gold, equities, bond yields) are normalized into typed series and served — cited and verifiable — to software and LLM agents over REST and a remote MCP server.

🔖

The provenance envelope

Every datapoint carries its provenance inline: source_doc_uri, effective_date, as_reported_at, ingested_at, revision_id, is_current, parser_confidence and a human-readable citation. source_doc_uri resolves to the exact archived source artifact — open it and check the original.

🕰️

Bitemporal time-travel

Two time axes: valid-time (effective_date — when a value applies) and transaction-time (as_reported_at / ingested_at — when we learned it). Revisions are append-only; nothing is overwritten. Add ?as_of=YYYY-MM-DD to any read to reconstruct exactly what was known on that date.

🛡️

The trust pipeline

ingest → archive raw to R2 → validate (range + period-over-period delta + cross-source reconciliation + sum-checks) → bitemporal store → cite. Cross-source reconciliation holds the Ft to ±0.01 satang (ERC authoritative); oil components must sum to the retail price within tolerance.

🚦

Quarantine — trust over coverage

A value with low parser-confidence, a failed validation, a reconciliation mismatch or a detected source-layout change is quarantined and never published. The deliberate bias is a false-positive quarantine over publishing a wrong value: a disputed number is held for human review, not served.

🧪

Demo data, real plumbing

This deployment serves representative synthetic fixtures — real ERC / EPPO / BOT data is gated on licensing. The pipeline is fully real: ingestion, content-addressed archival, validation, the bitemporal store, citations, lineage, REST and MCP all behave exactly as in production.

REST API

All endpoints are GET unless marked POST · CORS is open (origin *) · auth is anon unless noted. openapi.json

Catalog

Discover what exists. List and inspect series; filter by domain, country or a free-text query.

GET/v1/seriesList series; filter domain / country / qanon
GET/v1/series/{id}One series' metadataanon
Example request
curl 'https://veracle-api.chaiyaphum.workers.dev/v1/series?domain=commodity.gold'

Observations

The generic, cited read of any series. Filter by series_id or series_prefix, a from/to window, and ?as_of for point-in-time.

GET/v1/observationsCited read of any series; series_id | series_prefix, from, to, as_ofanon
GET/v1/observations/{id}/lineageFull provenance chain to the raw artifactanon
Example request
curl 'https://veracle-api.chaiyaphum.workers.dev/v1/observations?series_id=th.macro.fx.usd.mid'

Typed domain reads

Domain-shaped endpoints that return strongly-typed components (Ft by customer class, oil by grade with all structure components, FX by currency and rate type, macro by indicator).

GET/v1/ftElectricity Ft; period, customer_classanon
GET/v1/oilOil price structure; date, fuel_gradeanon
GET/v1/fxFX rates; currency, rate_type, dateanon
GET/v1/macroMacro indicator; indicatoranon
Example request
curl 'https://veracle-api.chaiyaphum.workers.dev/v1/ft?customer_class=general'

Carbon estimate

The energy→carbon bridge. Browse the cited emission factors as observations, then POST activity quantities (kWh, litres) with factor series ids to get kgCO₂e back — each result cites the exact factor (TGO, IEA, EU CBAM, DEFRA). Add as_of for point-in-time factors.

POST/v1/carbon/estimateEnergy→CO₂e; body { items: [{ factor_series, quantity, label }], as_of }anon
Example request
curl 'https://veracle-api.chaiyaphum.workers.dev/v1/observations?series_prefix=th.carbon.'

Ask Veracle

A citation-grounded LLM. Ask in natural language; the answer is grounded in retrieved, cited observations and can't fabricate a number. Env-gated — returns 503 where not enabled.

GET/v1/askGrounded answer + citations; q, limitkey required
Example request
curl 'https://veracle-api.chaiyaphum.workers.dev/v1/ask?q=What%20is%20the%20electricity%20Ft%20for%20the%20general%20class%3F'

Enterprise

Bulk Parquet exports with signed downloads, signed-webhook subscriptions, and your own audit trail. Downloads + webhooks require a non-anon principal; the audit trail requires the audit:read scope.

GET/v1/exportsList bulk Parquet snapshotsanon
GET/v1/exports/{id}/downloadShort-lived signed download URLkey required
POST/v1/webhooksSubscribe to signed eventskey required
GET/v1/auditYour own audit trail (scoped)scoped
Example request
curl 'https://veracle-api.chaiyaphum.workers.dev/v1/exports'

Operations

Liveness and readiness probes, Prometheus metrics, per-series freshness vs cadence budget, and the declarative data-residency disclosure.

GET/healthLiveness (cheap)anon
GET/health/readyReadiness; 503 if the DB is unreachableanon
GET/metricsPrometheus metrics (text)anon
GET/v1/freshnessPer-series freshness vs cadence budgetanon
GET/v1/residencyDeclarative data-residency disclosureanon
GET/openapi.jsonMachine-readable OpenAPI documentanon
Example request
curl 'https://veracle-api.chaiyaphum.workers.dev/v1/freshness'

Auth & tiers

Tiers are limits only — anon, free and pro return byte-identical data, provenance and citations. Over-limit requests get a 429. Every response carries X-Veracle-Tier, X-RateLimit-Limit and X-RateLimit-Remaining.

anonnone (by IP)60 / min
freeX-API-Key: vk_…600 / min
proAuthorization: Bearer … (OAuth)6000 / min

MCP for AI agents

The remote MCP server exposes each dataset as a typed tool, so an agent discovers the catalog and reads cited values directly — no scraping, verifiable citations. It speaks streamable HTTP and is OAuth-protected; for an anonymous dev server the read tools stay permissive.

Remote MCP endpoint
POST https://veracle-mcp.chaiyaphum.workers.dev/mcp
# dev: http://localhost:8788/mcp
9 tool ↔ REST analogue
list_seriesGET /v1/series
get_seriesGET /v1/series/{id}
get_observationsGET /v1/observations
get_ft_tariffGET /v1/ft
get_oil_price_structureGET /v1/oil
get_fx_ratesGET /v1/fx
get_macro_indicatorsGET /v1/macro
get_freshnessGET /v1/freshness
ask_veracleGET /v1/ask
Add to your MCP client

OAuth metadata advertises scopes_supported (ft|oil|fx|macro:read, export:download, webhooks:subscribe, audit:read). Claude Desktop has no native remote transport, so it uses the mcp-remote bridge; Cursor and VS Code take the URL directly.

{
  "mcpServers": {
    "veracle": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://veracle-mcp.chaiyaphum.workers.dev/mcp"
      ]
    }
  }
}

Ask Veracle

A citation-grounded LLM at GET /v1/ask — it answers in plain language but cannot fabricate a number.

🔎

Retrieve, then answer

Your question is matched to relevant series; the matching cited observations are retrieved and handed to the model as the only allowed evidence.

🔖

Grounded — can't fabricate

The model must answer only from the retrieved observations and return their citations. A grounded:false answer is flagged; numbers come from the data, never invented.

🧾

Auditable response

Each response returns answer, citations[], model, retrieved, cost_usd and grounded. Click any citation to trace its full lineage to the archived source.

🔌

Env-gated

Ask runs only where an LLM provider is configured; otherwise it returns 503 (not enabled). It needs a non-anon principal (an API key) and has its own daily budget.

Example request
curl -H 'X-API-Key: vk_…' 'https://veracle-api.chaiyaphum.workers.dev/v1/ask?q=What is the electricity Ft for the general class?'

SDKs

Both SDKs wrap the REST API and return the shared core-schema types, so responses are validated and carry the full provenance envelope + citation. apiKey / api_key selects the free tier; oauthToken / oauth_token selects pro. They accept an injectable transport for hermetic tests.

@veracle/sdk
Install
npm i @veracle/sdk
Construct a client
import { VeracleClient } from "@veracle/sdk";

const veracle = new VeracleClient({
  baseUrl: "https://veracle-api.chaiyaphum.workers.dev",
  apiKey: "vk_…", // free tier · or oauthToken for pro
});

const ft = await veracle.getFtTariffs({
  period: "2025-01",
  customer_class: "general",
});
console.log(ft[0].value, ft[0].citation);
Ask in natural language
const res = await veracle.ask(
  "What is the electricity Ft for the general class?",
);
console.log(res.answer);
for (const c of res.citations) console.log(c.citation);

Datasets

A new dataset is nearly free: an ingest fixture plus a series row makes it instantly discoverable, citable and freshness-tracked with zero new serving code. Browse the full live catalog in the Explorer. Browse the full live catalog →

DomainSeries namespaceCoverage
Electricity Ftth.energy.electricity.ft.*By customer class (general, residential, …)
Oil price structureth.oil.retail.structure.<grade>.<component>Per grade: ex-refinery, taxes, Oil Fund, conservation fund, margin, VAT, retail
FX ratesth.macro.fx.<ccy>.<rate_type>USD/EUR/JPY/GBP/CNY × buying/mid/selling
Macro indicatorsth.macro.indicator.<code>Policy rate, headline CPI, GDP
Carbon / emission factorsth.energy.* (reference)Emission factors for energy-cost reasoning
Goldth.commodity.gold.*Gold price (GTA reference)
SET equitiesth.equity.index.*SET / SET50 / SET100 indices
Bank & bond ratesth.macro.rate.* · th.macro.bond.*MLR/MOR/MRR · government-bond yields
Reference (TH)th.* (LPG/NGV, core CPI, min wage)LPG/NGV, core CPI, minimum wage
SEA (MY · SG)my.* · sg.*MY fuel/MYR/OPR/KLCI · SG SGD/CPI/STI/tariff
Derivedth.derived.energy.effective_cost_indexWeighted Ft+fuel+FX basket (base = 100), carries input observation ids
Forecasts<country>.forecast.<rest>Next-period OLS trend + confidence band — clearly-labelled estimates, never observations

Anatomy of a cited datapoint

Every observation returns this provenance envelope — the same shape across REST, MCP, SDKs and Ask.

{
  "observation_id": 27,
  "series_id": "th.energy.electricity.ft.general",
  "value": 0.3672,
  "unit": "THB/kWh",
  "effective_date": "2025-01-01",
  "as_reported_at": "2024-12-15T09:00:00Z",
  "ingested_at": "2024-12-16T02:11:00Z",
  "revision_id": 1,
  "is_current": true,
  "parser_confidence": 0.98,
  "source_id": "erc",
  "source_doc_uri": "r2://veracle-raw-artifacts/erc/ft/8a1f….pdf",
  "citation": "ERC electricity Ft — general class, Jan–Apr 2025: 0.3672 THB/kWh. Source: ERC announcement (p.2)."
}

GET /v1/observations/{id}/lineage resolves source → archived document; a derived series expands into the input observations it was computed from. Trace any live datapoint in the Explorer →