greencalculus-com Factors API

Emission-factor lookup and browse

Operations 4

GET /v1/health Service health #
GET /v1/factors/{key} Resolve one factor by canonical key (value + full provenance) #
GET /v1/factors/{key}/history Version history — what this factor has been #
GET /v1/factors Browse/search the corpus (open — no key, values included) #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/greencalculus-com:greencalculus-com-factors-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

greencalculus-com-factors-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: GreenCalculus Factors API
  version: v1
  description: 'Sourced greenhouse-gas emission factors and audit-traced carbon calculations. Every value returns with its exact source reference and data version — reproducible and citable. Free key at https://greencalculus.com/developers/.


    SCOPE: this document describes every endpoint we publish a callable example for — the data, calculation, discovery and watch endpoints. It deliberately excludes the control plane behind greencalculus.com (billing, sign-in, key management, admin), which is not a customer contract and is free to change, and /v1/account/webhook, whose configuration is session-only by design and therefore cannot be exercised with the bearer token this document describes. Those exclusions are enumerated and enforced by scripts/check-openapi-drift.mjs, so an endpoint is absent here because it was excluded, never because it was forgotten.'
  contact:
    name: GreenCalculus
    url: https://greencalculus.com/developers/
    email: jeremiah@greencalculus.com
  license:
    name: Attribution required except on Enterprise
    url: https://greencalculus.com/developers/docs/#attribution
servers:
- url: https://api.greencalculus.com
  description: Production
security:
- bearerAuth: []
tags:
- name: Factors
  description: Emission-factor lookup and browse
paths:
  /v1/health:
    get:
      tags:
      - Factors
      summary: Service health
      security: []
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Health'
      operationId: getV1Health
      x-operation-id-source: derived
  /v1/factors/{key}:
    get:
      tags:
      - Factors
      summary: Resolve one factor by canonical key (value + full provenance)
      parameters:
      - name: key
        in: path
        required: true
        schema:
          type: string
        example: grid.gbr.electricity.location_based
      - name: as_of
        in: query
        required: false
        schema:
          type: string
          example: '2026.175'
        description: 'Serve this factor as it stood at an ARCHIVED data version. On a hit you get the archived row, served_version is the version you asked for, and version_pin reports matched: true, reproducible: true. Two misses, and they behave differently. (1) The version is NOT in the archive: 200 carrying the CURRENT row, with version_pin.matched: false naming as_of_requested and listing every archived version available — unlike POST /v1/calculate/*?as_of=, which 400s instead. So read version_pin before treating a response as pinned; do not infer it from the status code. (2) The version IS archived but holds no row for this key — it did not exist yet, or was withdrawn at or before it: 404 not_found, naming the key and the version, and saying whether the key is in the CURRENT corpus so a real absence is distinguishable from a mistyped key. GET /v1/factors/{key}/history lists every version that recorded it. Case (2) returned 200 with the current value in a browse envelope until 2026-09-10; it now refuses, because serving a current value under a past version label is the one answer this endpoint must never give.'
      security:
      - bearerAuth: []
      responses:
        '200':
          description: Factor with value, source id, source reference, data version
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FactorLookup'
        '401':
          description: Missing/invalid key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Unknown key, or a key with no row at the requested ?as_of= version
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FactorMiss'
      operationId: getV1FactorsByKey
      x-operation-id-source: derived
  /v1/factors/{key}/history:
    get:
      tags:
      - Factors
      summary: Version history — what this factor has been
      description: Every version the reproducibility archive holds for one key, with the value each version served and whether it was a change or a withdrawal. Derived from the same per-key archive index and the same read that answers ?as_of=, so it cannot disagree with the archive. Requires a key (any tier). History begins at the delta watershed; a short list means a stable factor, and the payload says so.
      parameters:
      - name: key
        in: path
        required: true
        schema:
          type: string
        example: grid.gbr.electricity.location_based
      responses:
        '200':
          description: Current row + per-version history entries
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FactorHistory'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Key unknown to both the corpus and the archive
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      operationId: getV1FactorsByKeyHistory
      x-operation-id-source: derived
  /v1/factors:
    get:
      tags:
      - Factors
      summary: Browse/search the corpus (open — no key, values included)
      parameters:
      - name: search
        in: query
        schema:
          type: string
        example: UK electricity
        description: Free text. Every whitespace-separated word must appear in the row name or canonical key (dots/underscores/hyphens read as separators, so a pasted canonical key finds its own row). Results are relevance-ranked.
      - name: section
        in: query
        schema:
          type: string
        example: grid
      - name: key_prefix
        in: query
        schema:
          type: string
        example: grid.gbr
        description: Anchors at the START of the dotted key — "electricity" matches nothing; use search for words appearing anywhere.
      - name: family
        in: query
        schema:
          type: string
        example: grid-electricity
        description: Taxonomy family slug (hyphenated). An unknown value returns 200 with an empty result and the valid families listed in meta.warnings.
      - name: limit
        in: query
        schema:
          type: integer
          default: 100
          maximum: 500
      - name: offset
        in: query
        schema:
          type: integer
      - name: cursor
        in: query
        schema:
          type: string
        description: base64(canonical_key) from meta.next_cursor. Preferred over offset — stable across data-version bumps, and required for paging relevance-ordered search results.
      security: []
      responses:
        '200':
          description: Matching factor keys, names, sections. meta.warnings explains any filter that matched nothing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FactorList'
        '400':
          description: 'gc_unknown_param — a query parameter this endpoint does not accept. The message names the offender and lists the accepted set. Other 400s: gc_limit_too_large, gc_offset_invalid, gc_cursor_invalid, gc_section_conflict.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      operationId: getV1Factors
      x-operation-id-source: derived
