THE GUIDE · what it is · how it works · API + MCP

Veracle, explained.

Veracity + oracle — an AI-ready golden source for Thai & SEA energy and macro reference data. Normalized, citation-bearing and bitemporal, served to software and LLM agents over REST and MCP. This page is the full tour: concepts, the pipeline and a complete API reference.

Open the Explorer ▸API reference ↓openapi.json
DEMO DATAThis deployment serves synthetic demo data.

Veracle's plumbing is real — ingestion, content-addressed archival, validation & reconciliation, the bitemporal store, citations, lineage, REST and MCP. But the values shown are representative synthetic fixtures; real ERC / EPPO / BOT data is gated on licensing. Every datapoint is still fully cited and traceable end-to-end, so you can evaluate exactly how the platform behaves. Bias by design: a false-positive quarantine over publishing a wrong value — trust over coverage.

What is Veracle

For software developers (energy / fintech / industrial) and LLM agents that need verifiable, citeable reference numbers.

🧹

Normalized

Public-but-painful energy & macro data, cleaned into consistent, typed series.

🕰️

Historical continuity

Every revision is kept; query the value as of any point in time.

🔖

Provenance & audit

Each value resolves to the exact archived source artifact (page/bbox).

🛡️

Reliable

Validated, reconciled, quarantine-gated — never publishes a disputed value.

🧩

AI-native (MCP)

A remote MCP server that agents call as their grounded, citeable source.

Core concepts

🔖

Citation-bearing

Every datapoint carries source_doc_uri, effective_date, as_reported_at, parser_confidence and a human-readable citation. The lineage endpoint resolves the full chain back to the raw archived artifact.

🧩

MCP-native

A remote MCP server exposes typed tools, so agents discover the catalog and read cited values directly — no scraping, verifiable citations.

🕰️

Bitemporal

Two time axes: valid-time (effective_date) and transaction-time (as_reported_at / ingested_at). Revisions are append-only; add ?as_of=YYYY-MM-DD for point-in-time reads.

🛡️

Trust mechanisms

Cross-source reconciliation (ERC authoritative, ±0.01; oil components must sum to retail), source-change detection (content-hash + layout signature), and quarantine — low confidence or failed validation is held, never served.

How it works

Every value's journey, source to served.

1

Ingest

Docling for ERC Ft PDFs, Playwright for EPPO oil HTML, JSON for BOT FX/macro, fixtures for reference series.

2

Archive raw → R2

The raw artifact is stored content-addressed on R2 first — before anything is parsed.

3

Validate

Range checks + period-over-period delta + reconciliation / sum-checks.

4

Quarantine gate

Anything low-confidence or failing validation is quarantined and never published.

5

Bitemporal store

Append-only revisions in Neon Postgres — nothing is overwritten.

6

Serve

Metered, cached, citation-bearing delivery over REST + MCP on Cloudflare Workers.

↘ quarantine, never published

Datasets & coverage

~73 series across 3 countries. Browse the full catalog live →

🇹🇭 Thailand

  • Electricity Ft (by customer class)
  • Oil price structure per grade (ex-refinery, taxes, funds, margin, VAT, retail)
  • BOT FX: USD/EUR/JPY/GBP/CNY × buying/mid/selling
  • Macro: policy rate, CPI, GDP
  • Reference: LPG/NGV, gold, SET indices, bank rates, bond yields, core CPI, min wage

🇲🇾 Malaysia

  • Fuel · MYR · OPR · KLCI

🇸🇬 Singapore

  • SGD · CPI · STI · electricity tariff

📈 Derived & forecasts

  • Effective energy-cost index (base = 100); next-period forecasts (OLS trend + band, labelled estimates)

Quickstart

Anonymous works — no key needed (60 req/min by IP). Add X-API-Key: vk_… for the free tier (600/min); same data.

curl

curl 'https://veracle-api.chaiyaphum.workers.dev/v1/series'

TypeScript

import { VeracleClient } from "@veracle/sdk";
const client = new VeracleClient({ baseUrl: "https://veracle-api.chaiyaphum.workers.dev", apiKey: "vk_..." });
const data = await client.listSeries();

Python

from veracle_sdk import VeracleClient
client = VeracleClient(base_url="https://veracle-api.chaiyaphum.workers.dev", api_key="vk_...")
data = client.list_series()

