Documentation

Methodology Graph is a live, typed graph of every standard, calculator, factor table, framework, and registry that climate accounting runs on. Each methodology is exposed as a callable endpoint with full provenance. This page covers the mental model, quickstart, full REST reference, and the MCP server for AI agents.

What this API gives you#

One HTTPS endpoint to call any climate calculation, query any factor table, walk any framework's dependency graph, or audit any registry. The graph is parsed from primary sources (PDFs, HTML, XML, JSON, RSS feeds), version tracked, dependency mapped, and kept current by an autonomous review loop. Free for individual use with a one-minute email signup.

Three surfaces, same data:

Get a free API key

Every call needs an API key. Free tier gives you 600 requests/minute, takes 60 seconds to set up via email magic link. Sign up here. A public demo key exists (300 requests/minute, suitable for browsing and exploration).

Quickstart#

Five minutes from zero to a working calculation. The example below calculates the lifecycle CO2e abatement of a sustainable aviation fuel shipment, using only the inputs a shipper would actually have. The API resolves the carbon intensity factor from the ICAO default LCA table automatically.

1. List the methodologies in the graph

$ curl · LIST
curl https://api.methodology.energyweb.org/v1/methodologies?limit=5

{
  "data": [
    { "id": "icao-corsia-lca", "name": "ICAO CORSIA LCA", "layer": 3, ... },
    { "id": "ipcc-gwp", "name": "IPCC GWP", "layer": 1, ... },
    ...
  ],
  "count": 5
}

2. Inspect a specific methodology's calculation schema

$ curl · SCHEMA
curl https://api.methodology.energyweb.org/v1/methodologies/icao-corsia-lca/schema

{
  "methodology_id": "icao-corsia-lca",
  "methodology_version": "Eighth Edition, November 2025",
  "input_schema": {
    "type": "object",
    "required": ["baseline_ci", "saf_ci", "lhv", "units"],
    "properties": {
      "baseline_ci": { "type": "number", "description": "Baseline jet fuel CI, gCO2e/MJ" },
      "saf_ci": { "type": "number", "description": "SAF carbon intensity, gCO2e/MJ" },
      "lhv": { "type": "number", "description": "Lower heating value, MJ/kg" },
      "units": { "type": "number", "description": "Quantity in tonnes" },
      "pathway": { "type": "string", "description": "SAF pathway, auto-resolves saf_ci if provided" }
    }
  },
  "output_schema": { "properties": { "co2e_abated_tonnes": { "type": "number" } } },
  "formula_spec": {
    "type": "arithmetic",
    "outputs": [{
      "key": "co2e_abated_tonnes",
      "formula": "((baseline_ci - saf_ci) / 1000000) * (lhv * 1000) * units",
      "unit": "tCO2e"
    }]
  }
}

3. Call the calculation

Notice that saf_ci is not passed explicitly. The engine pulls it from the ICAO default LCA dataset using pathway as the lookup key.

$ curl · CALCULATE
curl -X POST https://api.methodology.energyweb.org/v1/calculate/icao-corsia-lca \
  -H "content-type: application/json" \
  -d '{
    "inputs": {
      "pathway": "HEFA-UCO",
      "lhv": 44,
      "units": 234.765,
      "baseline_ci": 89
    }
  }'

{
  "methodology_id": "icao-corsia-lca",
  "version": "Eighth Edition, November 2025",
  "result": {
    "co2e_abated_tonnes": 775.757,
    "co2e_abated_tonnes_unit": "tCO2e"
  },
  "provenance": {
    "formula": "((baseline_ci - saf_ci) / 1000000) * (lhv * 1000) * units",
    "inputs_used": { "pathway": "HEFA-UCO", "saf_ci": 13.9, "lhv": 44, ... },
    "standard_reference": "ICAO Annex 16 Vol IV",
    "resolved_from_datasets": {
      "saf_ci": {
        "dataset": "icao-corsia-lca",
        "key": "HEFA-UCO",
        "field": "core_lsf_value",
        "value": 13.9,
        "impl_id": "icao-corsia-saf-default-lca-v1"
      }
    }
  },
  "computed_at": "2026-05-14T10:30:00.000Z"
}

That's the entire integration loop. You passed four inputs, got back the answer (775.757 tCO2e abated), the formula text, the version, and the exact factor value the engine substituted for you with its citation.

What just happened

The engine looked up your pathway = "HEFA-UCO" in the ICAO Annex 16 Appendix 3 default LCA table, found core_lsf_value = 13.9, plugged it in as saf_ci, then evaluated the formula. Without this auto-resolution, you would have to fetch and maintain the ICAO default LCA table yourself.