components:
  schemas:
    Error:
      type: object
      description: The single error envelope, on every non-2xx response from every endpoint. Stated on /developers/docs and enforced at the gateway for origin-raised errors too — read the code from error.code.
      required:
      - error
      additionalProperties: true
      properties:
        error:
          type: object
          required:
          - code
          - message
          additionalProperties: true
          properties:
            code:
              type: string
              description: 'Stable machine-readable code. Transport-level: unauthorized, forbidden_tier, not_found, rate_limited, quota_exceeded, overage_cap_reached, busy, origin_unavailable, invalid_request. Validation codes are namespaced gc_* and named per endpoint (gc_unknown_param, gc_limit_too_large, gc_offset_invalid, gc_cursor_invalid, gc_section_conflict, and the per-engine gc_<engine>_* set).'
              example: gc_unknown_param
            message:
              type: string
              description: Human-readable and specific — a 4xx names the offending parameter and lists the accepted set.
              example: 'Unknown query parameter: bogus. This endpoint accepts: offset, cursor, limit, section, key_prefix, family, search. Free-text lookup is ?search=.'
            docs:
              type: string
              format: uri
              example: https://greencalculus.com/developers/docs/#errors
            details:
              type: object
              additionalProperties: true
              description: Present only when the failing endpoint attached structured detail beyond the HTTP status.
    SourceRef:
      type: object
      description: Provenance to the line. Carried on 100% of rows — where in the source document the value was read, not just which document. A workbook cell where the publisher ships a workbook (DEFRA); otherwise the table, annex clause or page they did ship (IPCC, CBAM, ECCC).
      additionalProperties: true
      properties:
        id:
          type: string
          example: DEFRA_2026
        cell_ref:
          type: string
          example: '''UK electricity''!E25'
        retrieved:
          type: string
          format: date
          example: '2026-06-18'
    FactorList:
      type: object
      description: Browse/search results. Open — no key, no quota. Values ARE returned on this route. Use /v1/factors/{key} when you want one row plus its audit envelope (provenance, licence, verification) or a version pin via ?as_of=.
      required:
      - meta
      - factors
      additionalProperties: true
      properties:
        meta:
          type: object
          additionalProperties: true
          properties:
            gc_version:
              type: string
              example: '2026.180'
            gc_updated:
              type: string
              format: date
              example: '2026-08-19'
            total:
              type: integer
              description: Rows matching the filter.
              example: 82
            canonical_total:
              type: integer
              description: Rows in the whole corpus at this version.
              example: 16554
            returned:
              type: integer
            offset:
              type: integer
            next_cursor:
              type:
              - string
              - 'null'
              description: base64(canonical_key). Prefer this over offset — stable across data-version bumps, and required to page relevance-ordered search results.
            filters:
              type: object
              additionalProperties: true
              description: The filters as the endpoint understood them — echoed back so a silent mismatch is visible.
            warnings:
              type: array
              items:
                type: string
              description: Why a filter matched nothing. A 200 with an empty array and a warning is the normal way this endpoint says "no such thing".
            licences:
              type: object
              description: One record per DISTINCT source on this page, keyed by source id — so the licence detail is carried once rather than repeated on every row. Join via factors[].source.id. `attribution` is present ONLY where the licence grants redistribution and requires a credit; its absence on a non-redistributable row is deliberate.
              additionalProperties:
                type: object
                additionalProperties: true
                properties:
                  name:
                    type: string
                  redistributable:
                    type: boolean
                  basis:
                    type:
                    - string
                    - 'null'
                  publisher:
                    type:
                    - string
                    - 'null'
                  url:
                    type:
                    - string
                    - 'null'
                  attribution:
                    type: string
        factors:
          type: array
          items:
            $ref: '#/components/schemas/FactorRow'
    FactorCitation:
      type: object
      description: 'The canonical citation for one factor row, built by the API (src/citation.ts) and printed VERBATIM by every official client (Sheets add-in, JS and Python SDKs, MCP). Format: "<factor name>. <source name> — <publisher>, cell <cell_ref>, retrieved <date>. via GreenCalculus data version <version>, factor <key>. <proof URL>". On GET /v1/factors/{key} the version is the one actually SERVED, so a ?as_of= lookup cites the pin. Present on rows from 2026-09-09. The format is a published specification, free for anyone to implement against their own data: https://greencalculus.com/developers/citation/'
      externalDocs:
        description: The factor citation specification
        url: https://greencalculus.com/developers/citation/
      additionalProperties: true
      properties:
        text:
          type: string
          example: UK grid electricity — location-based (generation). UK Government GHG Conversion Factors 2026 — Department for Energy Security and Net Zero (DESNZ), cell 'UK electricity'!E25, retrieved 2026-06-18. via GreenCalculus data version 2026.186, factor grid.gbr.electricity.location_based. https://verify.greencalculus.com/grid.gbr.electricity.location_based@2026.186
        source_id:
          type:
          - string
          - 'null'
          example: DEFRA_2026
        cell_ref:
          type:
          - string
          - 'null'
          example: '''UK electricity''!E25'
        version:
          type:
          - string
          - 'null'
          example: '2026.186'
        proof_url:
          type:
          - string
          - 'null'
          example: https://verify.greencalculus.com/grid.gbr.electricity.location_based@2026.186
    ProofUrls:
      type: array
      items:
        type: string
      description: Every factor used by this answer, as a public proof URL pinned to the data version. A portfolio calculation may list many; cite per line from here. Contains no request data — each URL is a fact about the GreenCalculus corpus and is identical for every caller.
    Attribution:
      type:
      - object
      - 'null'
      description: The credit the licence requires, or null on a plan that waives it. Was a bare STRING before 2026-08-25; the original string is preserved unchanged at `text`. `html` is a ready-to-paste anchor so that complying is less work than not complying, and `url` points at the public proof page for the exact factor and data version this answer used — your own audit evidence, not a marketing link.
      properties:
        text:
          type: string
          description: The plain credit line. Identical to the string this field used to be.
        html:
          type: string
          description: A single anchor, no classes and no styling, ready to paste.
        url:
          type:
          - string
          - 'null'
          description: 'Proof page for the factor this answer used, pinned to the data version — e.g. https://verify.greencalculus.com/grid.gbr.electricity.location_based@2026.181. Null where no single factor identifies the answer. The version is deliberate: an unversioned link would silently re-point at whatever the figure becomes.'
        required:
          type: boolean
          description: Whether this plan must display the credit. Reports the licence position, not a technical control.
    Uncertainty:
      type:
      - object
      - 'null'
      additionalProperties: true
      description: The publisher's own stated range, never derived by us. null means NOT RECORDED — explicitly not a claim that no uncertainty exists.
      properties:
        low:
          type:
          - number
          - 'null'
        high:
          type:
          - number
          - 'null'
        basis:
          type:
          - string
          - 'null'
          example: published
        published_as:
          type:
          - string
          - 'null'
          description: The publisher's exact wording, e.g. "±30-50%".
    FactorRow:
      type: object
      description: 'One corpus row as returned by browse/search. Carries the full row INCLUDING factor.value — the browse endpoint is open and unmetered by design, because our data is overwhelmingly open-licensed at source and gating it would make this API worse than the original publisher. What a paid plan adds is the right to REDISTRIBUTE, not the ability to read. (Note: the MCP search_factors tool DOES project rows down to key/name/section — that projection is deliberate and specific to that tool.)'
      additionalProperties: true
      properties:
        key:
          type: string
          example: grid.gbr.electricity.location_based
        name:
          type:
          - string
          - 'null'
        section:
          type:
          - string
          - 'null'
          example: grid
        activity_type:
          type:
          - string
          - 'null'
          example: purchased_energy
        factor:
          type: object
          additionalProperties: true
          properties:
            value:
              type:
              - number
              - 'null'
            unit:
              type:
              - string
              - 'null'
              example: kg CO2e per kWh
            gas:
              type:
              - string
              - 'null'
              example: CO2e
            basis:
              type:
              - string
              - 'null'
            gwp_set:
              type:
              - string
              - 'null'
              example: AR5_100
            gwp_set_basis:
              type:
              - string
              - 'null'
              description: How we know the GWP set — "published" where the source states it, "inferred" where we deduced it. null means not recorded, which is deliberately NOT the same as published.
            country_iso3:
              type:
              - string
              - 'null'
              example: gbr
            uncertainty:
              $ref: '#/components/schemas/Uncertainty'
            uncertainty_basis:
              type:
              - string
              - 'null'
              description: '"none_published" means the publisher states plainly that no range exists. null means not recorded — a different fact from silence.'
        source:
          $ref: '#/components/schemas/SourceRef'
        scope:
          type:
          - object
          - 'null'
          additionalProperties: true
          properties:
            ghg_protocol:
              type:
              - string
              - 'null'
              example: scope2
            category:
              type:
              - string
              - 'null'
        components:
          type:
          - object
          - 'null'
          description: Per-gas decomposition keyed by gas (co2, ch4, n2o…), each with its own cell_ref. Lets a consumer re-base AR5↔AR6 without us.
          additionalProperties:
            type: object
            additionalProperties: true
        note:
          type:
          - string
          - 'null'
          description: Includes what the publisher did NOT provide, stated verbatim.
        citation:
          $ref: '#/components/schemas/FactorCitation'
        licence:
          type: object
          additionalProperties: true
          description: 'The licence this row is published under, and whether the Business redistribution grant covers it. Present on the open browse from MB v2026.181 — the full terms, the required credit and the publisher are listed once per source under meta.licences. Absent (not empty) where no licence is on record: an empty value would read as "no licence applies".'
          properties:
            name:
              type: string
              example: Open Government Licence v3.0
            redistributable:
              type: boolean
    Verification:
      type: object
      description: What was actually checked — computed at serve time, not asserted.
      additionalProperties: true
      properties:
        components_sum_to_value:
          type:
          - boolean
          - 'null'
          description: Whether the per-gas components sum to the headline. null where the row carries no components — the absence of a check is not a failed check.
        gwp_set:
          type:
          - string
          - 'null'
        gwp_set_basis:
          type:
          - string
          - 'null'
        uncertainty:
          $ref: '#/components/schemas/Uncertainty'
        uncertainty_basis:
          type:
          - string
          - 'null'
        source_note:
          type:
          - string
          - 'null'
    FactorHistory:
      type: object
      additionalProperties: true
      properties:
        key:
          type: string
        current:
          type:
          - object
          - 'null'
          additionalProperties: true
          description: null when the key is withdrawn from the live corpus.
        history:
          type: array
          items:
            type: object
            additionalProperties: true
            properties:
              version:
                type: string
              date:
                type:
                - string
                - 'null'
              value:
                type:
                - number
                - 'null'
              unit:
                type:
                - string
                - 'null'
              kind:
                type: string
                enum:
                - recorded
                - withdrawn
        meta:
          type: object
          additionalProperties: true
    FactorLookup:
      type: object
      description: One factor with its value and the full audit envelope. Served from the edge KV store.
      additionalProperties: true
      properties:
        meta:
          type: object
          additionalProperties: true
        value:
          type:
          - number
          - 'null'
          description: Convenience top-level copy of factor.factor.value.
        unit:
          type:
          - string
          - 'null'
        gas:
          type:
          - string
          - 'null'
        factor:
          $ref: '#/components/schemas/FactorRow'
          description: The full row. Its `citation` is built at served_version, so a pinned lookup cites the pin.
        provenance:
          $ref: '#/components/schemas/Provenance'
        verification:
          $ref: '#/components/schemas/Verification'
        served_from:
          type: string
          example: edge
        served_version:
          type: string
          example: '2026.180'
        version_pin:
          type: object
          additionalProperties: true
          description: 'Present only when ?as_of= was sent — and not even then if the key did not exist at an archived version you asked for, which falls back to the browse envelope instead. `matched: false` means the requested version is not in the archive and the CURRENT value was served — check it before treating a response as pinned.'
        attribution:
          $ref: '#/components/schemas/Attribution'
        proof_urls:
          $ref: '#/components/schemas/ProofUrls'
    FactorMiss:
      type: object
      description: A key that does not exist. Carries candidate keys rather than a bare 404 — most misses are a naming difference, not a coverage gap. The documented error envelope is present alongside the bespoke fields.
      additionalProperties: true
      properties:
        error:
          $ref: '#/components/schemas/Error'
        found:
          type: boolean
          example: false
        requested_key:
          type: string
        reason:
          type: string
        suggestions:
          type: array
          items:
            type: object
            additionalProperties: true
            properties:
              key:
                type: string
              name:
                type:
                - string
                - 'null'
              section:
                type:
                - string
                - 'null'
        docs:
          type: string
          format: uri
    Provenance:
      type: object
      description: Where the number came from and whether you may republish it. Built from the source registry — src/envelope.ts.
      additionalProperties: true
      properties:
        source_id:
          type:
          - string
          - 'null'
        source_name:
          type:
          - string
          - 'null'
        publisher:
          type:
          - string
          - 'null'
          description: The organisation, in one spelling (MB `publisher`).
        issuer:
          type: string
          description: The issuing descriptor of this edition (MB `body`), present only when it differs from publisher.
        url:
          type:
          - string
          - 'null'
        cell_ref:
          type:
          - string
          - 'null'
        retrieved:
          type:
          - string
          - 'null'
          format: date
        licence:
          type:
          - string
          - 'null'
        redistributable:
          type:
          - boolean
          - 'null'
          description: Whether the Business redistribution grant covers this row. Fails closed — a source whose licence has not been assessed is false, not null.
        redistributable_basis:
          type:
          - string
          - 'null'
        update_cadence:
          type:
          - string
          - 'null'
        overrides_source:
          type: object
          description: Present only when this row carries a licence its source does not (a publisher republishing third-party data under its own terms, e.g. CBAM Annex II). licence, redistributable and redistributable_basis above are then the ROW's; this block keeps the source's own answer beside them.
          properties:
            source_redistributable:
              type:
              - boolean
              - 'null'
            since:
              type:
              - string
              - 'null'
              description: Data version at which the row-level answer was recorded.
            attribution_required:
              type:
              - string
              - 'null'
            source_ref:
              type:
              - string
              - 'null'
              description: Where the restricting text was read.
    Health:
      type: object
      additionalProperties: true
      properties:
        ok:
          type: boolean
        status:
          type: string
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Your API key, e.g. "Bearer gc_live_…". Get one free at https://greencalculus.com/developers/.
externalDocs:
  description: The factor citation specification — the line that travels with every number
  url: https://greencalculus.com/developers/citation/