# Philippine Data Explorer API and MCP

> Public, read-only access to saved PSA OpenSTAT statistics through an independent BetterGov.ph project. No API key is required.

## Entry points

- REST base: https://statistics.bettergov.ph/api/v1
- [OpenAPI specification](https://statistics.bettergov.ph/api/v1/openapi.json)
- [Coverage and query limits](https://statistics.bettergov.ph/api/v1/coverage)
- MCP endpoint: https://statistics.bettergov.ph/mcp (Streamable HTTP, not standalone SSE)
- [HTML documentation](https://statistics.bettergov.ph/api)

## Discover a dataset

GET /topics returns exact topic names and counts. GET /datasets accepts q, topic, ready=true or false, sort, limit (1–200) and offset (zero-based). Results match all search words against titles, source paths and topics. Responses put results in data and pagination in pagination. Follow pagination.nextOffset until null.

Sort values: recommended, title-asc, title-desc, size-asc, size-desc, year-asc, year-desc, updated-asc, updated-desc. The browser-only folder parameter is not accepted by the REST API.

Example: https://statistics.bettergov.ph/api/v1/datasets?q=palay&ready=true&limit=5

GET /datasets/{id} returns provenance, dimensions, the current release and a sampleQuery. Obtain IDs from search results. A dataset can be cataloged without having an available explorer; only complete published snapshots support observation queries.

## Query observations

GET /datasets/{id}/values requires dimension and release, and accepts q, limit and offset. Results contain source codes and labels. Keep codes as strings, including leading zeros, and URL-encode parameters.

POST /datasets/{id}/query accepts application/json with release and selection. Selection maps every dimension code to a nonempty array of allowed source codes. Use the metadata's sampleQuery for a bounded first request:

~~~javascript
const base = 'https://statistics.bettergov.ph/api/v1';
async function read(path, options) {
  const response = await fetch(base + path, options);
  const body = await response.json();
  if (!response.ok) throw new Error(body.error.message);
  return body;
}
const matches = await read('/datasets?q=palay&ready=true&limit=1');
if (!matches.data.length) throw new Error('No available snapshot.');
const { data: dataset } = await read('/datasets/' + matches.data[0].id);
const result = await read('/datasets/' + dataset.id + '/query', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(dataset.sampleQuery)
});
console.log(result.data);
~~~

To export CSV, send the same POST body to /datasets/{id}/query?format=csv and read the response as text. It contains exactly the selected observations and provenance. This is not a URL for downloading the entire dataset.

## Limits and failures

- At most 5,000 selected points, 64 matching chunks and 32 MiB of decompressed source data per query.
- JSON request bodies are limited to 64 KiB. Duplicate codes, unknown parameters and invalid selections are rejected.
- Two observation queries can run concurrently per server process. HTTP 503 includes Retry-After when the server is busy.
- A stale release produces HTTP 409. Fetch metadata again and review the selection before retrying.
- Errors use error.code and error.message. No authentication, mutation or background download endpoint is provided.

## Classification reference data

Browse https://statistics.bettergov.ph/classification or read the directory at https://statistics.bettergov.ph/api/classification. GET /api/classification/{system}/{version}/{level} returns count, next, previous and results. PTSCS uses /api/classification/ptscs/products and /api/classification/ptscs/industry without a version. No API key is required. The manifest at /api/classification/manifest.json lists available endpoints, counts and snapshot dates.

Example: https://statistics.bettergov.ph/api/classification/psgc/Q2_2024/barangays?reg=1&prv=28&page_size=20

Use page (starting at 1) and page_size (1–1000, default 1000); follow relative next links. PSGC filters are reg, prv, mun and bgy. Other systems use their hierarchy codes; documented names and corresponding record-field aliases are supported. Preserve leading zeros and version labels. Geographic codes are not necessarily unique. Classification data is not included in the six MCP tools.

PSGC all is unavailable. The mirror applies documented filters that some source endpoints ignore and consistently paginates tourism data. Textual codes match exactly. Errors use detail, with HTTP 400/404/405/413/503; for 413 reduce page_size. These are documented saved versions, not a guarantee of the latest PSA releases.

## MCP

Connect an MCP client using Streamable HTTP to https://statistics.bettergov.ph/mcp. The tools are get_coverage, list_topics, search_datasets, get_dataset, list_dimension_values and query_dataset. Use the same discovery → metadata → values → exact selection workflow as REST. A normal browser GET does not initialize an MCP session.

## Interpretation and citation

The source updated date, mirror retrieval date, inventory check date and release identifier describe different events. Source publication dates do not establish the time coverage of observations; inspect the dimension labels. Refer to the coverage response for current saved availability instead of assuming a fixed count.

Cite the PSA source URL, dataset title, release and dates returned by the API. Missing values stay null in JSON and empty in CSV; zero remains zero. Preserve units and status codes, and consult PSA definitions for unverified units or classifications. Do not sum overlapping categories or combine quarterly, semester and annual totals.

PSA is the authoritative statistical source. BetterGov.ph operates this independent explorer. The [Terms of Use](https://statistics.bettergov.ph/terms-of-service) distinguish the site's original material from source datasets; do not assume a blanket license for PSA observations.