API reference

All GET unless noted · CORS open · auth anon unless marked. openapi.json

Catalog

GET/v1/seriesList series; filter domain / country / qanonTry ▸
GET/v1/series/{id}One series' metadataanon

Generic observations

GET/v1/observationsCited read of any series; series_id | series_prefix, from, to, as_ofanon

Typed reads

GET/v1/ftElectricity Ft; period, customer_classanonTry ▸
GET/v1/oilOil price structure; date, fuel_gradeanonTry ▸
GET/v1/fxFX rates; currency, rate_type, dateanon
GET/v1/macroMacro indicator; indicatoranon

Lineage

GET/v1/observations/{id}/lineageFull provenance chain to the raw artifactanon

Ops

GET/healthLivenessanon
GET/health/readyReadiness; 503 if DB downanon
GET/metricsPrometheus metricsanonTry ▸
GET/v1/freshnessPer-series freshness vs cadenceanonTry ▸
GET/v1/residencyDeclarative data-residency disclosureanon

Enterprise

GET/v1/exportsList bulk Parquet snapshotsanon
GET/v1/exports/{id}/downloadSigned download URLkey required
POST/v1/webhooksSubscribe to signed eventskey required
GET/v1/auditYour audit trailscoped

Spec

GET/openapi.jsonMachine-readable OpenAPIanon

MCP for agents

Agents discover the catalog and read cited values directly — no scraping.

Remote MCP server endpoint
POST https://veracle-mcp.chaiyaphum.workers.dev/mcp
# dev: http://localhost:8788/mcp
8 tools · REST analogue
list_series/v1/series
get_series/v1/series/{id}
get_observations/v1/observations
get_ft_tariff/v1/ft
get_oil_price_structure/v1/oil
get_fx_rates/v1/fx
get_macro_indicators/v1/macro
get_freshness/v1/freshness
Add to your MCP client

Pick your client, then paste the config. Claude Desktop has no native remote transport, so it uses the mcp-remote bridge.

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

Ground an agent

Paste these into an agent's system prompt so it cites Veracle and uses point-in-time as_of correctly.

System prompt — always cite

When you use a figure from Veracle, quote its `citation` string verbatim and never state a number without it. If unsure, call get_observations / get_ft_tariff and read the citation field before answering.

Verify with as_of (point-in-time)

To answer 'what was X as reported on DATE', call get_observations(series_id, as_of=DATE). Revisions are append-only and bitemporal, so as_of reconstructs exactly what was known on that date — use it to avoid quoting a value that was only reported later.

Ground a tariff lookup

User asks for the electricity Ft tariff. Call get_ft_tariff(period, customer_class); return value + unit + the human-readable citation, and offer source_doc_uri so the user can verify the original document.

Auth & tiers

Limits only — every tier returns identical data and identical citations.

anonnone (by IP)60 / min
freeX-API-Key: vk_…600 / min
proAuthorization: Bearer (OAuth)6000 / min
Response headers on every call
X-Veracle-TierX-RateLimit-LimitX-RateLimit-RemainingX-CacheX-Veracle-ResidencyX-Request-Id

Citations & lineage

Anatomy of a cited datapoint

{
  "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; derived series expand into the input observations they were computed from. Trace any live datapoint in the Explorer →

SDKs

TypeScript

$ npm i @veracle/sdk

import { VeracleClient } from "@veracle/sdk";
const client = new VeracleClient({ baseUrl, apiKey: "vk_…" });
const ft = await client.getFtTariffs({ period: "2025-01" });

Python

$ pip install veracle

from veracle_sdk import VeracleClient
with VeracleClient(base_url=base, api_key="vk_…") as client:
    ft = client.get_ft_tariffs(period="2025-01")

FAQ

Is this real data?

No — synthetic demo fixtures today. Real ERC / EPPO / BOT sources are gated on licensing. The plumbing, citations and lineage are fully real.

Where is data stored? (residency)

Declarative, software-level: every response carries X-Veracle-Residency: TH:asia-southeast1; full disclosure at GET /v1/residency.

What happens to a bad value?

It is quarantined and never published — trust over coverage.

Are forecasts trustworthy?

They are clearly-labelled OLS estimates with a confidence band — not observations.

Do I need an account to start?

No — anonymous works at 60 req/min. Add an API key for the free tier (600/min); same data.