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

# Period Closing

> Lock accounting periods and transfer net income to retained earnings

## Overview

**Period closing** locks past accounting periods by creating a `PERIOD_CLOSE` journal entry that transfers all income and expense account balances to retained earnings. This prevents modifications to closed periods and finalizes financial results.

<Note>
  **Permission required**: `periods:close` (to close/undo periods), `reports:read` (to preview)

  Period closing is a critical accounting control that ensures financial records remain accurate and unchanged after review.
</Note>

***

## API Endpoints

### Close Period

**Close the next unclosed accounting period:**

```http theme={null}
POST /period-closing/close
Headers:
  x-organization-id: {organizationId}
  x-idempotency-key: {uniqueKey}
```

**Headers:**

| Header              | Type   | Required | Description                            |
| ------------------- | ------ | -------- | -------------------------------------- |
| `x-organization-id` | string | Yes      | Organization ID                        |
| `x-idempotency-key` | string | Yes      | Unique key to prevent duplicate closes |

**Response:**

```json theme={null}
{
  "message": "Accounting period closed successfully",
  "data": {
    "periodStart": "2026-06-01T00:00:00.000Z",
    "periodEnd": "2026-06-30T00:00:00.000Z",
    "accountingPeriod": "MONTHLY",
    "journalEntryId": "je-123",
    "closedAt": "2026-07-01T10:30:00.000Z"
  }
}
```

***

### Preview Period Close

**Preview what will happen when period is closed:**

```http theme={null}
GET /period-closing/preview
Headers:
  x-organization-id: {organizationId}
```

**Response:**

```json theme={null}
{
  "message": "Close period preview fetched successfully",
  "data": {
    "accountingPeriod": "MONTHLY",
    "periodStart": "2026-06-01T00:00:00.000Z",
    "periodEnd": "2026-06-30T00:00:00.000Z",
    "canClose": true,
    "netProfitLoss": 125000.00,
    "incomeStatement": {
      "revenue": [
        {
          "accountId": "acc-123",
          "accountName": "Interest Income",
          "accountCode": "4000",
          "debit": 0,
          "credit": 200000,
          "netAmount": 200000
        }
      ],
      "expenses": [
        {
          "accountId": "acc-456",
          "accountName": "Operating Expenses",
          "accountCode": "5000",
          "debit": 75000,
          "credit": 0,
          "netAmount": 75000
        }
      ],
      "totalRevenue": 200000,
      "totalExpenses": 75000,
      "netIncome": 125000
    },
    "balanceSheet": { ... },
    "transactions": [ ... ],
    "validations": {
      "hasWarnings": false,
      "warnings": []
    }
  }
}
```

**If cannot close:**

```json theme={null}
{
  "canClose": false,
  "reason": "No completed accounting period available to close",
  "periodStart": null,
  "periodEnd": null
}
```

***

### Undo Last Period Close

**Reverse the most recent period close:**

```http theme={null}
POST /period-closing/undo
Headers:
  x-organization-id: {organizationId}
  x-idempotency-key: {uniqueKey}
```

**Headers:**

| Header              | Type   | Required | Description                                     |
| ------------------- | ------ | -------- | ----------------------------------------------- |
| `x-organization-id` | string | Yes      | Organization ID                                 |
| `x-idempotency-key` | string | Yes      | Unique key to prevent duplicate undo operations |

**Response:**

```json theme={null}
{
  "message": "Latest accounting period close undone successfully",
  "data": {
    "undoneJournalEntryId": "je-123",
    "reversalJournalEntryId": "je-456",
    "periodEnd": "2026-06-30T00:00:00.000Z",
    "undoneAt": "2026-07-02T14:20:00.000Z"
  }
}
```

**Important**: Can only undo the **most recent** period close. Cannot undo arbitrary past periods.

***

## How Period Closing Works

### 1. Period Determination

**First close** (no prior periods closed):

* Finds earliest transaction date (or organization creation date if no transactions)
* Determines period window containing that date
* That becomes the first period to close

**Subsequent closes**:

* Finds last closed period's end date
* Next period = period immediately following last closed period
* Automatic sequential closing

**Current period check**:

