---
title: "Approve a budget request"
method: POST
path: "/v1/budget_requests/{id}/approve"
tags: ["Budget request"]
---

# Approve a budget request

`POST /v1/budget_requests/{id}/approve`

## Request

- Base URL: `https://api.cardda.com`
- URL: `https://api.cardda.com/v1/budget_requests/{id}/approve`
- Auth: HTTP bearer

Approves a pending request, optionally changing the amount (and, for a new budget,
the budget to create). Only admin / `budgets_manage` users, who can approve their own
requests too.

## Effects
- `more_funds` on a `funded` ("Con saldo") budget, without periods or with
  `period_scope: current_period`: tops the budget up from the company's free balance,
  like `POST /v1/budgets/{id}/top_up`. If the balance doesn't cover it, it fails like
  the top-up (`budgets/insufficient_company_funds` with `unreserved_cents`) and the
  request stays `pending`.
- `more_funds` with `period_scope: next_periods`: raises the budget's
  `base_amount_cents` from the next renewal on. It moves no balance today, so it never
  fails for lack of funds; `next_period_shortfall_cents` over 0 warns that the
  company's free balance wouldn't cover renewing it with the new base today.
- `more_funds` on a `tracking` ("Solo control") budget: raises its
  `allocated_amount_cents` (or its `base_amount_cents` with `next_periods`). No
  balance moves.
- `new_budget`: creates the budget like `POST /v1/budgets`, with the request as
  default (`funded`, the requester as Encargado, the amount asked for) and `budget`
  overriding it. The request's `budget_id` points to it from then on.

Any failure leaves the request `pending`.

## Path parameters

- `id` string, uuid, required

## Parameters

- `#/paths/~1v1~1bills/get/parameters/0` (unresolved $ref)

## Request body

- BudgetRequestApprove: Body to approve a budget request. Every field is optional: an empty body approves the amount asked for as it was asked for. Params go at the top level, except the new budget's overrides, nested under `budget`.
  - `approved_amount_cents` integer: The amount approved, if different from the one asked for. Must be over 0 (`budget_requests/invalid_amount`). For `new_budget`, `budget.allocated_amount_cents` takes precedence when sent.
  - `period_scope` 'current_period' | 'next_periods': `more_funds` only: overrides the one asked for. It's checked against the budget as it is now: required if it renews, and `next_periods` refused if it doesn't (`budget_requests/invalid_period_scope`).
  - `budget` object: `new_budget` only: what the admin changed in the budget to create ("Editar"). It takes the same fields as `POST /v1/budgets`. Anything not sent defaults to the request: `mode` `funded` ("Con saldo"), the requester as Encargado (`manager_id`), the amount asked for, and the name, periodicity and participants asked for.
    - `name` string
    - `description` string
    - `allocated_amount_cents` integer
    - `manager_id` string: User id of the Encargado. Defaults to the requester.
    - `access` 'members' | 'company'
    - `mode` 'funded' | 'tracking'
    - `recurrence_unit` 'week' | 'month' | 'year'
    - `recurrence_every` integer
    - `ends_on` string, date: Closing date (America/Santiago). Must be after today.
    - `co_manager_ids` string[]
    - `participant_ids` string[]: Defaults to the participants asked for.

## Response `200`

The request, `approved`.