4. Call a composition (umbrella with parts)

Some standards (EU RED III, ISO 14067, GHG Protocol Product) define a calculation as an umbrella plus a list of named components. Inspect the umbrella's structure with GET /v1/compositions/:id, then POST to /v1/calculate/:id to run it. Pass the components you have; the engine resolves the rest from their sub-methodologies, defaulting missing optional components to 0.

$ curl · COMPOSITION
curl -X POST https://api.methodology.energyweb.org/v1/calculate/eu-red3 \
  -H "content-type: application/json" \
  -d '{
    "inputs": {
      "e_ec": 12.5,
      "e_l":  0.0,
      "e_p":  8.4,
      "e_td": 1.2,
      "e_u":  0.0
    }
  }'

{
  "methodology_id": "eu-red3",
  "result": { "composition_value": 22.1 },
  "provenance": {
    "composition": {
      "final_formula": "e_ec + e_l + e_p + e_td + e_u - e_sca - e_ccs - e_ccr",
      "resolved_components": {
        "e_ec": { "value": 12.5, "from": "input" },
        "e_l":  { "value": 0, "from": "input" },
        "e_p":  { "value": 8.4, "from": "input" },
        "e_td": { "value": 1.2, "from": "input" },
        "e_u":  { "value": 0, "from": "input" },
        "e_sca": { "value": 0, "from": "default_optional" },
        "e_ccs": { "value": 0, "from": "default_optional" },
        "e_ccr": { "value": 0, "from": "default_optional" }
      }
    },
    "standard_reference": "Directive (EU) 2023/2413, Annex V Part C"
  }
}

You passed five of the eight components; the engine defaulted the three optional subtractors to 0 and surfaced that in the trace. Each component (eu-red3-cultivation, eu-red3-processing, and the others) is also a methodology on its own, callable at /v1/calculate/eu-red3-cultivation etc., with its own input schema.

The graph model#

Every methodology is a node. Every dependency between methodologies is a typed edge. Layers reflect where each methodology sits in the global standards stack, from layer 1 (constitutional standards like IPCC, ISO 14064) up to layer 7 (compliance regimes like EU CBAM).

Edges between methodologies are typed: references, extends, requires, implements, supersedes. The full edge graph drives the cascade: when IPCC GWP updates, every downstream methodology that references GWP is flagged for re-evaluation automatically.

Five kinds of methodology#

The formula_type column on every methodology tells you what kind it is and which URL space it lives under:

KindURL spaceWhat it is
formula /v1/calculate/:id An executable math expression or boolean rule. Pass inputs, get a result.
dataset /v1/lookup/:id A factor lookup table. Pass a key, get a value (or a row).
composition /v1/calculate/:id plus /v1/compositions/:id An umbrella methodology that decomposes into named components, each itself a methodology. POST the umbrella to run it; GET the compositions endpoint for the structural metadata.
framework /v1/frameworks/:id Governance, guidance, or disclosure principles. Read-only, no calculation.
registry /v1/registries/:id A credit or certificate issuance ledger. Detail endpoint lists consumers.

Methodologies of every kind also appear under /v1/methodologies/:id, which returns the bare graph node. The kind-specific endpoints add the right contract on top (calculate inputs, lookup keys, composition structure, framework dependencies, registry consumers).

A note on sub-methodologies: a composition's components are real methodologies, with their own id, schema, and version. They carry is_component: 1 on the methodology row and are filtered out of headline lists like /v1/methodologies by default. Pass ?include_components=true to see them, or look up any component by id directly.

Dataset auto-resolution#

A formula can declare that one of its inputs is sourced from a dataset. When a caller invokes the formula without that input, the engine resolves it for them. The mechanism uses the dependencies array on the formula spec:

formula_spec.dependencies
{
  "type": "arithmetic",
  "outputs": [...],
  "dependencies": [{
    "input": "saf_ci",            // the variable to populate
    "dataset": "icao-corsia-lca", // methodology_id of the source dataset
    "package": "icao-corsia-saf-default-lca-v1", // optional pin
    "key_from": "pathway",        // which user input holds the lookup key
    "value_field": "core_lsf_value", // which field on the row to use
    "optional": true             // if user passes saf_ci explicitly, skip lookup
  }]
}

If the caller passes saf_ci explicitly, the lookup is skipped (because optional: true). If they don't, but they pass pathway, the engine looks up the matching row in the ICAO dataset, pulls core_lsf_value, and stores it. The response's provenance.resolved_from_datasets block discloses every substitution.

Composition and component resolution#

