990 Quick Wins — Allocate-on-Post + Schedule B Watchlist + Acknowledgments
Three features that build the IRS Form 990's hardest sections from data in Muin: Part IX allocation, Schedule B donor disclosure, and acknowledgment letters.
This guide covers three features that ship together as part of Muin’s 990-season toolkit:
- Allocate-on-Post — every expense splits across program / management / fundraising at the moment it posts, using your saved allocation rules. Form 990 Part IX is filled from those postings rather than reconstructed at year end.
- Schedule B Watchlist + Auto-Acknowledgments — a real-time list of donors at or above the IRS reporting threshold, and §170(f)(8)-compliant acknowledgment letters generated automatically for donations over $250.
- Allocation Copilot — an AI agent that proposes the program / management / fundraising split AND a one-line audit-grade rationale on every bill capture; you review and confirm.
These work together. A bill captured today is allocated to programs (1) using either a saved rule or the Copilot’s proposal (3); a donation over the threshold is added to the Schedule B watchlist (2) and triggers an acknowledgment letter (2). Twelve months later, the 990 Workspace surfaces a draft populated with values you’ve been confirming all year.
Allocate-on-Post (Part IX engine)
What it does
Every expense entered in Muin can be split across one or more programs, plus management and fundraising buckets. The split is stored on the expense itself and aggregates into the 990 Workspace’s Part IX preview live.
Allocation Rules
Saved per-tenant rules match expenses by vendor pattern and/or GL account pattern (e.g. vendor_pattern: “Pacific Gas” + gl_account_pattern: “rent” → 60% program A, 25% program B, 10% management, 5% fundraising). When an expense matches exactly one active rule, the split applies automatically.
Each rule carries:
- Splits — program UUIDs and the literal keys
managementandfundraising. Percentages must sum to exactly 100. - Confidence floor — the minimum confidence threshold for the Allocation Copilot to auto-apply this rule’s split.
- Rationale template — optional one-line text the auto-generated audit log records.
Manage rules at Finance → Tax & Compliance → Allocation Rules.
Splitting an expense
When you open an expense detail page (via the receipt-upload pipeline or directly in Bills), the Allocate to Part IX card shows the current allocation. Click Edit allocation to open the split modal:
- Pick a saved rule (auto-fills splits) OR build a custom split inline.
- The sum-to-100 indicator turns green when the split balances; the Save button stays disabled otherwise.
- Add an optional rationale — this lands in the audit trail and is the seed text for Schedule O narrative material.
Part IX preview
The 990 Workspace (Compliance → Form 990 Workspace) shows a live Part IX preview pane: fiscal-year totals broken down into program services (per-program rows), management & general, and fundraising — with a progress count of allocated vs. unallocated expenses. Numbers update as soon as a split is saved.
Backfilling historical expenses
Use POST /api/v1/nonprofit/expense-allocation-rules/backfill (Allocation Rules page → admin actions) to walk historical expenses inside a fiscal year and apply matching rules to anything current_splits IS NULL. The flow is idempotent (already-allocated rows are skipped), supports dry_run=true for a count preview, and writes a single summary audit event.
Allocation Copilot
What it does
When a bill enters the system, the Copilot proposes a split: a percentage breakdown across active programs, a one-line rationale grounded in the tenant’s program registry, recent allocation history, and the matched rule (if any). The ED reviews and clicks Apply — or overrides.
How the proposal is shown
In the split modal, the Allocation Copilot panel sits above the form. Click Suggest with AI to call the Copilot. The panel displays:
- Proposed split — numeric percentages by program / management / fundraising.
- Confidence badge —
0.0–1.0with the rule-specific or platform-default floor (0.7) shown alongside. Below-floor proposals show a warning before apply. - Matched rule — name + ID of the rule the Copilot selected (if any).
- Rationale — one-line text grounded in tenant data. This is what lands in the audit log + Schedule O.
- Model — the Bedrock model that produced the proposal (claude-haiku-4-5 by default).
What it can and can’t do
It can:
- Propose splits when no exact rule match exists (e.g. a new vendor with characteristics similar to a known one).
- Generate Schedule O narrative material as a byproduct (the rationale).
- Operate within rate limits: 60 calls per tenant per minute, soft-fail to a 0-confidence placeholder when limited.
It can’t:
- Apply a split below the confidence floor without ED click.
- Hallucinate rule IDs or program UUIDs — the service validates every output against the active registry.
- Replace your accountant or your own judgment. Treat it as a fast-second-pair-of-eyes; ED in the loop on every below-
0.90proposal.
Schedule B Watchlist
What it does
Real-time donor list of all contributors year-to-date who have crossed the IRS Schedule B reporting threshold ($5,000 cash OR $5,000 noncash, with the IRS 170(b) floating threshold automatically applied for filers over $250K total contributions).
Where to find it
Nonprofit → Tax & Compliance → Schedule B Watchlist
What’s on the page
A table per tax year with:
- Donor — person name, foundation name, or “Anonymous (aggregate)”.
- Kind — Person / Foundation / Anonymous badge.
- Cash YTD — cumulative cash contributions for the year.
- In-kind YTD — cumulative noncash contributions, kept separate so a noncash valuation cannot push a donor over the cash threshold on its own (IRS Schedule B treats these as separate Parts).
- # Gifts — contribution count.
How donors are bucketed
- Person donors — individual contributions where
is_anonymous = false. - Foundations / Grantor organizations — contributions made through
grantor_organization_id. Multiple gifts from the same foundation aggregate into a single watchlist row. - Anonymous — contributions where
is_anonymous = truecollapse into a single aggregate row, surfaced only when the aggregate crosses the threshold (donors stay anonymous; the count and total surface for IRS-disclosure parity).
Threshold rule
For total contributions under $250K, the threshold is a fixed $5,000. At or above $250K, it floats: max($5,000, 2% × total contributions) — IRS Pub 578 Filing Requirements. The Watchlist shows the threshold actually applied at the top of the page; the Schedule B preview (used inside the 990 Workspace) shows the same value with the rule label.
Auto-Acknowledgments (§170(f)(8) compliant letters)
What it does
Every donation $250 or higher automatically drafts a §170(f)(8)-compliant acknowledgment letter — within minutes of the contribution status hitting completed. The letter contains all IRS-required elements: amount, date, organization name + EIN, and the “no goods or services were provided” disclaimer (or the quid-pro-quo statement, if tax_deductible_amount < amount).
Where letters surface
Nonprofit → Tax Receipts — the unified list of receipts and acknowledgment letters with status (pending, sent, void), receipt number, donor, amount, year, and a download-PDF action.
Idempotency
The endpoint is idempotent: a second call for the same contribution returns the existing non-void receipt, never creates a duplicate. A donation marked PENDING that later transitions to COMPLETED triggers exactly one letter. Voiding a contribution voids the matching receipt.
Manual override
You can:
- Re-send an acknowledgment letter from the receipt detail page (audit-logged with reason).
- Void a receipt and reissue (e.g. corrected donor name, amount adjustment).
- Generate annual giving statements (rollup of all year’s gifts in one PDF) from Donors → Annual Statement.
API reference
All endpoints are versioned under /api/v1/:
| Method | Path | Notes |
|---|---|---|
| GET | /api/v1/nonprofit/expense-allocation-rules |
List rules |
| POST | /api/v1/nonprofit/expense-allocation-rules |
Create rule |
| PATCH | /api/v1/nonprofit/expense-allocation-rules/{id} |
Update |
| DELETE | /api/v1/nonprofit/expense-allocation-rules/{id} |
Archive |
| POST | /api/v1/nonprofit/expenses/{id}/allocate |
Apply split |
| GET | /api/v1/nonprofit/expenses/{id}/copilot-proposal |
Copilot suggest |
| POST | /api/v1/nonprofit/expense-allocation-rules/backfill |
Backfill |
| GET | /api/v1/nonprofit/tax-990-workspaces/{id}/part-ix-preview |
Part IX preview |
| GET | /api/v1/nonprofit/schedule-b/watchlist |
Watchlist |
| GET | /api/v1/nonprofit/schedule-b/preview |
Schedule B preview |
| POST | /api/v1/nonprofit/donations/{id}/acknowledgment |
Generate letter |
| GET | /api/v1/nonprofit/donations/{id}/acknowledgment |
Fetch letter |
All endpoints are JWT-authenticated, tenant-scoped, audit-logged, and rate-limited per Muin’s standard middleware patterns.
Limits + clarifications
- Auto-filing — Muin produces 990 drafts; your CPA files. We don’t talk to the IRS for you.
- Schedule L (related-party / COI) — not yet built; tracked for a future release.
- State charitable-solicitation registration — not in scope for this release.
- Allocation Copilot — confidence-floor-based; ED in the loop on
<0.90. The Copilot does not replace human review.
For broader 990 prep, see Form 990 Workspace and the Tax Receipts flow.