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

# Period-End Accruals: Post from Claude over MCP

> Work out an accrual from a raw export in Claude, then post it to DualEntry as a balanced journal entry with an automatic reversal, using the MCP server.

Period-end accruals usually start as a raw export nobody wants to pivot by hand: a timesheet dump, an open purchase order report, a contractor invoice queue. This guide brings that export into Claude, works the numbers, and posts the result to DualEntry as a balanced journal entry with its reversal already scheduled.

The whole sequence runs in one Claude conversation. You do not export anything back out, and you do not retype figures into the ledger.

To do the same job inside DualEntry instead, see [how to draft accruals with Copilot and a scheduled agent](../draft-accruals-with-copilot-and-a-scheduled-agent). The difference is where the entry is created and how it is confirmed: Copilot proposes an entry in a preview and nothing reaches the general ledger until you post it yourself, while the MCP server's `save_record` writes to the ledger as soon as Claude calls it. Prefer the Copilot path when you want a preview between the proposal and the posting.

## Before you start

Connect Claude to DualEntry first, because none of the steps below work without the tools attached. Follow [Quickstart: DualEntry MCP Server](../../../developers/guides/mcp-quickstart) and confirm Claude lists the DualEntry tools before you continue.

You also need:

* **A DualEntry role with create permission for journal entries**: MCP access mirrors your dashboard role, so if you cannot post a journal entry in DualEntry, Claude cannot post one for you.
* **Access to the company you intend to post to**: Company-level restrictions apply to the tools the same way they apply to the dashboard.
* **An open accounting period for the posting date**: A locked period rejects the entry.
* **The accrual accounts already in your chart of accounts**: Create them in DualEntry first if they do not exist.

This guide assumes you know what the accrual should be. Claude does the arithmetic and the grouping, not the accounting judgment.

<Warning>
  The `save_record` tool posts a real record immediately. There is no draft stage, no preview, and no confirmation prompt between Claude deciding to call it and the entry hitting your ledger. Review the numbers in the conversation before you tell Claude to post, and treat "post it" as the irreversible instruction it is.
</Warning>

## Step 1: Give Claude the source data

Attach the raw export to the conversation and state the accrual you want, in one message. Claude reads the file directly, so you do not need to clean it up first.

Say what the accrual is, which period it belongs to, and how the numbers should be grouped. A useful prompt names all three:

```text theme={null}
Attached is our August contractor timesheet export. Work out the accrual for
unbilled contractor cost at 08/31/2026, grouped by department. Show me the
per-department totals and the grand total before you do anything else.
```

The last sentence matters. Without it Claude may go straight to looking up accounts and posting, and you want to see the arithmetic first.

Check what comes back against something you already know. A department total that is an order of magnitude off, a grand total that does not tie to the export's own footer, or a department you do not recognize all point at a misread file rather than a bad accrual. Ask Claude to show its grouping if the totals look wrong:

```text theme={null}
Show me the rows that make up the Engineering total.
```

Resolve any disagreement here, while the numbers are still just text in a conversation. Every later step assumes these figures are the ones you want in the ledger.

## Step 2: Look up the account and company IDs

DualEntry records reference accounts and companies by numeric ID, not by name, so Claude has to resolve those before it can build the entry. Ask it to look them up rather than supplying IDs yourself.

```text theme={null}
Find the account IDs for IT Expense, Human Resources Expense, Consulting
Expense, and Accrued Purchases. Also get the company ID for Enterprise Level.
```

Claude calls `search_entities` for each name and `list_companies` for the company. A returned account looks like this:

```json theme={null}
{
  "id": 53953,
  "name": "Accrued Purchases",
  "number": "2510000",
  "account_type": "other_current_liability",
  "currency_iso_4217_code": null
}
```

Read the `account_type` and `number` on what comes back, not just the name. Chart of accounts naming drifts, and several similarly named accounts often exist. If `search_entities` returns more than one plausible match, tell Claude which account number is correct instead of letting it choose.

If a search returns nothing, the account does not exist under that name in your chart of accounts. Create it in DualEntry, then ask Claude to search again. Do not let it substitute a near match: an accrual posted to the wrong liability account is harder to find later than one that failed to post at all.

Confirm the company too. Organizations with multiple entities frequently have similar company names, and the company ID decides which entity's books the accrual lands in.

## Step 3: Have Claude show the entry before it posts

Ask for the journal entry as a table before it goes anywhere near the ledger. This is the review step, and it is the last point at which a mistake costs nothing.

