{
  "components": {
    "schemas": {
      "IndexDocument": {
        "properties": {
          "attribution": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Attribution credits each source a pair's sources name. The default\nfeed body leaves most credits out and points here instead.",
            "type": "object"
          },
          "count": {
            "type": "integer"
          },
          "coverage_profile": {
            "type": "string"
          },
          "derivation": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "derived_count": {
            "type": "integer"
          },
          "filters": {
            "$ref": "#/components/schemas/IndexFilters"
          },
          "native_count": {
            "type": "integer"
          },
          "pairs": {
            "items": {
              "$ref": "#/components/schemas/IndexEntry"
            },
            "type": "array"
          },
          "quotes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "IndexEntry": {
        "properties": {
          "base": {
            "type": "string"
          },
          "class": {
            "type": "string"
          },
          "delisted": {
            "type": "boolean"
          },
          "history_start": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "pair": {
            "type": "string"
          },
          "quote": {
            "type": "string"
          },
          "sources": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "tier1": {
            "type": "boolean"
          },
          "url": {
            "type": "string"
          },
          "via": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "IndexFilters": {
        "properties": {
          "base": {
            "type": "string"
          },
          "class": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "quote": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "OptionsCounts": {
        "properties": {
          "bases": {
            "type": "integer"
          },
          "pairs": {
            "type": "integer"
          },
          "quotes": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "OptionsDocument": {
        "properties": {
          "attribution": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Attribution credits each source by the name the index's sources use.",
            "type": "object"
          },
          "counts": {
            "$ref": "#/components/schemas/OptionsCounts"
          },
          "coverage_profile": {
            "type": "string"
          },
          "delisted": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "derivation": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "generated_at": {
            "type": "string"
          },
          "groups": {
            "items": {
              "$ref": "#/components/schemas/OptionsGroup"
            },
            "type": "array"
          },
          "quote_sets": {
            "items": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "type": "array"
          },
          "quotes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "support": {
            "$ref": "#/components/schemas/OptionsSupport"
          },
          "url_template": {
            "description": "URLTemplate builds one pair's feed URL: substitute base and quote. It\npoints at the include host.",
            "type": "string"
          }
        },
        "type": "object"
      },
      "OptionsGroup": {
        "properties": {
          "bases": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "class": {
            "type": "string"
          },
          "quote_set": {
            "type": "integer"
          },
          "tier1": {
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "OptionsSupport": {
        "properties": {
          "absence_means": {
            "description": "AbsenceMeans is \"unknown\" — never \"unsupported\".",
            "type": "string"
          },
          "on_request": {
            "description": "OnRequest names what resolves without being enumerated.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "probe": {
            "description": "Probe is how to settle one case, since only the server can.",
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerToken": {
        "description": "A token for the include host, sent as `Authorization: Bearer \u003ctoken\u003e`.",
        "scheme": "bearer",
        "type": "http"
      },
      "sessionCookie": {
        "description": "The session cookie a browser holds after signing in to the include host.",
        "in": "cookie",
        "name": "authSess:beancount.io",
        "type": "apiKey"
      }
    }
  },
  "info": {
    "contact": {
      "email": "dev@stargately.com",
      "name": "BlockEden Support",
      "url": "https://blockeden.xyz"
    },
    "description": "Daily close prices published as Beancount price includes.\n`GET /prices` is the index of available pairs, `GET /prices/options.json` the\ncompact bases and quotes to combine, and `GET /prices/{pair}` one pair's price\ndirectives. On the include host the options document and this description are\npublic; the index and the pair documents need a signed-in session or an\n`Authorization` token, and answer a request without one with a redirect to the\nlogin page.",
    "license": {
      "name": "MIT",
      "url": "https://opensource.org/licenses/MIT"
    },
    "title": "BlockEden Crypto Price API",
    "version": "1.0"
  },
  "openapi": "3.0.3",
  "paths": {
    "/prices": {
      "get": {
        "description": "Returns the catalog of Beancount price includes. Each entry links to its\n`/prices/{pair}` document. `format=text` (or `Accept: text/plain`) returns one\nabsolute URL per line instead of JSON. Bodies carry a strong `ETag`,\n`Cache-Control: public, max-age=3600` and `Last-Modified`, and are gzipped when\nlarge and the client accepts it. Needs a signed-in session or an `Authorization`\ntoken; without one the include host redirects to its login page.",
        "parameters": [
          {
            "description": "Filter to one base commodity (case-insensitive), e.g. BTC",
            "in": "query",
            "name": "base",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Filter to one quote currency (case-insensitive), e.g. USD",
            "in": "query",
            "name": "quote",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Filter to one asset class",
            "in": "query",
            "name": "class",
            "schema": {
              "enum": [
                "crypto",
                "fiat",
                "equity"
              ],
              "type": "string"
            }
          },
          {
            "description": "Which pairs to include (default native)",
            "in": "query",
            "name": "kind",
            "schema": {
              "enum": [
                "native",
                "derived",
                "all"
              ],
              "type": "string"
            }
          },
          {
            "description": "Response format; text returns a plain URL list",
            "in": "query",
            "name": "format",
            "schema": {
              "enum": [
                "text"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IndexDocument"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Index document, or a URL list when format=text"
          },
          "302": {
            "description": "No valid session or token: the include host redirects to its login page",
            "headers": {
              "Location": {
                "description": "The include host's login page, with the requested path in `next`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "304": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Unchanged since the If-None-Match ETag or the If-Modified-Since date"
          },
          "400": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "class is not crypto, fiat, or equity, kind is not native, derived, or all, or format is not text"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "No pairs match the requested base"
          },
          "412": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "If-Match names no current strong ETag, or the document changed after If-Unmodified-Since"
          },
          "503": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Price catalog not loaded yet"
          }
        },
        "security": [
          {
            "bearerToken": []
          },
          {
            "sessionCookie": []
          }
        ],
        "summary": "List the price pairs this feed publishes",
        "tags": [
          "prices"
        ]
      },
      "head": {
        "description": "Returns the catalog of Beancount price includes. Each entry links to its\n`/prices/{pair}` document. `format=text` (or `Accept: text/plain`) returns one\nabsolute URL per line instead of JSON. Bodies carry a strong `ETag`,\n`Cache-Control: public, max-age=3600` and `Last-Modified`, and are gzipped when\nlarge and the client accepts it. Needs a signed-in session or an `Authorization`\ntoken; without one the include host redirects to its login page.",
        "parameters": [
          {
            "description": "Filter to one base commodity (case-insensitive), e.g. BTC",
            "in": "query",
            "name": "base",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Filter to one quote currency (case-insensitive), e.g. USD",
            "in": "query",
            "name": "quote",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Filter to one asset class",
            "in": "query",
            "name": "class",
            "schema": {
              "enum": [
                "crypto",
                "fiat",
                "equity"
              ],
              "type": "string"
            }
          },
          {
            "description": "Which pairs to include (default native)",
            "in": "query",
            "name": "kind",
            "schema": {
              "enum": [
                "native",
                "derived",
                "all"
              ],
              "type": "string"
            }
          },
          {
            "description": "Response format; text returns a plain URL list",
            "in": "query",
            "name": "format",
            "schema": {
              "enum": [
                "text"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Index document, or a URL list when format=text"
          },
          "302": {
            "description": "No valid session or token: the include host redirects to its login page",
            "headers": {
              "Location": {
                "description": "The include host's login page, with the requested path in `next`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the If-None-Match ETag or the If-Modified-Since date"
          },
          "400": {
            "description": "class is not crypto, fiat, or equity, kind is not native, derived, or all, or format is not text"
          },
          "404": {
            "description": "No pairs match the requested base"
          },
          "412": {
            "description": "If-Match names no current strong ETag, or the document changed after If-Unmodified-Since"
          },
          "503": {
            "description": "Price catalog not loaded yet"
          }
        },
        "security": [
          {
            "bearerToken": []
          },
          {
            "sessionCookie": []
          }
        ],
        "summary": "List the price pairs this feed publishes (headers only)",
        "tags": [
          "prices"
        ]
      }
    },
    "/prices/options.json": {
      "get": {
        "description": "The pair universe as dimensions instead of the cross product: each group holds\nthe bases sharing one class, tier, and quote set, and its `quote_set` indexes\n`quote_sets`. Expanding every base against its quote set yields exactly the pairs\n`GET /prices?kind=all` lists, in about a hundredth of the bytes, so a page can load\nthe whole catalog at once and let a reader pick any pair. Build each URL from\n`url_template`. Non-tier-1 equities are enumerated against USD only; their other\nquotes still derive on request. The body carries a strong `ETag`,\n`Cache-Control: public, max-age=3600` and `Last-Modified`, and is gzipped when the\nclient accepts it. No authentication.",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptionsDocument"
                }
              }
            },
            "description": "Every base and quote the feed publishes"
          },
          "304": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Unchanged since the If-None-Match ETag or the If-Modified-Since date"
          },
          "412": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "If-Match names no current strong ETag, or the document changed after If-Unmodified-Since"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Price catalog not loaded yet"
          }
        },
        "summary": "List the bases and quotes that combine into a pair",
        "tags": [
          "prices"
        ]
      },
      "head": {
        "description": "The pair universe as dimensions instead of the cross product: each group holds\nthe bases sharing one class, tier, and quote set, and its `quote_set` indexes\n`quote_sets`. Expanding every base against its quote set yields exactly the pairs\n`GET /prices?kind=all` lists, in about a hundredth of the bytes, so a page can load\nthe whole catalog at once and let a reader pick any pair. Build each URL from\n`url_template`. Non-tier-1 equities are enumerated against USD only; their other\nquotes still derive on request. The body carries a strong `ETag`,\n`Cache-Control: public, max-age=3600` and `Last-Modified`, and is gzipped when the\nclient accepts it. No authentication.",
        "responses": {
          "200": {
            "description": "Every base and quote the feed publishes"
          },
          "304": {
            "description": "Unchanged since the If-None-Match ETag or the If-Modified-Since date"
          },
          "412": {
            "description": "If-Match names no current strong ETag, or the document changed after If-Unmodified-Since"
          },
          "503": {
            "description": "Price catalog not loaded yet"
          }
        },
        "summary": "List the bases and quotes that combine into a pair (headers only)",
        "tags": [
          "prices"
        ]
      }
    },
    "/prices/{pair}": {
      "get": {
        "description": "Returns `YYYY-MM-DD price COMMODITY \u003cprice\u003e QUOTE` directives. The default body opens\nwith one summary comment (pair, first and last date, provisional or delisted state,\nsampling rule), plus a `; data:` credit for a source that must be credited\nin the body. Directives carry only what changes how a price reads: `provisional: TRUE`,\n`observed-at` on the provisional spot, `price-source` on rows from another source\nthan the pair's own, a non-close `price-kind`, `adjusted: FALSE` for equities, and\n`price-kind`, `via`, `legs`, `observed-at` and a differing `leg-observed-at` for\nderived pairs. Source credits are in the `/prices` index\n`attribution`. `meta=full` returns every header line (alias, sources, attribution,\ncoverage profile, history start, revision) and every directive field.\n`pair` is matched in order: an exact catalog alias (including compat aliases such\nas `BTCUSD`), then a base the index lists (`BTC`, `BRK-B`, `USD`), which returns\nthe `/prices` index filtered to that base and honours the same quote, class, kind\nand format query parameters, then `BASE-QUOTE` split on the **last** hyphen so\n`BRK-B-USD` means base `BRK-B` (derived by inverse, fx-reference, or one pivot\ncross). When that split cannot resolve, the one other hyphen that yields two\nresolvable commodities is used (`USD-BRK-B`); several such splits stay a 404.\nBodies carry a strong `ETag` and `Cache-Control: public, max-age=60`.\nA throttled cold fill answers 429 with `Retry-After`. Needs a signed-in session\nor an `Authorization` token; without one the include host redirects to its login page.",
        "parameters": [
          {
            "description": "Catalog alias, BASE-QUOTE pair, or a bare base commodity",
            "in": "path",
            "name": "pair",
            "required": true,
            "schema": {
              "example": "BTC-USD",
              "type": "string"
            }
          },
          {
            "description": "full returns every header line and directive field; any other value is a 400",
            "in": "query",
            "name": "meta",
            "schema": {
              "enum": [
                "full"
              ],
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: filter the index to one quote currency",
            "in": "query",
            "name": "quote",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: filter the index to one asset class",
            "in": "query",
            "name": "class",
            "schema": {
              "enum": [
                "crypto",
                "fiat",
                "equity"
              ],
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: which pairs to include",
            "in": "query",
            "name": "kind",
            "schema": {
              "enum": [
                "native",
                "derived",
                "all"
              ],
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: text returns a plain URL list",
            "in": "query",
            "name": "format",
            "schema": {
              "enum": [
                "text"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IndexDocument"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Beancount price directives (text), or the filtered index when pair is a bare base (JSON, or a URL list with format=text)"
          },
          "302": {
            "description": "No valid session or token: the include host redirects to its login page",
            "headers": {
              "Location": {
                "description": "The include host's login page, with the requested path in `next`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "304": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Body unchanged since the If-None-Match ETag"
          },
          "400": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Missing price pair, a meta value other than full, or for a bare base an invalid class or kind or a format other than text"
          },
          "404": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Unknown alias or pair, or a pair that cannot be derived yet"
          },
          "412": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "If-Match names no current strong ETag"
          },
          "429": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Cold history fill throttled for this client; see Retry-After"
          },
          "503": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Catalog not loaded, or price history not ready"
          }
        },
        "security": [
          {
            "bearerToken": []
          },
          {
            "sessionCookie": []
          }
        ],
        "summary": "Fetch one pair as a Beancount price include",
        "tags": [
          "prices"
        ]
      },
      "head": {
        "description": "Returns `YYYY-MM-DD price COMMODITY \u003cprice\u003e QUOTE` directives. The default body opens\nwith one summary comment (pair, first and last date, provisional or delisted state,\nsampling rule), plus a `; data:` credit for a source that must be credited\nin the body. Directives carry only what changes how a price reads: `provisional: TRUE`,\n`observed-at` on the provisional spot, `price-source` on rows from another source\nthan the pair's own, a non-close `price-kind`, `adjusted: FALSE` for equities, and\n`price-kind`, `via`, `legs`, `observed-at` and a differing `leg-observed-at` for\nderived pairs. Source credits are in the `/prices` index\n`attribution`. `meta=full` returns every header line (alias, sources, attribution,\ncoverage profile, history start, revision) and every directive field.\n`pair` is matched in order: an exact catalog alias (including compat aliases such\nas `BTCUSD`), then a base the index lists (`BTC`, `BRK-B`, `USD`), which returns\nthe `/prices` index filtered to that base and honours the same quote, class, kind\nand format query parameters, then `BASE-QUOTE` split on the **last** hyphen so\n`BRK-B-USD` means base `BRK-B` (derived by inverse, fx-reference, or one pivot\ncross). When that split cannot resolve, the one other hyphen that yields two\nresolvable commodities is used (`USD-BRK-B`); several such splits stay a 404.\nBodies carry a strong `ETag` and `Cache-Control: public, max-age=60`.\nA throttled cold fill answers 429 with `Retry-After`. Needs a signed-in session\nor an `Authorization` token; without one the include host redirects to its login page.",
        "parameters": [
          {
            "description": "Catalog alias, BASE-QUOTE pair, or a bare base commodity",
            "in": "path",
            "name": "pair",
            "required": true,
            "schema": {
              "example": "BTC-USD",
              "type": "string"
            }
          },
          {
            "description": "full returns every header line and directive field; any other value is a 400",
            "in": "query",
            "name": "meta",
            "schema": {
              "enum": [
                "full"
              ],
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: filter the index to one quote currency",
            "in": "query",
            "name": "quote",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: filter the index to one asset class",
            "in": "query",
            "name": "class",
            "schema": {
              "enum": [
                "crypto",
                "fiat",
                "equity"
              ],
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: which pairs to include",
            "in": "query",
            "name": "kind",
            "schema": {
              "enum": [
                "native",
                "derived",
                "all"
              ],
              "type": "string"
            }
          },
          {
            "description": "Only when pair is a bare base: text returns a plain URL list",
            "in": "query",
            "name": "format",
            "schema": {
              "enum": [
                "text"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Beancount price directives (text), or the filtered index when pair is a bare base (JSON, or a URL list with format=text)"
          },
          "302": {
            "description": "No valid session or token: the include host redirects to its login page",
            "headers": {
              "Location": {
                "description": "The include host's login page, with the requested path in `next`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "304": {
            "description": "Body unchanged since the If-None-Match ETag"
          },
          "400": {
            "description": "Missing price pair, a meta value other than full, or for a bare base an invalid class or kind or a format other than text"
          },
          "404": {
            "description": "Unknown alias or pair, or a pair that cannot be derived yet"
          },
          "412": {
            "description": "If-Match names no current strong ETag"
          },
          "429": {
            "description": "Cold history fill throttled for this client; see Retry-After"
          },
          "503": {
            "description": "Catalog not loaded, or price history not ready"
          }
        },
        "security": [
          {
            "bearerToken": []
          },
          {
            "sessionCookie": []
          }
        ],
        "summary": "Fetch one pair as a Beancount price include (headers only)",
        "tags": [
          "prices"
        ]
      }
    }
  },
  "servers": [
    {
      "url": "https://beancount.io"
    }
  ]
}