- object: A budget request ("solicitud de presupuesto"): a company member asks an admin for more funds for a budget they belong to (`more_funds`, "Más fondos") or for a new budget (`new_budget`, "Presupuesto nuevo"). An admin approves it (optionally changing the amount) or rejects it with a note; whoever asked can withdraw it while it's pending. Amounts are in the smallest currency unit (v1 is CLP-only, so cents == pesos).
  - `id` string, uuid, required
  - `company_id` string, uuid, required
  - `kind` 'more_funds' | 'new_budget', required: - `more_funds` ("Más fondos"): more money for an existing budget (`budget_id`). - `new_budget` ("Presupuesto nuevo"): a budget that doesn't exist yet; approving it creates the budget and `budget_id` points to it from then on.
  - `status` 'pending' | 'approved' | 'rejected' | 'withdrawn' | 'canceled', required: - `pending`: waiting for an admin. - `approved`: an admin approved it; the money moved (or the budget was created). - `rejected`: an admin rejected it; `resolution_note` says why. - `withdrawn`: whoever asked withdrew it. - `canceled`: the budget closed while it was pending (`resolution_note` is `budget_closed`).
  - `budget_id` string, uuid, nullable: The budget asked about (`more_funds`), or the one created on approval (`new_budget`). `null` for a `new_budget` request not approved.
  - `requested_amount_cents` integer, required: What was asked for.
  - `approved_amount_cents` integer, nullable: What the admin approved (the amount asked for unless changed). `null` until approved.
  - `currency` string, required
  - `period_scope` 'current_period' | 'next_periods' | 'null', nullable: Only for `more_funds` on a recurring budget (`null` otherwise): - `current_period`: the money is for the period in progress. - `next_periods`: raises what each period starts with (`base_amount_cents`) from the next renewal on.
  - `reason` string: Why the requester needs it.
  - `resolution_note` string, nullable: The admin's note when rejecting it. `budget_closed` when it was canceled because its budget closed.
  - `name` string, nullable: Name of the budget asked for (`new_budget` only).
  - `recurrence_unit` 'week' | 'month' | 'year' | 'null', nullable: How often the budget asked for should renew (`new_budget` only). `null` if it shouldn't.
  - `recurrence_every` integer, nullable: How many `recurrence_unit` each period of the budget asked for spans (`new_budget` only).
  - `participant_ids` string[]: Users the requester wants in the new budget (`new_budget` only; empty otherwise).
  - `origin_channel` 'web' | 'whatsapp', required: Where it was asked from.
  - `resolved_at` string, date-time, nullable: When it was approved, rejected, withdrawn or canceled.
  - `created_at` string, date-time, required
  - `requested_by` object, required: Who asked.
    - `id` string
    - `name` string, nullable
    - `email` string
  - `resolved_by` object, nullable: Who approved, rejected or withdrew it. `null` while pending or when canceled.
    - `id` string
    - `name` string, nullable
    - `email` string
  - `budget` object, nullable: The budget it's about (`budget_id`), `null` if there's none.
    - `id` string, uuid
    - `name` string
    - `mode` 'funded' | 'tracking'
    - `recurring` boolean: Whether it renews (`recurrence_unit` set).
    - `closing` boolean: Whether its closing date came.
    - `dissolved` boolean: Whether it's closed.
    - `period_ends_on` string, date, nullable: Scheduled renewal boundary of its period in progress. `null` if it doesn't renew.
    - `base_amount_cents` integer, nullable
    - `allocated_amount_cents` integer
  - `next_period_check` object, nullable: Only for users with `budgets_manage` (`null` for anyone else), on a pending `next_periods` request for a `funded` ("Con saldo") budget: the figures to warn that the company's free balance wouldn't renew the budget with the higher base today. `null` otherwise.
    - `current_base_cents` integer: What each period starts with today.
    - `available_for_base_cents` integer: The most the company's free balance could renew it with today.
  - `next_period_shortfall_cents` integer, required: How much the company's free balance falls short of renewing the budget with its new base today. Over 0 only for `next_periods` on a `funded` budget; 0 otherwise.

## Other responses

- `401`: Unauthorized - missing or invalid authentication token, or a caller without `budgets_manage`.
- `404`: Request not found (or outside the caller's scope).
- `409`: `budget_requests/already_resolved`: the request isn't `pending` anymore.
- `422`: `error_code` tells why: - `budget_requests/invalid_amount`: `approved_amount_cents` isn't an integer over 0. - `budget_requests/invalid_period_scope`: a recurring budget without `period_scope`, or `next_periods` on a budget that doesn't renew. - `budget_requests/budget_closed` / `budget_requests/budget_closing`: the budget is closed, or its closing date came. - `budgets/insufficient_company_funds` (with `unreserved_cents`): the company's free balance doesn't cover the top-up or the new `funded` budget. - `budgets/amount_must_be_positive`, `budgets/invalid_recurrence`, `budgets/invalid_end_date`: the new budget doesn't validate, as in `POST /v1/budgets`. Other failures (e.g. a duplicate budget name) answer only `message`.

---

[API](https://skmtc.dev/cardda/apis/finance-api.md) - [All operations](https://skmtc.dev/cardda/apis/finance-api/llms.txt) - [OpenAPI document](https://skmtc.dev/cardda/apis/finance-api/revisions/59752c65ea74?raw)