Some climate standards do not define a single calculation. They define an umbrella plus a list of named components, each of which is its own calculation. EU RED III's lifecycle GHG, ISO 14067's product carbon footprint, and the GHG Protocol Product Standard's life-cycle inventory are all shaped this way. These are compositions. The umbrella is a methodology of kind composition; each component is a methodology in its own right, with is_component: 1 set on its row and a typed imports edge pointing at it from the umbrella with predicate component:<symbol>.

A composition's formula_spec declares a final_formula (e.g. e_ec + e_l + e_p + e_td + e_u - e_sca - e_ccs - e_ccr) and a components array. Each component carries a symbol (the variable name in the final formula), a description, an expected_sub_kind, and a sub_methodology_id pointing at the child:

formula_spec for kind = composition
{
  "type": "composition",
  "final_formula": "e_ec + e_l + e_p + e_td + e_u - e_sca - e_ccs - e_ccr",
  "components": [
    {
      "symbol": "e_ec",
      "description": "Emissions from feedstock cultivation",
      "expected_sub_kind": "formula",
      "sub_methodology_id": "eu-red3-cultivation"
    },
    // e_l, e_p, e_td, e_u, e_sca, e_ccs, e_ccr...
  ]
}

When a caller POSTs to /v1/calculate/:umbrella_id, the composition runner resolves each symbol in order:

  1. If the caller provided a value directly under inputs, that value is used. The trace marks it from: "input".
  2. Otherwise, if the component has a sub_methodology_id pointing at a methodology with a live executable implementation, the engine recursively calls that sub-methodology and uses its result. The trace marks it from: "sub_methodology" and records which sub-methodology supplied the value.
  3. Otherwise, if the symbol is in input_schema.properties but NOT in input_schema.required, the engine defaults the value to 0. The trace marks it from: "default_optional".
  4. Otherwise (the symbol IS required and could not be resolved), the runner returns a 422 listing every unresolved symbol and refuses to compute a result.

The recursion has a depth cap (5 by default) so a malformed extraction cannot loop. Optional defaults are only applied when input_schema.required is declared as an array; if the schema does not declare a required list, the engine falls back to strict mode (every symbol must come from input or sub-methodology).