* Cannot close current period (period containing today's date)
* Can only close completed past periods

***

### 2. Income & Expense Analysis

For the period being closed, the system:

1. **Finds all INCOME and EXPENSE account transactions**
   * Only POSTED journal entries
   * Excludes PERIOD\_CLOSE entries
   * Date range: periodStart to periodEnd

2. **Calculates net balance per account**
   ```
   INCOME accounts: netIncome = credit - debit
   EXPENSE accounts: netExpense = debit - credit
   ```

3. **Identifies non-zero accounts**
   * Skips accounts with zero net balance
   * Only accounts with activity need closing entries

***

### 3. PERIOD\_CLOSE Journal Entry

Creates journal entry with `kind = 'PERIOD_CLOSE'` that:

**For INCOME accounts** (normal credit balance):

* **DEBIT** the income account (zeros it out)
* **CREDIT** Retained Earnings (increases equity)

**For EXPENSE accounts** (normal debit balance):

* **CREDIT** the expense account (zeros it out)
* **DEBIT** Retained Earnings (decreases equity)

**Net effect**: All income and expense accounts go to zero, and net income transfers to Retained Earnings.

**Example**:

```
Period: June 1-30, 2026
Interest Income (CREDIT balance): 200,000
Operating Expenses (DEBIT balance): 75,000
Net Income: 125,000

PERIOD_CLOSE Journal Entry (June 30, 2026):
┌────────────────────────┬────────┬─────────┐
│ Account                │ Debit  │ Credit  │
├────────────────────────┼────────┼─────────┤
│ Interest Income        │ 200,000│         │ ← Zero out revenue
│ Operating Expenses     │        │  75,000 │ ← Zero out expenses
│ Retained Earnings      │        │ 125,000 │ ← Net income to equity
├────────────────────────┼────────┼─────────┤
│ TOTAL                  │ 200,000│ 200,000 │
└────────────────────────┴────────┴─────────┘
```

**Result**:

* Interest Income balance: 0 (was 200,000)
* Operating Expenses balance: 0 (was 75,000)
* Retained Earnings balance: +125,000

***

### 4. Transaction Lock

After period close entry is posted:

**Cannot create/modify** transactions with dates in closed period:

* ❌ Cannot record deposits dated in closed month
* ❌ Cannot edit loans from closed period
* ❌ Cannot delete expenses from closed period
* ❌ Cannot create manual journal entries dated in closed period
* ❌ System validation error: "Transaction date in closed period"

**Can still access** closed period data:

* ✅ View historical transactions (read-only)
* ✅ Generate reports for closed periods
* ✅ Export data for audits
* ✅ See journal entries and balances

**Ongoing transactions work normally**:

* ✅ Loan payments for loans originated in closed periods
* ✅ Reports can aggregate closed + open periods

***

## Why Close Periods

**Financial integrity:**

* Prevents retroactive changes to finalized records
* Creates immutable historical snapshots
* Ensures reports don't change after distribution

**Accounting accuracy:**

* Transfers net income to retained earnings
* Prepares income/expense accounts for new period
* Resets temporary accounts to zero

**Audit compliance:**

* Demonstrates internal controls over financial records
* Provides clear period boundaries
* Establishes audit trail

**Operational benefits:**

* Peace of mind that past periods are final
* Prevents accidental backdating
* Stops fraudulent modifications

***

## Accounting Period Types

Your organization's accounting period is configured in settings:

| Period Type   | Frequency      | Example Close Dates            |
| ------------- | -------------- | ------------------------------ |
| **MONTHLY**   | Every month    | Jan 31, Feb 28, Mar 31...      |
| **QUARTERLY** | Every 3 months | Mar 31, Jun 30, Sep 30, Dec 31 |
| **YEARLY**    | Annually       | Dec 31 (or fiscal year-end)    |

**Sequential closing**: Periods must be closed in order (cannot skip periods).

***

## Before Closing a Period

<Warning>
  **Critical checklist** - DO NOT close until complete:

  **Transactions:**

  * ✅ All deposits, withdrawals, loans recorded for period
  * ✅ All expenses and payments posted
  * ✅ No DRAFT journal entries pending
  * ✅ All loan payments processed

  **Reconciliation:**

  * ✅ Bank accounts reconciled with bank statements
  * ✅ Member balances verified (spot-check savings accounts)
  * ✅ Loan portfolio reconciled (outstanding balances correct)

  **Verification:**

  * ✅ Trial balance runs and balances (debits = credits)
  * ✅ Balance sheet equation holds (Assets = Liabilities + Equity)
  * ✅ No negative balances in asset/liability accounts (unless expected)

  **Reporting:**

  * ✅ Financial statements generated (Balance Sheet, P\&L)
  * ✅ Reports reviewed by treasurer/accountant
  * ✅ Unusual items investigated and documented

  **Approval:**

  * ✅ Management/board approval obtained
  * ✅ Minutes documenting approval (if required)

  **Backup:**

  * ✅ Database backup created
  * ✅ Financial reports archived
</Warning>

***

## Closing Workflow

**Recommended process:**

<Steps>
  <Step title="Preview period close">
    ```bash theme={null}
    GET /period-closing/preview
    ```

    Review period dates, net income, and validations
  </Step>

  <Step title="Verify net income matches expectations">
    Compare `netProfitLoss` to Profit & Loss report for period
  </Step>

  <Step title="Check validations">
    Address any warnings in `validations.warnings` array
  </Step>

  <Step title="Get approval">
    Present preview to treasurer/management for sign-off
  </Step>

  <Step title="Generate idempotency key">
    ```typescript theme={null}
    const idempotencyKey = `period-close-${Date.now()}-${Math.random()}`;
    ```
  </Step>

  <Step title="Close the period">
    ```bash theme={null}
    POST /period-closing/close
    Headers:
      x-idempotency-key: {idempotencyKey}
    ```
  </Step>

  <Step title="Verify close successful">
    Check response contains `journalEntryId` and `closedAt`
  </Step>

  <Step title="Archive reports">
    Export and save Balance Sheet, P\&L, and closing journal entry
  </Step>
</Steps>

***

## Example: Monthly Close

**Scenario**: Close June 2026

**Timeline:**

| Date   | Action                                                  |
| ------ | ------------------------------------------------------- |
| Jul 1  | Record last June transactions                           |
| Jul 2  | Reconcile June bank statements                          |
| Jul 3  | Run June trial balance (verify balanced)                |
| Jul 3  | Preview period close: `GET /period-closing/preview`     |
| Jul 4  | Generate June financial statements                      |
| Jul 4  | Review with treasurer, identify net income: 125,000 RWF |
| Jul 5  | Get board approval to close June                        |
| Jul 5  | **Close June period**: `POST /period-closing/close`     |
| Jul 6+ | Continue July transactions normally                     |

**API calls:**

```bash theme={null}
# Preview
curl -X GET "/period-closing/preview" \
  -H "x-organization-id: org-abc123"

# Close (after approval)
curl -X POST "/period-closing/close" \
  -H "x-organization-id: org-abc123" \
  -H "x-idempotency-key: period-close-june-2026"
```

**Result**:

* June period locked
* Interest income account zeroed out
* Operating expenses account zeroed out
* Retained earnings increased by 125,000 RWF (net income)
* Cannot modify June transactions anymore

***

## Undoing a Period Close

<Warning>
  **Use sparingly**: Only undo for critical errors. Frequent undoing indicates poor closing procedures.
</Warning>

**When to undo:**

* Major error discovered after close (misposted transaction)
* Audit requires adjustment to closed period
* Bank reconciliation error found post-close
* Incorrect period closed by mistake

**Limitations:**

* ❗ Can ONLY undo the **most recent** period close
* ❗ Cannot undo arbitrary past periods (e.g., if June, July, August closed, can only undo August)
* ❗ To undo June, must first undo August, then July, then June

**Procedure:**

```bash theme={null}
# Undo last period close
curl -X POST "/period-closing/undo" \
  -H "x-organization-id: org-abc123" \
  -H "x-idempotency-key: undo-period-close-2026-07-02"
```

**What happens:**

1. **Finds most recent PERIOD\_CLOSE journal entry**
2. **Marks it as REVERSED** (status = 'REVERSED')
3. **Creates REVERSAL journal entry** with opposite debits/credits
   * Original: DEBIT Interest Income, CREDIT Retained Earnings
   * Reversal: CREDIT Interest Income, DEBIT Retained Earnings
4. **Period reopens** - can now modify transactions in that period

**After undo:**

* Make necessary corrections
* Re-run all reports
* Get re-approval
* Close period again

**Best practice**: Instead of undoing, create correcting entry in current period referencing past error (if error is immaterial).

***

## Sequential Closing

**Backend enforces sequential closing automatically:**

✅ **Correct sequence**:

1. Close January
2. Close February
3. Close March
4. Close April

❌ **Cannot skip periods**:

* Close January → Close March (skipping February) ❌ NOT ALLOWED

**Why sequential?**

* Financial statements build on prior periods
* Retained earnings balance carries forward
* Must finalize periods in chronological order

**Implementation**:
Backend determines next unclosed period automatically:

* If last closed = January 31, next close = February 1-28
* If no periods closed, next close = earliest transaction period

***

## Year-End Closing

**Additional considerations for fiscal year-end:**

<Steps>
  <Step title="Close all months in fiscal year">
    Ensure all 12 months closed (if calendar year: Jan-Dec)
  </Step>

  <Step title="Close final month">
    December close triggers year-end (or last month of fiscal year)
  </Step>

  <Step title="Generate annual statements">
    ```bash theme={null}
    GET /reports/balance-sheet?asOfDate=2025-12-31
    GET /reports/profit-loss?startDate=2025-01-01&endDate=2025-12-31
    ```
  </Step>

  <Step title="Verify retained earnings">
    Retained Earnings should include all net income from closed year
  </Step>

  <Step title="External audit (if required)">
    Provide auditors with annual statements and supporting schedules
  </Step>

  <Step title="Archive reports">
    Keep 7+ years per regulations (check local laws)
  </Step>
</Steps>

**Note**: Income and expense accounts reset to zero after each period close (monthly, quarterly, or yearly depending on your period type).

***

## Common Errors

**"No completed accounting period available to close"**

**Cause**: Current period (containing today's date) cannot be closed.

**Solution**: Wait until period ends. For monthly: wait until next month starts.

***

**"User is not part of this organization"**

**Cause**: Authenticated user doesn't have organization membership.

**Solution**: Verify user has organization access and correct `x-organization-id` header.

***

**"x-idempotency-key header is required"**

**Cause**: Missing idempotency key header.

**Solution**: Add unique `x-idempotency-key` to request:

```bash theme={null}
-H "x-idempotency-key: period-close-$(date +%s)"
```

***

**"No closed period available to undo"**

**Cause**: Attempting to undo when no periods have been closed.

**Solution**: Verify periods have been closed using preview endpoint.

***

**"Last closed period has already been undone"**

**Cause**: Attempting to undo same period multiple times.

**Solution**: Check if period already reopened. Cannot undo twice.

***

## Best Practices

<Note>
  **Period closing checklist:**

  **Timing:**

  * ✅ Close monthly within 7 days of month-end
  * ✅ Don't rush - complete all reconciliation first
  * ✅ Schedule consistent close date (e.g., 5th of following month)

  **Verification:**

  * ✅ Always preview before closing (use `/period-closing/preview`)
  * ✅ Compare net income to Profit & Loss report
  * ✅ Get second person to verify before closing
  * ✅ Review validation warnings in preview response

  **Documentation:**

  * ✅ Document any unusual items before closing
  * ✅ Maintain closing checklist (paper or digital)
  * ✅ Note closing in board minutes (if required)
  * ✅ Document reason if period undone

  **Backup:**

  * ✅ Create database backup before closing each period
  * ✅ Archive financial statements immediately after close
  * ✅ Keep backups for 7+ years

  **Idempotency:**

  * ✅ Use unique idempotency key for each close/undo
  * ✅ Format: `period-close-YYYY-MM-DD-timestamp`
  * ✅ Prevents accidental duplicate closes

  **Reopening:**

  * ✅ Only undo for critical errors
  * ✅ Get management approval before undoing
  * ✅ Document reason for undo in audit trail
  * ✅ Re-close promptly after corrections
</Note>

***

## Troubleshooting

**Q: Accidentally closed period too early (still have transactions to record)**

A: Undo immediately:

```bash theme={null}
POST /period-closing/undo
```

Complete missing tasks, then re-close.

***

**Q: Need to record transaction dated in closed period**

A: **Option 1** (if critical): Undo period, add transaction, re-close

**Option 2** (recommended): Record in current period with note:

```
Description: "Correcting June expense recorded in July -
             See receipt dated June 25"
```

***

**Q: Audit requires changes to closed year**

A: If must change closed period:

1. Undo periods sequentially back to target period
2. Make auditor-approved adjustments
3. Update all affected reports
4. Re-close all periods
5. Document in audit report

**Note**: This can be tedious if many periods closed. Consider materiality before undoing multiple periods.

***

**Q: How do I know which period will close?**

A: Call preview endpoint first:

```bash theme={null}
GET /period-closing/preview
```

Response shows `periodStart` and `periodEnd` of next period to close.

***

**Q: Can I close periods out of order?**

A: No. Backend enforces sequential closing. Must close periods chronologically.

***

**Q: What happens to INCOME/EXPENSE accounts after closing?**

A: They are zeroed out. Balance transfers to RETAINED\_EARNINGS. Accounts reset for next period.

***

**Q: Can I undo period close from 6 months ago?**

A: Only if no periods closed after it. Can only undo most recent period. To undo 6 months ago, must sequentially undo all periods closed since then.

***

## Related Topics

<CardGroup cols={2}>
  <Card title="Profit & Loss Report" icon="chart-line" href="/tontines/reports/profit-and-loss">
    View net income before closing
  </Card>

  <Card title="Balance Sheet" icon="scale-balanced" href="/tontines/reports/balance-sheet">
    Verify retained earnings after close
  </Card>

  <Card title="Journal Entries" icon="book-open" href="/tontines/general-ledger/viewing-journal-entries">
    View PERIOD\_CLOSE entries
  </Card>

  <Card title="Monthly Closing Checklist" icon="check-double" href="/tontines/workflows/monthly-closing-checklist">
    Complete period-end procedures
  </Card>
</CardGroup>
