> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filexpress.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Budgets

> Budgets by cost center and budget vs actual report from an external system

| Permission | Endpoints |
| - | - |
| `accounting.budgets` | `GET /accounting/budgets`, `GET /accounting/budgets/{id}`, `GET /accounting/reports/budget-vs-actual` |
| `accounting.budgets.write` | `POST /accounting/budgets`, `PUT /accounting/budgets/{id}`, `PUT /accounting/budgets/{id}/lines`, `POST /accounting/budgets/{id}/status`, `DELETE /accounting/budgets/{id}` |

> [!NOTE]
>
> These are **explicit** permissions: you must select them one by one in **External integrations**; existing integrations do not receive them automatically.

A budget holds monthly amounts per leaf [cost center](https://docs.filexpress.app/en/docs/api/contabilidad/centros-de-costo.md) and income statement account (accounts whose center policy is `optional` or `required`; see the [catalog](https://docs.filexpress.app/en/docs/api/contabilidad/catalogo.md)). You can have several per year, but only one can be `approved`. See [Budgets](https://docs.filexpress.app/en/docs/contabilidad/presupuestos.md) in the manual.

## Budget object

```json theme={null}
{
  "id": "b1f0...",
  "business_id": "uuid",
  "name": "Presupuesto 2026",
  "fiscal_year": 2026,
  "status": "draft",
  "notes": null,
  "lines_count": 24,
  "total_amount": 54000.00,
  "created_at": "2026-10-08T15:00:00.000000Z",
  "updated_at": "2026-10-08T15:00:00.000000Z",
  "lines": [
    {
      "id": "uuid",
      "cost_center_id": "c3a1...",
      "account_id": "a9d2...",
      "month": 1,
      "amount": 100.00,
      "cost_center": { "id": "c3a1...", "code": "0101", "name": "Ventas San Salvador" },
      "account": { "id": "a9d2...", "code": "6102", "name": "Papelería" }
    }
  ]
}
```

| Field | Description |
| - | - |
| `status` | `draft` (editable), `approved` (only one per year) or `closed`. |
| `lines_count`, `total_amount` | Number of lines and sum of amounts. |
| `lines` | Only in the single-budget query and in write responses. One line per center, account and month (`1` to `12`). Months with 0 are not stored. |

## List budgets

```http theme={null}
GET /accounting/budgets?fiscal_year=2026&status=approved
```

**Required permission:** `accounting.budgets`

| Parameter | Required | Description |
| - | - | - |
| `fiscal_year` | No | Filters by year. |
| `status` | No | `draft`, `approved` or `closed`. |

Returns the list of budgets in `data` (without `lines`), from the most recent year to the oldest.

## Get budget

```http theme={null}
GET /accounting/budgets/{id}
```

**Required permission:** `accounting.budgets`

Responds `200` with the [budget](#budget-object) and its `lines`, or `404` `Budget not found`.

## Create budget

```http theme={null}
POST /accounting/budgets
```

**Required permission:** `accounting.budgets.write`

```json theme={null}
{
  "name": "Presupuesto 2026",
  "fiscal_year": 2026,
  "notes": "Versión inicial",
  "lines": [
    { "cost_center_id": "c3a1...", "account_id": "a9d2...", "month": 1, "amount": 100 },
    { "cost_center_id": "c3a1...", "account_id": "a9d2...", "month": 2, "amount": 100 }
  ]
}
```

| Field | Required | Description |
| - | - | - |
| `name` | Yes | Name. |
| `fiscal_year` | Yes | Fiscal year. |
| `notes` | No | Notes. |
| `lines` | No | Initial lines (see [Lines](#save-lines)). |

The budget starts as `draft`. **`201` response**: the [budget](#budget-object) with its lines.

## Edit budget

```http theme={null}
PUT /accounting/budgets/{id}
```

**Required permission:** `accounting.budgets.write`

```json theme={null}
{ "name": "Presupuesto 2026 v2", "notes": "Ajuste de gastos" }
```

Accepts `name`, `fiscal_year` and `notes` (all optional). Only in `draft`.

## Save lines

```http theme={null}
PUT /accounting/budgets/{id}/lines
```

**Required permission:** `accounting.budgets.write`

```json theme={null}
{
  "replace": false,
  "lines": [
    { "cost_center_id": "c3a1...", "account_id": "a9d2...", "month": 3, "amount": 150 },
    { "cost_center_id": "c3a1...", "account_id": "a9d2...", "month": 4, "amount": 0 }
  ]
}
```

| Field | Required | Description |
| - | - | - |
| `lines[].cost_center_id` | Yes | **Leaf** and active center of the company. |
| `lines[].account_id` | Yes | Company account with center policy `optional` or `required` (income statement account). |
| `lines[].month` | Yes | Month, from `1` to `12`. |
| `lines[].amount` | Yes | Amount greater than or equal to 0. |
| `replace` | No | `false` (default): updates only the cells sent (by center, account and month), and an `amount: 0` deletes that cell. `true`: replaces all budget lines with the ones sent. |

Only in `draft`. Responds `200` with the budget and its lines.

## Change status

```http theme={null}
POST /accounting/budgets/{id}/status
```

**Required permission:** `accounting.budgets.write`

```json theme={null}
{ "status": "approved" }
```

`status`: `draft`, `approved` or `closed`. There can be only one `approved` budget per year: if another one already exists, it responds `422` `Ya existe un presupuesto aprobado para 2026.`.

## Delete budget

```http theme={null}
DELETE /accounting/budgets/{id}
```

**Required permission:** `accounting.budgets.write`

Only in `draft`. Responds `{"status": true, "data": {"deleted": true}}`.

## Budget vs actual report

```http theme={null}
GET /accounting/reports/budget-vs-actual?fiscal_year=2026&month_from=1&month_to=10
```

**Required permission:** `accounting.budgets`

| Parameter | Required | Description |
| - | - | - |
| `fiscal_year` | No | Year. Defaults to the current year. |
| `budget_id` | No | Budget to compare. Without it, the year's `approved` budget is used (`422` if there is none). |
| `month_from`, `month_to` | No | Month range (`1` to `12`). |
| `cost_center_ids[]` | No | Centers to include. Without it, the whole tree. |
| `include_children` | No | Defaults to `true`: includes the sub-centers of the selected centers. |
| `depth` | No | Groups accounts into their parent account at that catalog level. Without it, detail account. |
| `branch_id` | No | Limits actuals to one branch. |
| `expense_threshold` | No | Execution threshold for costs and expenses (default `100`). |
| `income_threshold` | No | Execution threshold for income (default `100`). |
| `format` | No | `json` (default), `pdf` or `excel`: downloads `presupuesto-vs-real-2026.pdf` or `.xlsx`. |

```json theme={null}
{
  "status": true,
  "data": {
    "title": "Presupuesto vs real por centro de costo",
    "budget": { "id": "b1f0...", "name": "Presupuesto 2026", "fiscal_year": 2026, "status": "approved" },
    "month_from": 1,
    "month_to": 10,
    "expense_threshold": 100,
    "income_threshold": 100,
    "centers": [
      {
        "id": "c3a0...", "code": "01", "name": "Ventas", "level": 1, "parent_id": null, "is_leaf": false,
        "rows": [
          { "account_code": "6102", "account_name": "Papelería", "group": "expenses", "budget": 100, "actual": 120, "variance": 20, "execution_pct": 120, "status": "exceeded" }
        ],
        "totals": {
          "income": { "budget": 0, "actual": 0, "variance": 0, "execution_pct": null },
          "costs": { "budget": 0, "actual": 0, "variance": 0, "execution_pct": null },
          "expenses": { "budget": 100, "actual": 120, "variance": 20, "execution_pct": 120 }
        }
      }
    ],
    "totals": {
      "income": { "budget": 0, "actual": 0, "variance": 0, "execution_pct": null },
      "costs": { "budget": 0, "actual": 0, "variance": 0, "execution_pct": null },
      "expenses": { "budget": 100, "actual": 120, "variance": 20, "execution_pct": 120 }
    }
  }
}
```

| Field | Description |
| - | - |
| `centers` | Selected centers and their descendants, in tree order. A parent center's amounts include those of its children. |
| `rows[].group` | `income`, `costs` or `expenses`. |
| `budget` | Sum of the months in the range. |
| `actual` | Lines from **processed** journal entries in the period with that center and account. Income: credit minus debit; costs and expenses: debit minus credit. |
| `variance` | `actual - budget`. |
| `execution_pct` | `actual / budget × 100`; `null` if the budget is 0. |
| `status` | `ok`; `exceeded` (cost or expense with `execution_pct` greater than `expense_threshold`, or with actual greater than 0 and no budget); `under` (income with `execution_pct` less than `income_threshold`). |
| `totals` | Sum of the root centers in the selection, without double-counting sub-centers. |

## Errors

| Code | Cause |
| - | - |
| `401` | Missing or invalid API key. |
| `403` | The integration does not have the required permission. |
| `404` | `Budget not found` (nonexistent or belonging to another company). |
| `422` | `Validation errors`; for example `status`: `Solo se puede modificar un presupuesto en borrador.`, `Ya existe un presupuesto aprobado para 2026.`; `budget_id`: `No hay un presupuesto aprobado para 2026.`; or `lines.N.field` with the line's error. |

```json theme={null}
{
  "status": false,
  "message": "Validation errors",
  "errors": { "status": ["Solo se puede modificar un presupuesto en borrador."] }
}
```

> [!NOTE]
>
> Excel import and export of the budget is available in FileXpress (**Accounting → Budgets**), not in the external API.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.