Philippine Budget Data API
A free, public, read-only API over Philippine national budget data — the enacted General Appropriations Act (FY2020–2026), the FY2027 National Expenditure Program, budget-cycle execution data, and the House budget hearings (what was actually said, topic by topic, with timestamps). Also available as an MCP server for AI agents.
https://budget.bettergov.ph/api/v1
No auth required
CORS: open (*)
All amounts in exact ₱ pesos
curl https://budget.bettergov.ph/api/v1/gaa/departments
curl "https://budget.bettergov.ph/api/v1/gaa/search?q=school%20building"
curl https://budget.bettergov.ph/api/v1/nep/2027
The API is free for public use under fair-use conditions. Responses are cached at the edge
(Cache-Control: public, max-age=300, s-maxage=3600); data updates at most a few times a year,
so aggressive client-side caching is encouraged. Please identify heavy automated use with a
descriptive User-Agent.
Datasets & units
| Dataset | Coverage | What it is |
|---|---|---|
gaa | FY2020–2026, 38 departments | The enacted General Appropriations Act, down to UACS object-level line items (~2M rows). Hierarchy: department → agency → program (P/A/P) → operating unit → fund → expense class → object. |
nep/2027 | FY2027, 39 departments | The Executive's proposed ₱7.20 T National Expenditure Program. Every figure carries
amount (FY2027 proposal), base_amount (FY2026 GAA baseline), delta, and pct. |
budget-cycle | FY2018–2026, selected departments | How appropriations moved through the cycle: NEP → GAA → authorized/adjusted appropriation → adjusted allotment → obligations → disbursements, per program × year × stage × expense class. |
hearings | FY2027 season, House Committee on Appropriations | The budget deliberations: for each hearing (2–9 hours of video), a per-topic record of what transpired — the question at issue, who said what and when, the agency's answer, figures as spoken, commitments, and where it landed — plus a section-by-section timeline and the transcript. Every item is timestamped and deep-linked to the video. |
Units. Every amount anywhere in this API is an exact Philippine peso figure.
Each response's meta restates this ("currency": "PHP", "scale": "pesos"). The upstream
source publishes GAA figures in thousands; this API rescales them so you never have to.
Department ids. GAA ids are two digits (07 = Department of Education,
18 = Public Works). The NEP FY2027 dataset uses the same two-digit ids plus two
synthetic departments carved out for correctness: SPF (special purpose funds) and
AUTO (automatic appropriations).
AUTO is a synthetic NEP department — it is not GAA department 04.
(2) Budget-cycle figures cover Current New Appropriations only, a narrower scope than the
main GAA series — never compare the two 1:1.
(3) GAA and NEP are different stages of the budget process: NEP is the proposal, GAA is the law.
(4) In NEP rollups, __unassigned__ buckets rows the source didn't tag with that dimension,
and __other__ is an explicit remainder row on capped lists — both exist so lists always
sum to the true total.Conventions
Every endpoint is GET and returns JSON in a common envelope:
{
"meta": { "dataset": "gaa", "currency": "PHP", "scale": "pesos", ... },
"data": [ ... ] | { ... },
"next_cursor": "..." | null // paginated lists only
}
GAA rows carry per-year figures as a nested map — every year key is always present (zeroed if the source has no row for that year):
"years": { "2020": { "count": 12, "amount": 4491000 }, ..., "2026": { "count": 15, "amount": 5120000 } }
Filtered list endpoints also report whole-result-set totals in meta.matched /
meta.matched_amount, so a single request answers "how many and how much in total?"
without fetching every page.
Pagination
Large lists use opaque keyset cursors. Take next_cursor from a response and pass it back
as cursor; when it is null, the list is exhausted. Cursors are tied to the exact filter
combination that produced them — changing any filter invalidates the cursor (you'll get
400 bad_cursor or wrong pages). There is no page-number or offset pagination; cursor
performance does not degrade with depth.
Errors
Errors are JSON with a machine-readable slug and a human-readable message:
{ "error": "not_found", "message": "No GAA department 99" }
| Status | Slug | Meaning |
|---|---|---|
| 400 | bad_request | Invalid parameter (year out of range, malformed id, …) |
| 400 | bad_cursor | The cursor was not issued by this API (or filters changed) |
| 404 | not_found | Unknown department / endpoint |
| 405 | method_not_allowed | The API is read-only — use GET |
| 503 | not_loaded | The dataset is not loaded on this deployment |
| 500 | query_failed | Unexpected database error |
GAA — General Appropriations Act, FY2020–2026
/api/v1/gaaNational totals per fiscal year, summed across all departments.
curl https://budget.bettergov.ph/api/v1/gaa
{
"meta": { "dataset": "gaa", "years": [2020, ..., 2026], "currency": "PHP", "scale": "pesos", "departments": 38 },
"data": [
{ "year": 2020, "line_items": 725178, "amount": 4100000000000 },
...
{ "year": 2026, "line_items": 810081, "amount": 6326000000000 }
]
}
/api/v1/gaa/departmentsAll 38 departments with per-year appropriations and line-item counts, largest FY2026 budget
first. This is where you discover valid {id} values.
curl https://budget.bettergov.ph/api/v1/gaa/departments
/api/v1/gaa/departments/{id}One department in full: yearly totals, its agencies/bureaus (whose ids work as
agency_id filters elsewhere), and the expense-class breakdown.
curl https://budget.bettergov.ph/api/v1/gaa/departments/07
/api/v1/gaa/departments/{id}/expense-classesPersonnel Services / MOOE / Financial Expenses / Capital Outlays totals per year.
| Code | Class |
|---|---|
1 | Personnel Services (PS) |
2 | Maintenance and Other Operating Expenses (MOOE) |
3 | Financial Expenses (FinEx) |
6 | Capital Outlays (CO) |
/api/v1/gaa/departments/{id}/programsProgram/activity/project (P/A/P) families — raw P/A/P rows deduplicated by normalized name within an agency — ranked by appropriation in the chosen year. Paginated.
| Param | Type | Description |
|---|---|---|
year | 2020–2026 | Ranking year (default 2026) |
q | string | Substring filter on program name |
agency_id | string | Scope to one agency/bureau |
limit | 1–500 | Page size (default 100) |
cursor | string | From a previous next_cursor |
curl "https://budget.bettergov.ph/api/v1/gaa/departments/07/programs?year=2026&q=computerization&limit=5"
/api/v1/gaa/departments/{id}/objectsUACS object-level line items — the finest granularity in the GAA (DepEd alone has about a
million rows). Filter tightly and paginate. Rows with a zero amount in the chosen year are
hidden unless include_zero=1.
| Param | Type | Description |
|---|---|---|
year | 2020–2026 | Filter/ranking year (default 2026) |
q | string | Substring filter on description or UACS code |
agency_id | string | Scope to one agency/bureau |
expense_class | 1, 2, 3, 6 | 1=PS, 2=MOOE, 3=FinEx, 6=CO |
sort | amount | description | code | total | total ranks by the 7-year sum (implies include_zero) |
dir | asc | desc | Defaults: desc for amounts, asc otherwise |
limit, cursor | Page size 1–500 (default 100); keyset cursor |
curl "https://budget.bettergov.ph/api/v1/gaa/departments/07/objects?year=2026&q=textbooks&limit=10"
Note that free-text search here matches the object-level description (the UACS
expense object, e.g. "Textbooks and Instructional Materials"), not program names — search
programs with /gaa/search instead.
/api/v1/gaa/searchSearch program names across all departments at once — the quickest route from a topic ("school building", "flood control", "irrigation") to who funds it and with how much.
| Param | Type | Description |
|---|---|---|
q | string, required | Search text (min 2 chars) |
department_id | string | Optional two-digit scope |
year | 2020–2026 | Ranking year (default 2026) |
limit | 1–100 | Max results (default 25) |
curl "https://budget.bettergov.ph/api/v1/gaa/search?q=flood%20control&year=2026&limit=10"
/api/v1/gaa/years/{year}One fiscal year in isolation: the national total plus every department's appropriation,
line-item count, and share of that year's budget, largest first. The per-year counterpart of
/gaa/departments, which returns all seven years per row.
This is the API face of the per-year budget
browser.
curl https://budget.bettergov.ph/api/v1/gaa/years/2022
{
"meta": { "dataset": "gaa", "year": 2022, "departments": 37, ... },
"data": {
"total": { "year": 2022, "line_items": 628666, "amount": 5023600000000 },
"departments": [
{ "id": "07", "slug": "department-of-education-deped", "description": "Department of Education (DepEd)",
"year": 2022, "line_items": 308586, "amount": 633323678000, "share": 0.12607 },
...
]
}
}
/api/v1/gaa/years/{year}/departments/{id}/childrenWalk one department's hierarchy a level at a time, scoped to a single fiscal year — the same
drill the per-year browser does: department → agency (bureau) → program (FPAP) → operating unit
→ fund → expense class. Rows carry that year's figures only, ranked largest first, and keep
their parent-id columns so each row's id feeds the next level's parent.
Rows with a zero amount in that year are hidden unless include_zero=1.
| Param | Type | Description |
|---|---|---|
level | agencies | fpaps | operating_units | fund_subcategories | expenses | Level to list (default agencies) |
parent | string | Parent entity id — required below agencies |
include_zero | 1 | Keep rows the year doesn't fund |
limit, cursor | Page size 1–500 (default 100); keyset cursor |
# DepEd's bureaus in FY2022
curl "https://budget.bettergov.ph/api/v1/gaa/years/2022/departments/07/children"
# then programs of one bureau...
curl "https://budget.bettergov.ph/api/v1/gaa/years/2022/departments/07/children?level=fpaps&parent=07-001"
# ...down to the expense classes of one fund
curl "https://budget.bettergov.ph/api/v1/gaa/years/2022/departments/07/children?level=expenses&parent=07-001-310400100002000-0807002-01101101"
NEP FY2027 — National Expenditure Program
The Executive's ₱7.20 T proposal for FY2027, measured line by line against the FY2026 GAA.
Every row carries amount, base_amount, delta, and pct (null when the FY2026
baseline is zero, i.e. a new item).
/api/v1/nep/2027National overview: every department with its delta, expense classes, regions, top funds and programs, and the biggest movers up/down.
curl https://budget.bettergov.ph/api/v1/nep/2027
/api/v1/nep/2027/departmentsAll 39 departments (including synthetic SPF and AUTO) with amounts, baselines, and
per-dimension counts.
/api/v1/nep/2027/departments/{id}Full department view: agencies, programs, expense classes, funds, and regions in full;
objects, operating units, and divisions capped at the top 50 with an explicit
__other__ remainder row so lists still sum to the department total.
curl https://budget.bettergov.ph/api/v1/nep/2027/departments/07
curl https://budget.bettergov.ph/api/v1/nep/2027/departments/SPF
/api/v1/nep/2027/departments/{id}/rollups/{dimension}The complete, untruncated list for one dimension within one department, paginated.
Dimensions: agency, program, expense_class, fund, region, object,
operating_unit, division.
curl "https://budget.bettergov.ph/api/v1/nep/2027/departments/07/rollups/operating_unit?limit=500"
/api/v1/nep/2027/rollups/{dimension}National rollups. Two modes:
- Default — national totals per code in the dimension, summed across all departments. Every dimension is complete, so these sums are exact.
?code=X&by=department— one code broken down across departments (e.g. which departments spend in region13, or on object5020399000).
curl https://budget.bettergov.ph/api/v1/nep/2027/rollups/expense_class
curl "https://budget.bettergov.ph/api/v1/nep/2027/rollups/region?code=13&by=department"
Budget cycle — NEP → GAA → execution
/api/v1/budget-cycleDataset manifest and coverage: which departments are included, fiscal years (2018–2026), stages, and expense classes. Scope is Current New Appropriations only — narrower than the main GAA series; do not compare the two directly.
curl https://budget.bettergov.ph/api/v1/budget-cycle
/api/v1/budget-cycle/departments/{id}For one covered department: its programs (with the source→portal crosswalk and match confidence) and facts — one row per program × fiscal year × stage × expense class.
| Field | Values |
|---|---|
stage | nep, gaa, authorized_appropriation, adjusted_appropriation, adjusted_allotment, obligations, disbursements |
expense_class | ps, mooe, finex, co, total |
curl https://budget.bettergov.ph/api/v1/budget-cycle/departments/14
Budget hearings — what was said, topic by topic
The House Committee on Appropriations deliberates each agency's proposed budget in hearings that
run 2–9 hours. We transcribe the streams (speaker-labelled) and build a deliberation record:
not a summary of the hearing, but an account of what transpired on each topic. Machine
transcripts are imperfect — names and figures are as heard — so every item carries a timestamp and a
url that opens the hearing page with the video at that moment. Treat the records as an
index into the video, and verify before you quote.
/api/v1/hearingsAll hearings, newest first. Filters: fiscal_year, agency (acronym as in the title,
e.g. DOH), q (title keyword), limit, offset. has_record
says whether the topic record exists; transcript_source says how the transcript was made.
curl "https://budget.bettergov.ph/api/v1/hearings?agency=DOH"
/api/v1/hearings/search?q=…Keyword search over every topic record across all hearings — the topic, its summary, question, outcome,
and every spoken moment. All terms must match. Each hit returns the topic and the specific
matching_moments (timestamp, speaker, what was said, url). Optional fiscal_year,
agency, status (resolved | committed | parked | unresolved | informational).
curl "https://budget.bettergov.ph/api/v1/hearings/search?q=philhealth%20subsidy"
curl "https://budget.bettergov.ph/api/v1/hearings/search?q=flood%20control&status=committed"
/api/v1/hearings/{video_id}One hearing's metadata and its topic index (topic, status, first timestamp, summary, outcome).
/api/v1/hearings/{video_id}/topics
· /topics/{index}The full deliberation record. For each topic: question (what the committee was trying to
establish), thread (chronological moments: timestamp, speaker, side,
kind, said, url), agency_position, positions,
figures (as spoken; amount is a best-effort peso parse), actions (document
requests, commitments, motions, rulings), outcome and status. ?thread=0 omits the
moment-by-moment thread.
curl https://budget.bettergov.ph/api/v1/hearings/7U4YvhlnbZY/topics
curl "https://budget.bettergov.ph/api/v1/hearings/7U4YvhlnbZY/topics?thread=0"
/api/v1/hearings/{video_id}/timelineThe proceedings in order — roll call, presentation, each interpellation, motions, suspensions — with per-section summaries, exchanges, figures and actions.
/api/v1/hearings/{video_id}/transcript?from=&to=Raw transcript segments for a time window (seconds; default 20 minutes from from, at most
1000 segments), with the inferred speaker name when known.
curl "https://budget.bettergov.ph/api/v1/hearings/7U4YvhlnbZY/transcript?from=3600&to=3900"
OpenAPI specification
A machine-readable OpenAPI 3.1 description of every endpoint, parameter, and schema:
https://budget.bettergov.ph/api/v1/openapi.json
Import it into Postman, Insomnia, or any OpenAPI-aware code generator.
MCP server
The same data is exposed as an MCP server for AI agents — Claude, Cursor, and any other MCP-capable client. The transport is stateless Streamable HTTP: no auth, no sessions, JSON-RPC over POST.
https://budget.bettergov.ph/mcpTransport: Streamable HTTPRead-only toolsInstall in your AI client
Claude Code (CLI)
claude mcp add --transport http ph-budget https://budget.bettergov.ph/mcp
Then just ask: "Using ph-budget, which departments gain the most in the FY2027 proposal?"
Claude Desktop & claude.ai
Settings → Connectors → Add custom connector → paste
https://budget.bettergov.ph/mcp. No authentication is needed; the server is read-only.
Cursor
Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json in a project:
{
"mcpServers": {
"ph-budget": { "url": "https://budget.bettergov.ph/mcp" }
}
}
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"ph-budget": { "serverUrl": "https://budget.bettergov.ph/mcp" }
}
}
VS Code (Copilot Chat)
Run MCP: Add Server… from the command palette (choose HTTP), or add to
.vscode/mcp.json:
{
"servers": {
"ph-budget": { "type": "http", "url": "https://budget.bettergov.ph/mcp" }
}
}
Gemini CLI
Add to ~/.gemini/settings.json:
{
"mcpServers": {
"ph-budget": { "httpUrl": "https://budget.bettergov.ph/mcp" }
}
}
Anything else
Any client that speaks MCP over Streamable HTTP works: point it at
https://budget.bettergov.ph/mcp, no auth, no session setup. Most clients accept the generic
{"mcpServers": {"ph-budget": {"url": "https://budget.bettergov.ph/mcp"}}} shape.
Tools
| Tool | What it answers |
|---|---|
list_gaa_departments | Which departments exist, with per-year budgets (start here) |
get_gaa_national_trends | National GAA totals per year, 2020–2026 |
get_gaa_department | One department: yearly totals, agencies, expense classes |
search_gaa_programs | Find programs by name across all departments |
get_gaa_department_programs | All programs of one department, paginated |
search_gaa_line_items | Object-level line items with text/agency/expense-class filters |
get_nep_2027_overview | The FY2027 proposal at national level, vs FY2026 |
list_nep_2027_departments | All 39 NEP departments with deltas |
get_nep_2027_department | One department's FY2027 proposal in full |
get_nep_2027_rollup | Slice FY2027 by agency/program/region/object/… nationally, per department, or cross-department |
get_budget_cycle | NEP→GAA→execution stages for covered departments |
Example prompts
Once connected, ask your assistant things like:
- "Which departments get the biggest increases in the FY2027 budget proposal, in pesos and in percent?"
- "How much has the government appropriated for flood control programs each year since 2020, and under which departments?"
- "Break down DepEd's FY2026 budget by expense class, then show its largest line items for capital outlays."
- "Which regions gain and which lose in the FY2027 NEP compared to the FY2026 GAA?"
- "For the Department of Health, compare what was proposed (NEP), enacted (GAA), obligated, and disbursed across recent years."
- "What are the special purpose funds in the FY2027 proposal and how much is each?"
- "What did the DOH say in its budget hearing about the PhilHealth subsidy, and what did members demand? Link me to the moments."
- "Across all FY2027 hearings, which topics ended with the agency committing to submit documents?"
How an agent typically chains the tools
A question like "how much of DepEd's 2026 budget is textbooks?" resolves in three calls:
list_gaa_departments→ find DepEd's id (07)get_gaa_department {"department_id": "07"}→ totals and agencies for contextsearch_gaa_line_items {"department_id": "07", "query": "textbooks", "year": 2026}→ the matched line items, plusmeta.matched_amountanswering the question in one number
National "who spends on X?" questions go straight to search_gaa_programs (GAA) or
get_nep_2027_rollup with by_department: true (FY2027 proposal).
Raw protocol examples (curl)
The transport is stateless JSON-RPC over POST — you can drive it with curl. Handshake:
curl -X POST https://budget.bettergov.ph/mcp -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": { "protocolVersion": "2025-06-18", "capabilities": {},
"clientInfo": { "name": "curl", "version": "1.0" } }
}'
curl -X POST https://budget.bettergov.ph/mcp -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
Search flood-control programs across all departments:
curl -X POST https://budget.bettergov.ph/mcp -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": { "name": "search_gaa_programs",
"arguments": { "query": "flood control", "limit": 3 } }
}'
Break FY2027 spending in NCR (region code 13) down by department:
curl -X POST https://budget.bettergov.ph/mcp -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0", "id": 4, "method": "tools/call",
"params": { "name": "get_nep_2027_rollup",
"arguments": { "dimension": "region", "code": "13", "by_department": true, "limit": 5 } }
}'
Tool results arrive as JSON text inside result.content[0].text, in the same envelopes
the REST API returns. Invalid inputs come back as a result with
isError: true and a message explaining what to fix.
Data sources & attribution
Source data is derived from Department of Budget and Management publications, packaged as the BetterGov.PH GAA dataset. Figures are presented as published; always verify against official DBM documents before citing in formal work. If this API is useful to you, attribution to BetterGov.PH is appreciated.