post /v1/budgets/{budget_id}/assignments
Give money a job: assign, move, record income, cover overspending
scope budget:write · createAssignment
Parameters
budget_id path · string · required
Body · JSON
month string · required · YYYY-MM or YYYY-MM-DD
kind "assign" | "unassign" | "move" | "income" | "rollover_cover" | "card_reserve" · required
envelope_id string | null · ≤ 64 chars
from_envelope_id string | null · ≤ 64 chars
account_id string | null · ≤ 64 chars
transaction_id string | null · ≤ 64 chars
amount_cents integer · required · > 0
note string | null · ≤ 1000 chars
Returns · 201
{ id, month, undo, ready_to_assign_cents, envelopes[] }: the month's ready to assign after this write, and { envelope_id, assigned_cents, available_cents } for each envelope it touched. The plan ledger, append-only: a correction is a compensating row, never an edit. amount_cents is always POSITIVE; direction comes from which envelope is named. income names neither (money arrives unassigned); assign names envelope_id (pool -> envelope); move and rollover_cover name both. Covering credit overspending funds the card: when assign, move or rollover_cover puts money into an envelope that is overspent because of card purchases its money did not cover this month, that much of the amount is also reserved into the card's payment envelope (a card_reserve row), so the bill is funded; that payment envelope then appears in envelopes[] too. Cash overspending covers as before. undo (null for income, which DELETE /v1/budgets/{budget_id}/income/{id} takes back) is the one move { from_envelope_id, envelope_id, amount_cents, card_releases? } that puts every envelope back exactly, the card's payment envelope included: send it as the only move to POST /v1/budgets/{budget_id}/assignments/batch. Nothing here moves a real dollar.
Example
Errors · besides 401, 429, 500
- 400
validation_failed: The request body or query is malformed. The message names the offending field; fix it and retry. - 403
forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message. - 404
not_found: No such record on this budget. Re-read GET /v1/budgets/{id} (or the relevant list) for current ids rather than reusing a remembered one. - 409
idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.already_linked: This transaction already pays a loan (or a bank row already pays it). DELETE /v1/transactions/{id}/loan-payment to unlink first; linking twice would drop the principal twice.