The metadata endpoint GET /v1/compositions/:id returns the components list with each one annotated by is_required (from the umbrella's input_schema) and sub_methodology_live (whether the referenced sub-methodology has a live executable implementation today). Useful for clients that want to render the umbrella's structure without making a calculate call.

Edge provenance: how dependencies are grounded#

Every dependency edge in the graph carries its own provenance, so a reader can always see why an edge exists and what it rests on. An edge is grounded in one of three ways. These are three different kinds of grounding, presented as equal. None is a ranking above the others, and none implies the others are unverified.

Each edge also carries an origin (one of author_declared, parser_hardcoded, model_inferred, migration_audit, structural_inferred, composition, operator), a one-line rationale, a status_label naming the basis above with a one-sentence status_text, and a source pointer. The source pointer always includes the publisher_url (a link to the publisher's own page). It includes a cached_url to our stored snapshot only when the source's license permits redistribution, because serving the snapshot is redistributing the publisher's document.

These fields appear on every edge returned by the dependency endpoints, the dependency tree, and the MCP tools, and they drive the "why this edge exists" panel in the viewer.

Provenance#

Every successful calculate response carries:

This is enough metadata to replay the same call years later and get bit-identical results, assuming the version is still available. Methodology versions are immutable; new versions get new identifiers.

Versions and cascades#

Each methodology has a current_version string. Calling /v1/calculate/:id uses the current live version. Calling /v1/calculate/:id/:version pins to a specific version (useful for audit replay).

When a methodology's version bumps, the cascade walks every edge in the dependency graph and flags every downstream methodology as requires re-evaluation. This is published as a revision event in /v1/revisions/recent, so consumers can subscribe to changes and decide when to migrate.

API base & auth#

Base URL for all REST endpoints:

https://api.methodology.energyweb.org/v1/

Authentication

Every /v1/* request requires an API key. Send it as the X-API-Key header (or Authorization: Bearer if you prefer the OAuth convention):

Auth header
curl https://api.methodology.energyweb.org/v1/methodologies \
  -H "X-API-Key: vcc_mg_..."

Getting a key. Three tiers:

TierRate limitHow to get one
demo300 requests / minute *Shared public key demo-key-public-2026. Used by the viewer and API explorer by default, with no signup required. Suitable for browsing and exploration. Both surfaces switch to your personal key automatically once you sign up.
free600 requests / minuteSign up with email. One key per email. Magic-link confirmation, no password. Manage at /account.
enterpriseCustom (admin-issued)For partner integrations. Email methodology@energyweb.org.

* The demo key's 300 req/min cap applies to programmatic callers (scripts, server-side code, external clients). Calls made from our own viewer and API explorer pages bypass the per-key cap because the browser's Origin header marks them as same-origin to the API host. The per-IP cap below still applies in both cases.

The single exception: GET /v1/health requires no key, so uptime probes work without authentication. GET /v1/stats is also unauthenticated for the marketing page.

Rate limits

Per-key, per-minute, sliding window. When you exceed your quota the API returns 429 rate_limited with a Retry-After header and a JSON body that includes retry_after_seconds:

429 response
HTTP/1.1 429 Too Many Requests
Retry-After: 23
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "You hit your per-minute limit (600). Retry in 23s.",
    "retry_after_seconds": 23,
    "details": {
      "limit": 600,
      "used": 600,
      "window_seconds": 60,
      "tier": "free"
    }
  }
}

A secondary per-IP limit (1200 req/min) sits in front of the key check to slow brute-force key-guessing. In practice you will not see it unless you share an IP with many other callers or you're making unauthenticated requests at high volume.

Response envelope

List responses always return { "data": [...], "count": N }. Single-resource responses return the resource object directly. Errors always return:

Error envelope
{
  "error": {
    "code": "validation_failed",
    "message": "Provide an inputs object in the request body",
    "details": { ... optional ... }
  }
}

Error codes are documented in the Errors section below.

Versioning

The API itself is versioned under the URL path. Today's version is v1. Breaking changes will introduce v2; v1 remains supported for a deprecation window of at least 12 months.

Methodologies#

The core resource. Every node in the graph is a methodology. Use these endpoints to browse the registry, fetch detail, and walk dependencies.

List methodologies

GET /v1/methodologies

Query parameters

NameTypeDescription
layerintegerFilter by layer (1 to 7).
jurisdictionstringFilter by jurisdiction code (e.g. EU, US, GLOBAL).
limitintegerMax results to return, default 200, max 1000.
offsetintegerSkip results, default 0.

Get a methodology

GET /v1/methodologies/:id

Returns the full graph node, including name, layer, modality, jurisdiction, current_version, formula_type, vcc_status, scope, and timestamps.

List versions

GET /v1/methodologies/:id/versions

Returns every version of a methodology, ordered newest to oldest. Each version has an immutable identifier, an effective date, and a source content reference.

Recent revisions

GET /v1/methodologies/:id/revisions

Audit log of every revision event for a methodology (version bumps, status changes, dependency updates). Useful for change tracking.

Dependencies

GET /v1/methodologies/:id/dependencies

Upstream and downstream edges in one response. upstream lists methodologies this one depends on; downstream lists methodologies that depend on this one.

Each edge carries its full provenance (see Edge provenance for what each basis means):

FieldTypeDescription
from_methodology_id / to_methodology_idstringThe two endpoints of the edge.
edge_typestringThe relationship, e.g. imports, uses_factor, references, supersedes.
predicatestringThe specific thing the dependency is for, e.g. "woody biomass carbon stock estimation".
rationalestringOne-line statement of why the edge exists.
status_labelstringHow the edge is grounded: Source-checked, Extracted, or Structural. Three equally legitimate kinds of grounding, not a ranking.
status_textstringOne sentence expanding the label for a reader.
confidence_bandstring or nullHigh, Medium, or Low. Present only for Source-checked edges; null otherwise.
evidence_phrasestring or nullThe exact sentence from the source that states the dependency, when the pipeline captured one (Extracted edges). null when no single passage was pinned.
originstringOne of author_declared, parser_hardcoded, model_inferred, migration_audit, structural_inferred, composition, operator.
sourceobjectsource_id, publisher_url (always present), and cached_url (our stored snapshot, present only when the source license permits redistribution; null otherwise).

The dependency tree at /v1/methodologies/:id/tree and the MCP tools return edges in the same shape.

Get a methodology's schema

GET /v1/methodologies/:id/schema

Returns the live implementation's input_schema, output_schema, formula_spec, and standard_reference. Use this to discover what inputs a calculator expects before calling it.

Calculate#

Execute a methodology's formula. Pass the inputs the schema requires, get the result with full provenance metadata.

List calculators

GET /v1/calculate

Returns every methodology with a live, callable implementation. Each entry includes the implementation id, version, status, and schema summary.

List extraction candidates

GET /v1/calculate/candidates

Methodologies that have a formula in the published standard but no live implementation yet. Useful for tracking pipeline coverage.

Get calculator metadata

GET /v1/calculate/:methodology_id

Returns every implementation for one methodology, with input and output schemas.

Run a calculation

POST /v1/calculate/:methodology_id

Request body

FieldTypeDescription
inputsrequiredobjectObject containing all required inputs from the methodology's input_schema. Optional inputs may be omitted; declared dataset dependencies may also be omitted if the lookup key is provided.

Response

FieldTypeDescription
methodology_idstringEcho of the requested methodology.
versionstringMethodology version that ran.
impl_idstringImplementation identifier.
resultobjectOutput values keyed per output_schema. Numbers rounded to 3 decimals. Each output may be accompanied by a _unit sibling.
provenanceobjectFormula text, inputs used, standard reference, resolved dataset values.
vcc_receiptobjectVerified Compute receipt if available, null otherwise.
computed_atstringISO 8601 UTC timestamp.

Run pinned to a specific version

POST /v1/calculate/:methodology_id/:version

Identical to the unpinned variant, but executes against the named version instead of the current live version. Use this for audit replay and version-locked integrations.

Lookup#

Query dataset-type methodologies. Each dataset is a key-value lookup table, optionally with multiple value fields per row.

List datasets

GET /v1/lookup

Returns every methodology with formula_type = dataset, including those without a populated lookup table yet.

Get dataset metadata

GET /v1/lookup/:methodology_id

Returns implementation metadata: the key field, the available value fields, row count, and three sample rows. Does not return the full table.

List keys

GET /v1/lookup/:methodology_id/keys

Returns the available key values for a dataset, plus one suggested_key. Useful for clients that want to prefill a lookup form with a key that will hit a real row.

Query parameters

NameTypeDescription
limitintegerMax keys to return, default 50, max 500.

Get the full table

GET /v1/lookup/:methodology_id/table

Returns every row in the live lookup table for a dataset.

Query parameters

NameTypeDescription
limitintegerMax rows to return, default 500, max 5000.
offsetintegerSkip rows, default 0.

Look up a key

GET /v1/lookup/:methodology_id/key?key=...&field=...
POST /v1/lookup/:methodology_id

POST body shape:

FieldTypeDescription
keyrequiredstringThe value to look up. Matched against the dataset's key_field.
fieldstringOptional. Return only this field from the matching row. Omit to return the whole row.
Example: IPCC GWP100 for methane
curl -X POST https://api.methodology.energyweb.org/v1/lookup/ipcc-gwp \
  -H "content-type: application/json" \
  -d '{"key": "CH4", "field": "gwp_100"}'

{
  "methodology_id": "ipcc-gwp",
  "version": "AR6 WG1 (2021)",
  "result": { "gwp_100": 29.8 },
  "provenance": {
    "key_field": "gas",
    "standard_reference": "IPCC AR6 WG1, Chapter 7, Table 7.15"
  }
}

Frameworks#

Governance and disclosure frameworks with no calculation logic. Useful for understanding the regulatory context around calculators that implement them.

List frameworks

GET /v1/frameworks

Query parameters

NameTypeDescription
layerintegerFilter by layer.
jurisdictionstringFilter by jurisdiction.
limitintegerMax results, default 200.

Get framework detail

GET /v1/frameworks/:methodology_id

Returns four blocks. framework is the bare graph node. impl is the live framework method package, including its standard reference and critic confidence. content carries the extracted structure: purpose, scope, audience, sections (each with a title and a summary), key_definitions (each with a term and a definition), and references. upstream and downstream list every methodology connected by an edge.

Registries#

Credit and certificate issuance registries that other methodologies depend on.

List registries

GET /v1/registries

Get registry detail

GET /v1/registries/:methodology_id

Returns four blocks. registry is the bare graph node. impl is the live registry method package. metadata carries the registry profile: issuer, jurisdiction, governance_body, accepted_credit_types, accepted_methodologies, public_portal_url, has_public_api, ledger_access, scope_summary. consumers lists every methodology that depends on this registry.

Compositions#

Umbrella methodologies that decompose into named components. The metadata endpoint described here returns the structural view. To actually run a composition, POST to /v1/calculate/:id with the umbrella's id.

List compositions

GET /v1/compositions

Returns every methodology with formula_type = composition.

Get composition detail

GET /v1/compositions/:methodology_id

Returns the structural view of an umbrella. The response carries:

Example: inspect EU RED III
curl https://api.methodology.energyweb.org/v1/compositions/eu-red3 \
  -H "X-API-Key: vcc_mg_..."

{
  "composition": { "id": "eu-red3", "name": "EU RED III", ... },
  "impl": { "impl_id": "eu-red3-composition-...", "status": "live", ... },
  "final_formula": "e_ec + e_l + e_p + e_td + e_u - e_sca - e_ccs - e_ccr",
  "components": [
    { "symbol": "e_ec", "sub_methodology_id": "eu-red3-cultivation", "is_required": true, "sub_methodology_live": false },
    // ...
  ],
  "required_symbols": ["e_ec", "e_l", "e_p", "e_td", "e_u"],
  "component_edges": [...]
}

Impacts & dependency trees#

Traverse the graph by edge relationships, not just by methodology.

Get impacts

GET /v1/impacts?upstream=X
GET /v1/impacts?downstream=Y

Walk upstream or downstream from a given methodology. Useful for change-impact analysis (e.g. "what breaks if IPCC GWP updates"). Requires a personal API key. The shared demo key is not accepted from external callers on this endpoint; sign up for a free key (email only, no credit card) at /signup.

Layer matrix

GET /v1/impacts/layer-matrix

Returns edge-count aggregates between each pair of layers (1 through 7). Up to 49 rows. Use for chord and sankey diagrams that show the topology shape without enumerating individual edges. Public, demo-key accessible.

Centrality leaderboard

GET /v1/impacts/centrality

Returns the top methodologies ranked by total degree (inbound + outbound edges). Each row has the methodology id, name, layer, and the inbound and outbound counts. Default 50, max 500. Public, demo-key accessible. Useful for finding the most-depended-on methodologies (the gravity wells of the graph).

All edges (enterprise)

GET /v1/impacts/edges/all

Returns every edge in the graph with both endpoints' layers pre-joined. Restricted to enterprise-tier keys. Responses include a watermark _meta.export_token for traceability. For most use cases, the layer matrix and centrality endpoints above provide the same insight without exposing individual edges. Contact methodology@energyweb.org for enterprise access.

Dependency tree

GET /v1/dependency-tree/:methodology_id

Returns the full upstream-plus-downstream dependency tree for one methodology, up to depth 3 in each direction, capped at 500 nodes total. Public, demo-key accessible. Subject to per-IP scrape detection: fetching more than 100 distinct methodologies in a 5-minute window from one IP triggers a temporary 1-request-per-second throttle. Sign up for a free key to bypass the demo restrictions on related endpoints.

Sources#

The primary documents the pipeline crawls and parses. One source can produce many methodologies (e.g. a single ICAO Annex document defines multiple calculators and a default LCA table).

List sources

GET /v1/sources

Returns every active source, with publisher, content type, last fetched time, and the methodologies it produced.

Get a source

GET /v1/sources/:id

Returns full detail for one source: publisher, URL, jurisdiction, fetch cadence, last fetched at, current status, and the methodologies it produces.

Source snapshots

GET /v1/sources/:id/snapshots

Every archived snapshot the pipeline has taken of a source, ordered newest to oldest. Each entry includes the content hash, fetch timestamp, and snapshot storage reference.

Revisions#

The audit log of every meaningful change in the graph: methodology version bumps, status transitions, dataset re-extractions, dependency edge updates. Useful for change-tracking integrations and webhook fan-out.

Recent revisions

GET /v1/revisions/recent

The 50 most recent revision events across the entire registry, ordered newest first. Each entry includes the methodology id, revision kind (version_bump, status_change, schema_change, dataset_update), the from and to values, and the timestamp.

List revisions

GET /v1/revisions

Paginated list of every revision event. Supports limit and offset for pagination. For methodology-scoped revisions use /v1/methodologies/:id/revisions instead.

Stats#

A public snapshot of headline counts across the registry. Useful for dashboards, status pages, and any integration that wants to show "how big is the graph today" without crawling every endpoint.

Get stats

GET /v1/stats

The only /v1/* endpoint that does not require an API key, since it returns only aggregate counts and no individual records. Cached server-side for 60 seconds.

Example response
{
  "as_of": "2026-05-16T17:00:00Z",
  "cached": true,
  "methodologies": {
    "total": 412,
    "by_type": {
      "formula": 198,
      "dataset": 22,
      "framework": 96,
      "registry": 14
    }
  },
  "calculators": { "live": 111, "beta": 5, "deprecated": 2 },
  "sources":     { "total": 312, "active": 296 },
  "graph":       { "edges": 568, "revisions": 1284 },
  "factor_sets": { "loaded": 42, "rows_total": 8915 },
  "discovery":   { "seeds_active": 87, "parser_templates": 31 }
}

Errors#

All errors return a unified JSON envelope with an HTTP status that matches the code:

Error response shape
{
  "error": {
    "code":    "rate_limited",
    "message": "Human-readable summary.",
    "details": { ... optional structured detail ... },
    "retry_after_seconds": 60
  }
}

The retry_after_seconds field is only set on rate_limited and service_unavailable, and is mirrored to the HTTP Retry-After header so off-the-shelf retry libraries pick it up automatically.

Statuserror codeMeaning
400bad_requestRequest body could not be parsed as JSON, or is malformed.
400validation_failedRequired fields are missing or invalid. details often includes an example showing the expected shape.
401unauthorizedMissing, unknown, or revoked API key. Visit /signup for a key, /account to manage an existing one.
403forbiddenAuthentication succeeded but the resource is not accessible to this key's tier or scopes.
404not_foundPath, methodology, lookup key, or version does not exist. The message states which.
405method_not_allowedThe endpoint exists but does not accept this HTTP verb.
409conflictThe action conflicts with current state (for example, signing up with an email that already has a key).
410goneA token or link has expired or already been used.
413payload_too_largeRequest body exceeds 64 KB.
429rate_limitedPer-key or per-IP rate limit exceeded. Honour Retry-After.
500internal_errorServer-side bug or transient failure. Safe to retry with backoff.
503service_unavailableAn upstream dependency (D1, Resend, etc.) is degraded. Retry with backoff.

Some calculation-specific responses return additional fields inside details:

MCP server overview#

An MCP server exposing the entire Methodology Graph as typed tools. Designed for LLM clients that speak the Model Context Protocol: Claude (web, desktop, mobile), Cursor, custom ChatGPT integrations, or any agent runtime with MCP support.

https://mcp.methodology.energyweb.org

Once connected, the agent can ask questions like:

The server replies with structured tool calls that return JSON the agent can reason about, including the same provenance metadata as the REST API.

Connecting an MCP client#

Two flows. Consumer clients (Claude on web, desktop, mobile) authenticate via OAuth, taking about a minute. Programmatic clients use a Bearer API key, the same one the REST API uses.

Claude (web, desktop, mobile)

One-click OAuth flow. No config files, no API keys to paste.

  1. Open Settings → Connectors (or visit claude.ai/customize/connectors).
  2. Click the + button next to Connectors. Pick a name (for example, Methodology Graph) and paste:
    MCP server URL
    https://mcp.methodology.energyweb.org
    Leave the Advanced settings empty. Click Add.
  3. Click Connect. A new tab opens to a Methodology Graph consent page. Enter your email, click Send confirmation link.
  4. Open the email titled Confirm Claude connection to Methodology Graph and click Confirm connection. Your browser briefly lands on Methodology Graph then redirects back to Claude. You are connected.

The connection mints a new API key tied to your email under the hood. You can revoke it any time at /account (look for a key named MCP: ... (your-email)). Re-connecting from a new device or after revocation issues a new key. The same email can hold multiple MCP connections at once (one per client: Claude web, Claude desktop, Cursor, and so on).

If you are on a Claude Team or Enterprise plan, an admin can add the connector at the organization level so it appears in every member's connectors list automatically. Each member still completes their own OAuth flow; tokens are per-user by design.

Claude Desktop (manual config, legacy)

If you prefer the legacy config-file path, edit Claude Desktop's config and paste your existing REST API key as a Bearer token. The OAuth flow above is recommended instead because it manages token rotation and per-device revocation automatically.

~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "methodology-graph": {
      "url": "https://mcp.methodology.energyweb.org",
      "headers": {
        "Authorization": "Bearer vcc_mg_..."
      }
    }
  }
}

Get a key at /signup (email magic link, 60 seconds, no credit card). Restart Claude Desktop after editing.

Programmatic clients (Cursor, agent frameworks, custom)

Any MCP-compatible client can connect by pointing at the server URL above with a Bearer token in the Authorization header:

MCP auth header
Authorization: Bearer vcc_mg_...

Get a key the same way as the REST API: /signup. Free tier (600 req/min) is enough for typical agent workflows. For high-volume integrations, request an enterprise key at methodology@energyweb.org.

The server speaks the MCP 2025-06-18 Streamable HTTP transport. POST JSON-RPC 2.0 messages to the server root. The handshake is:

MCP handshake (JSON-RPC over HTTP)
POST https://mcp.methodology.energyweb.org/
Authorization: Bearer vcc_mg_...
Content-Type: application/json

{"jsonrpc":"2.0","method":"initialize","id":1}

Followed by tools/list to discover available tools, and tools/call to invoke one. See the MCP specification at modelcontextprotocol.io for the full protocol.

Available MCP tools#

Tool nameWhat it does
search_methodologiesSemantic search across the registry. Returns the top matches with similarity scores.
get_methodologyFetch full detail for one methodology including version, schema, dependencies.
list_methodologiesFilter the registry by layer, jurisdiction, or formula type.
calculateRun a calculator with inputs. Returns result plus full provenance.
lookup_datasetQuery a dataset lookup table by key.
get_frameworkRead a framework's metadata plus dependency context.
get_registryRead a registry's metadata plus consumer list.
dependency_treeWalk upstream and downstream from a methodology.
which_rules_applyFind which methodologies apply to a company given what it does. Provide an activity code (ISIC, NACE, or NAICS), optionally narrowed by jurisdiction and regime (V/R/B). Returns the grounded set of rules that govern that activity, each with its applicability and an importance signal, mandatory rules first. The primary tool for onboarding a claimant: it answers "which rules apply to me".
get_applicabilityGet the applicability of one methodology: the activities it governs, the actor role it applies to, conditions, exclusions, and the basis (stated in source vs provisional), each grounded to a source. Use after get_methodology to explain who a rule applies to.
get_reportingGet the reporting requirement for one methodology: the format, where it is submitted, whether third-party verification is required and of what, and the filing cadence, grounded to a source. Answers "how do I report this".
recent_revisionsList the most recent change events across the registry.
list_sourcesList all source entities (regulators, standards bodies, registries, dataset publishers) with license disposition. Use to answer "who is behind X" or "which sources permit commercial reuse".
get_sourceFetch one source entity with optional full license chain including attribution template. Use to answer "can I use this dataset commercially".
planCompose a content-addressed Verification Plan from a natural-language company description. Picks the right methodologies, frameworks, and factor sources for the target regimes and jurisdictions. Useful when an agent does not yet know which calculator to call.
replayRe-fetch a previously composed Plan by its content identifier. Returns the plan structure; re-executing a plan's results is a separate step.
attestProduce a signed attestation over a plan execution. Returns a Verified Compute receipt that an auditor can verify offline against the published standard. Currently in beta and available to allowlisted enterprise keys.

Every tool returns the same structured data shape as the REST API, with the same provenance metadata. The MCP server is a transport wrapper, not a separate data model.

Webhooks#

Subscribe to events emitted by the autonomous pipeline. Today's primary event is plan.published, fired when a Verification Plan is composed or republished. Future events include methodology.revised, calculator.promoted, and calculator.deprecated; subscribers receive these automatically when they ship.

Creating a webhook

Webhooks are managed in the admin Settings UI by users with admin access. For enterprise customers, Energy Web staff can create webhooks on your behalf. Contact methodology@energyweb.org for a webhook registration. You will receive back a webhook id and a one-time-displayed secret of the form whsec_... that you'll need to verify deliveries.

Delivery contract

The pipeline POSTs each event to your endpoint as JSON with three control headers:

HeaderValue
content-typeapplication/json
x-ew-mg-eventEvent name, currently always plan.published.
x-ew-mg-delivery-idUUID. Use as your idempotency key.
x-ew-mg-signaturesha256=<hex>, HMAC-SHA256 of the raw request body using your webhook secret.
Example body: plan.published
{
  "event": "plan.published",
  "plan_cid": "bafy2bzaceabc...xyz",
  "reason": "revision-cascade",
  "affected_methodology_ids": ["ipcc-gwp", "verra-vm0007"],
  "emitted_at": "2026-05-19T15:08:42.117Z"
}

Verifying signatures

Every request is signed with HMAC-SHA256 using your webhook's secret. To verify, compute the HMAC over the raw request body (not the parsed object) and compare to the value in x-ew-mg-signature after the sha256= prefix. Use a constant-time comparison.

Node.js verification
import crypto from 'node:crypto';

function verify(rawBody, signatureHeader, secret) {
  const [scheme, hex] = signatureHeader.split('=');
  if (scheme !== 'sha256') return false;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(hex, 'hex'),
    Buffer.from(expected, 'hex')
  );
}

Idempotency and retries

Each delivery carries a unique x-ew-mg-delivery-id. We dedup on the worker side too: a successful delivery of a given (webhook, plan_cid, reason) tuple is recorded for 30 days, and repeats are silently dropped at the source. You should still implement your own idempotency check using the delivery id, because edge cases (worker restart between dedup write and ack) can produce duplicates.

We treat any non-2xx response as a failure. The current implementation does not retry per-webhook (a single failure increments your failure_count; sustained failures result in your endpoint being disabled). A future revision will move per-webhook retry into a separate queue with exponential backoff for partners that require at-least-once with retry.

Best practices

Support#

For bug reports, feature requests, integration questions, or to discuss enterprise tier access, reach out at methodology@energyweb.org.

For partnership conversations (custom calculators, priority extraction, Verified Compute receipts, audit firm pilots), contact Energy Web directly.