```text theme={null}
Show me the journal entry you would post: account name, account ID, debit,
credit, and memo per line. Do not post it yet.
```

Check four things in what comes back:

* **The entry balances.** Total debits equal total credits. DualEntry rejects an unbalanced entry, but catching it here saves a round trip.
* **The debits and credits sit on the right sides.** An expense accrual debits the expense accounts and credits the accrued liability. A reversed pair still balances, so the ledger will accept it.
* **The account IDs match the ones you confirmed.** Compare against Step 2 rather than trusting the names in the table.
* **The date is the period end you intended.** A posting date of today lands the accrual in the wrong period.

Then decide the reversal. Most accruals should reverse on the first day of the following period, which DualEntry can create for you as part of the same save:

```text theme={null}
Post it dated 08/31/2026 with a reversal date of 09/01/2026.
```

Passing a reversal date creates both halves in one operation, so the reversal cannot be forgotten next period. DualEntry adds it as a second transaction on the same journal entry, dated the reversal date, with the debits and credits flipped and a `Reversal:` memo prefix, rather than as a separate entry carrying its own number. Omit it only when the accrual is meant to stay on the books until something specific relieves it.

## Step 4: Post the entry

Tell Claude to post once the table is right. It calls `save_record` with `record_type` set to `journal_entry` and a payload shaped like this:

```json theme={null}
{
  "company_id": 9,
  "date": "2026-08-31",
  "reversal_date": "2026-09-01",
  "currency_iso_4217_code": "USD",
  "exchange_rate": 1,
  "memo": "August unbilled contractor accrual",
  "items": [
    {"id": null, "position": 0, "account_id": 153591, "debit": 41200.00, "credit": 0, "memo": "IT"},
    {"id": null, "position": 1, "account_id": 153593, "debit": 18650.00, "credit": 0, "memo": "HR"},
    {"id": null, "position": 2, "account_id": 153599, "debit": 27490.00, "credit": 0, "memo": "Consulting"},
    {"id": null, "position": 3, "account_id": 53953, "debit": 0, "credit": 87340.00, "memo": "Accrued contractor cost"}
  ]
}
```

Dates in the payload are ISO 8601 (`YYYY-MM-DD`), which is what the API accepts, even though you write them as `08/31/2026` when you talk to Claude. Claude converts them.

A successful save returns two identifiers, and neither one is the number DualEntry displays on the entry:

```json theme={null}
{
  "success": true,
  "record_id": 2021522,
  "record_number": 830,
  "record_type": "journal_entry"
}
```

Keep the `record_id`. For a journal entry it is the transaction ID: one number under two names, which come apart only on aggregate record types that span several transactions, such as intercompany journal entries. `get_record_detail`, `get_record_history`, and `get_related_records` therefore take the `record_id` exactly as the save returned it. Their parameter is spelled `transaction_id` and the tool description offers `search_records` as the place to find it, but no search is needed here, because you already hold the value. The `record_number` is a per-organization document sequence that nothing in this workflow needs.

The number DualEntry shows on the entry comes from a third value, the journal entry's own ID, which `save_record` does not return. To get it, have Claude read the entry back and use the `id` field on the `get_record_detail` response. For the save above that is `495642`, which the interface shows as `JE-495642`, zero-padded to 6 digits when the ID is shorter. Results from `search_records` carry the same value ready-formatted in a `reference` field.

Do not pass the `record_number` to `get_record_by_number` to find the entry. That tool resolves its argument as an ID first and only falls back to the document sequence, so `830` returns the journal entry whose ID is 830 if your organization has one, and yours only if it does not. Give it the display number instead, which is the form it expects: `JE-495642`.

A failed save returns an error instead, and the record is not created. Nothing partial is written, so you can correct the problem and ask Claude to post again without cleaning anything up.

## Step 5: Verify the entry landed

Confirm the posting in DualEntry rather than taking the tool response as proof, because a successful save still leaves room for the entry being right in form and wrong in substance.

Check it through Claude first. A read-back addresses the entry by ID, so it cannot land on a different record, and it works the instant the save returns:

```text theme={null}
Show me the detail for the journal entry you just posted.
```

Claude calls `get_record_detail` with the `record_id` from the save response. The response carries the journal entry's own `id` alongside its `transaction_id`, so this one call also gives you the display number. A journal entry line reads like this:

```json theme={null}
{
  "id": 86345287,
  "account": {"id": 199467, "name": "SaaS Subscriptions", "number": 60010},
  "amount": "80.00",
  "debit": "80.00",
  "credit": null,
  "currency": "USD"
}
```

The unused side of each line comes back as `null` rather than zero, so a line showing `"debit": null` is a credit line and not a broken one.

To open the entry in DualEntry itself, search for its display number, `JE-495642` in this example. Expect a short delay: records are indexed for search asynchronously once the save commits, so an entry posted seconds ago may not be findable yet. Until it is indexed, a number search matches the document sequence rather than the display number, which can return a different entry with the same number. Compare what opens against the detail Claude read back, and if the two disagree you are looking at the wrong record rather than a bad post. Once the right entry opens, check the line accounts, the amounts, the posting date, and that the status reads **Posted**.

Last, confirm the reversal, which takes a second call. `get_record_detail` returns only the lines of the transaction you asked about, with no reversal date and no reversal ID, so a reversal that posted correctly is still absent from that response. Do not read that absence as a missing reversal. Posting a manual reversing entry on top of one that already exists reverses the accrual twice, which is a worse outcome than the problem you were checking for.

Ask Claude to search the reversal date instead:

```text theme={null}
Check for the reversal: search journal entries dated 09/01/2026 with
"Reversal" in the memo.
```

Claude calls `search_records` with the reversal date as both `start_date` and `end_date`, and `Reversal` as the `memo`, which matches on partial text. DualEntry posts the reversal as a second transaction on the same journal entry rather than as a new entry with its own number, so what comes back shares the accrual's `JE-495642` reference and differs only in date, memo, and `transaction_id`. Identify it by the reversal date and the `Reversal:` memo prefix rather than by the number, and check that its flipped debits and credits match the original amounts.

## Troubleshooting

Failures in this workflow typically fall into two categories: insufficient permissions or invalid references. In most cases, the tool response identifies the specific field that caused the error.

| What you see                                  | Cause                                                                 | Fix                                                                                                                                               |
| --------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `"error": "validation_error"` naming a field  | The payload is missing a required field or the entry does not balance | Ask Claude to show the payload it sent, correct the named field, and post again                                                                   |
| `"Company access restricted"` on `company_id` | Your role does not cover the company you are posting to               | Post to a company you can access, or ask an administrator to widen your company access                                                            |
| `Missing permission:`                         | Your DualEntry role lacks create access for journal entries           | Ask an administrator to update your role. MCP cannot exceed your dashboard permissions                                                            |
| An FK error naming an account                 | An account ID does not exist, or belongs to a different organization  | Re-run `search_entities` for the account and use the ID it returns                                                                                |
| The period is locked                          | The posting date falls in a closed period                             | Post to an open period, or reopen the period if your role allows it                                                                               |
| Claude cannot find the entry you just posted  | Neither identifier in the save response is the display number         | Have Claude call `get_record_detail` with the `record_id`, or `search_records` on the posting date and memo. Searching by number will not find it |
| Claude posted before you were ready           | `save_record` has no confirmation step                                | Reverse the entry in DualEntry. Add "do not post yet" to your prompts before Step 3                                                               |

If Claude reports no DualEntry tools at all, the connection dropped rather than the entry failing. Reconnect using [Quickstart: DualEntry MCP Server](../../../developers/guides/mcp-quickstart) and start again from Step 3, since nothing was posted.

## Related reading

* [Quickstart: DualEntry MCP Server](../../../developers/guides/mcp-quickstart): connecting a client and confirming it works.
* [MCP Server: Tools, Permissions, and Troubleshooting](../../../developers/guides/mcp-integration): the full tool catalog and permissions by tool.
* [How to Connect an MCP Connector](../connect-an-mcp-connector): the reverse direction, giving DualEntry Copilot access to outside systems.
* [How to Draft Accruals with Copilot and a Scheduled Agent](../draft-accruals-with-copilot-and-a-scheduled-agent): the same accrual inside DualEntry, with a preview before posting.
* [How to Post and Reverse Month-End Accruals](../../core-financials/general-ledger/post-and-reverse-accruals): the entry mechanics, independent of how it is created.
* [How Accounting Intelligence Works](../ai-accounting-intelligence): DualEntry's in-product assistant.
* [Month-End Close Checklist](../../core-financials/close-management/month-end-close-checklist): where accruals sit in the wider close.
* [Audit Trail and Compliance](../../platform-configuration/audit-trail-and-compliance): how records posted through MCP are attributed.
