EP Finance Invoicing
EP Finance Invoicing issues quotes and invoices, takes payment for them, and posts the result into your books. It is part of the EP Finance family and sits on top of the EP Finance ledger.
This page documents EP Finance Invoicing 0.2.0.
Published by ElmsPark Studio.
Requirements
Section titled “Requirements”- PageMotor 0.9b or later
- EP Finance, which provides the ledger, the money handling and the chart of accounts. EP Finance Invoicing is a member of the finance family and is not a standalone install: it is supplied and configured alongside EP Finance rather than picked up on its own
- EP Ecommerce with a payment provider configured, if you want pay links. It reuses whatever provider you already have, normally EP Ecommerce Stripe
- EP Email if you want due-soon and overdue reminders
Settings
Section titled “Settings”Everything on the settings screen is saved with PageMotor’s own Save button.
| Setting | What it does |
|---|---|
| Business name | Shown on the PDF and hosted page. Blank falls back to your site title |
| Address / VAT number / contact | One item per line. Appears in the seller block on every document |
| Payment details | Account name, sort code, account number, one per line. Printed on invoices |
| Default payment terms (days) | Used to compute the due date. Defaults to 30 |
| Due-soon reminder lead time | How many days before the due date the reminder goes out. Defaults to 3 |
| Send reminders | Turns the due-soon and overdue reminder emails on or off |
Numbering, and why it is built this way
Section titled “Numbering, and why it is built this way”Invoice numbers must be sequential and gap-free. Most systems allocate the number when the draft is created, which produces gaps every time a draft is abandoned, and can collide if two people issue at the same moment.
This plugin allocates the number at issue, not at creation, inside a locked counter. Two simultaneous issues cannot gap and cannot collide. Each series keeps its own counter, and quotes and invoices number separately.
Voiding an invoice keeps its number. The issue posting is reversed in the ledger, but the number stays used, because removing it would create the gap the whole design exists to prevent.
The document lifecycle
Section titled “The document lifecycle”- Draft. Create a quote or an invoice with line items. Nothing touches the ledger yet.
- Issue. The next number in the series is allocated and the receivable is posted to the ledger. Revenue is recognised at this point.
- Pay. A settlement is recorded: bank up, receivable down. Revenue is not posted again, because it was recognised at issue.
- Void. Available for an issued invoice that has not been paid. Reverses the issue posting and keeps the number. A paid invoice cannot be voided.
Getting paid
Section titled “Getting paid”Each invoice has a hosted page at an unguessable tokenised URL, in the form ?ep_inv=<token>, with &format=pdf for the branded PDF. The page is print-friendly, so a customer can save or print it without an account.
Every response from that endpoint is served noindex, whether the token is valid or not, so invoices never reach a search engine.
The pay link creates an order through EP Ecommerce and reuses your existing payment extensions. There is no second payment integration to configure, and no second set of keys to keep in step.
The double-posting wall
Section titled “The double-posting wall”The risk in any system where an invoice can be settled from more than one direction is that a payment posts twice, once from the invoice and once from the payment feed. This plugin holds a single-source-of-truth wall so an invoice payment posts exactly once.
You can test that wall rather than trust it. The invoice_simulate_paylink action fulfils a pay-link order for a real invoice, runs the genuine EP Ecommerce fulfilment broadcast, and reports how many settlement groups resulted. The correct answer is 1. It also reports whether the sources feed correctly skipped the transaction, and whether the audit came back clean.
Structured output
Section titled “Structured output”Documents are shaped to EN 16931, the European standard for electronic invoicing. The PDF is branded, and the same underlying document drives the hosted page.
API actions
Section titled “API actions”Every action is admin-only.
| Action | What it does |
|---|---|
invoice_create | Create a draft invoice or quote with line items. Returns the id, token and total. Nothing posts to the ledger |
invoice_issue | Issue a draft: allocate the next gap-free number and post the receivable |
invoice_get | Full invoice: fields, computed lines, tax breakdown, events, hosted and PDF URLs |
invoice_pay | Record a settlement once. Idempotent |
invoice_void | Void an invoice, reversing the issue posting and keeping the number |
invoice_series | The current next number for every series |
invoice_simulate_paylink | Test the double-posting wall, as described above |
Line items are passed as JSON, each with a description, quantity, unit price in cents, and a tax rate in basis points.
Tax packs
Section titled “Tax packs”Tax is handled through a swappable interface, so a jurisdiction-specific pack can be dropped in without changing the invoicing code. A working manual-rate default ships with the plugin, so it is usable immediately with rates you set yourself.
Things worth knowing
Section titled “Things worth knowing”It loads defensively. PageMotor includes plugin files with no try/catch, so a fatal at file scope takes the whole site down. This plugin guards its bundled requires, so a missing or corrupt file degrades to “plugin absent” with a note in the error log rather than an outage.
It carries a Model: EP_Ecommerce header. That registers it as an EP Ecommerce extension, which is how a fulfilled pay-link order reaches it.
Money is held in cents. Line unit prices are integers, not floats, which is what keeps totals exact.
Related plugins
Section titled “Related plugins”- EP Ecommerce and EP Ecommerce Stripe, which provide the payment rail for pay links
- EP Email, which delivers the reminders
Document stamps
Section titled “Document stamps”Every invoice and quote PDF carries a stamp in its footer: a number and the first characters of a fingerprint taken over the invoice’s own figures.
If a client queries an invoice, or you are looking at one from two years ago, the stamp lets you check whether its figures are exactly what was recorded when it was issued.
The fingerprint covers the figures, not the file. Two renders of an unchanged invoice produce the same fingerprint, so reprinting one does not make it look altered. Changing a single line total produces a different one, and so does reordering two lines even when every total stays identical.
It is not a signature. It says nothing about who produced the invoice, only whether its figures have changed since. Anyone with access to the database could write a matching record. It protects against accident, drift and quiet edits, not against a determined party with that access.
Requires EP Finance 0.6.0 or later for the stamp to be recorded. With anything older the invoice is produced exactly as before, simply without a stamp line.
Changelog
Section titled “Changelog”0.2.17
Section titled “0.2.17”- Every unpaid invoice now waits until it is paid on the cash basis. Before, only invoices with VAT did. An invoice with no VAT counted as income on the day you issued it, even if it was never paid. Now every invoice counts on the cash basis on the day it is paid. This affects Schedule C and SA103 on the cash method, and a cash-accounting VAT return.
- Tools, “Cash basis: invoices already in your books”. Invoices issued before this update still count on the day they were issued. The Tools tab counts them first and changes nothing. When you press the button, unpaid invoices then wait until paid, paid ones count on their payment date, and voided ones do not count at all.
- Invoices in a period you have closed are left as filed. Figures on the invoice or accrual basis do not change.
- Needs EP Finance 0.8.0 or later.
0.2.16
Section titled “0.2.16”- Settings language menu. The language menu in this plugin’s settings now lists only the languages it is actually translated into, plus English, so you can no longer pick a language that changes nothing.
0.2.15
Section titled “0.2.15”- Invoices put their VAT in your books on its own line. With EP Finance 0.8.0 set as VAT registered, issuing an invoice records each rate’s sales without VAT and the VAT the invoice shows, so your VAT return reads it. Voiding an invoice takes its VAT back off.
- Cash accounting counts an invoice when it is paid. An unpaid invoice is left out of a cash-basis VAT return until you record its payment, and then counts in the period it was paid.
- An invoice issued before your VAT registration date goes into your books at its full amount, and its history says the VAT was not recorded as VAT.
0.2.14
Section titled “0.2.14”- Paying an invoice by M-Pesa now shows the “check your phone” screen. On the invoice’s own page, pressing Pay with M-Pesa sent the request but showed nothing while the customer approved it on their phone. The waiting screen now appears, counts down, and says when the payment is received.
- With EP Ecommerce M-Pesa 0.1.2 the page then shows the invoice paid. With EP Ecommerce Paystack 0.1.2, a customer paying by Paystack comes back to the invoice rather than your home page. With EP Ecommerce Products 0.1.16, their email says the payment was received for the invoice. Update those plugins too.
0.2.13
Section titled “0.2.13”- An amount too large for your books is refused before anything is saved. A unit price of 10 trillion or more used to be saved as 0.00, and a huge quantity (or price times quantity) gave a meaningless total, or an error. Creating an invoice or quote, or changing its lines, is now refused with “An amount is larger than the books can hold”, and nothing is created or changed.
- The largest amount the books hold, 9,999,999,999,999.99, still works.
0.2.12
Section titled “0.2.12”- An invoice or quote PDF now downloads even when its document stamp cannot be saved. On a server where database errors stop the page, a PDF whose stamp record could not be read or written failed with an error, for example alongside an EP Finance older than 0.6.0, which does not keep stamps. The PDF is now produced without the stamp line, as intended.
- The stamp line printed on your PDFs does not change.
- Update EP Finance to 0.7.13 at the same time: it carries the same fix.
0.2.11
Section titled “0.2.11”- Invoices know when their entry in the books was deleted. If you delete, in EP Finance, the sale, payment or void an invoice put in your books, the invoice now says “Not in your books: …” and shows Post to books, which puts back exactly that part, dated when it first happened. Before, the invoice believed it was still in the books, so the button never came back.
- Voiding an invoice whose sale had been deleted no longer fails with “Nothing to reverse”.
- After Mark paid, Void, Issue or Post to books, the confirmation (for example “Marked paid.”) now stays on screen. It used to vanish straight away. It is also read out by screen readers.
- The invoice list no longer makes the page scroll sideways on a phone.
0.2.10
Section titled “0.2.10”- A GDPR erasure now also removes the buyer’s name from your books. When an invoice’s buyer asks to be erased, the invoice was already anonymised but kept. Now the name also comes out of the transaction the invoice made in EP Finance (“Invoice INV-0001 — REDACTED”), including the audit trail’s copies. Amounts are not touched, and it works even inside a closed period.
- The erasure result says how many ledger descriptions were cleaned. With an EP Finance older than 0.7.9 it says how many were left instead, and everything else is erased as before.
- The document stamp on invoice and quote PDFs now covers more of the document. It now includes each line’s quantity and your business name and address as printed, including when they come from your settings. Stamps on documents you have already sent can still be checked.
- The stamp line on PDFs is now readable. It used to show ”??” between its parts. Accented letters and typographic dashes and quotes in names and descriptions now print as plain letters and punctuation instead of question marks.
- Opening an invoice link no longer adds to its history every time. A view of the customer’s invoice page is recorded at most once a day, and downloading the same unchanged PDF again reuses its stamp rather than recording a new one.
- Quotes now have their own stamp history, separate from invoices with the same number.
- Accepting a quote twice no longer creates a second invoice. The second click shows the invoice made the first time. A declined or void quote can no longer be accepted.
- The invoices list now has pages. It shows the newest 50, with Newer and Older buttons. Before, it stopped at 200 with no way to see older invoices.
- Safer invoice links. A visit to an invoice link that does not exist no longer sets anything up in your books.
- An issued invoice’s lines and total can no longer be changed. Before, they could still be edited after the invoice was issued or sent, which left the amount in your books and the amount the customer was asked to pay out of step. To correct an issued invoice, void it and issue a new one. You can still change the customer’s name and address, your details, the notes and the terms. A draft can be changed freely, as before.
- A quote can no longer be marked paid. A quote is an offer, so nothing is owed on it yet. Accept it to turn it into an invoice, then record the payment on that invoice. The “Mark paid” and “Test pay-link” buttons no longer appear on quotes.
- Voiding now either finishes or changes nothing. If the sale cannot be taken back out of your books, for example because its date is inside a period you have closed, the invoice stays as it was and you are told why. Before, it was marked void while the sale stayed in your books. Fix the cause (such as reopening the period) and void it again.
- When a refused action is clicked, the invoices screen now says so. Before, a refused “Mark paid” or “Void” could show as done.
- Erasing a customer’s personal data now removes it everywhere in Invoicing. The customer’s details are also removed from the invoice’s stored e-invoice data and from the “Emailed to” line in its history. The invoice and its number are kept, as before. The description of the sale in your EP Finance books still includes the customer’s name, because EP Finance does not allow a recorded transaction’s description to be edited.
- Long invoices now print in full. The PDF used to stop after about 25 lines with “(continued)”, and printed the totals over the page footer. Every line now appears, over as many pages as needed, with the totals after the last line and a page number at the foot of each page.
- Invoice payments now follow EP Finance’s new “Main bank account” setting. When Invoicing’s own “Bank account for invoice payments” is left on its first option, payments are recorded on the main bank account set in EP Finance. The option now names it. If none is set, payments go to the same automatic account as before. An account chosen here still wins.
- Security fix in the bank account list. An account name containing HTML is now shown as text. Before, it was placed on the settings page as it was typed.
- Customers can now pay an invoice online from its link. The “Pay this invoice” section on the invoice page could not complete a payment before this release. The site treated the invoice as an unavailable product and refused it, the page was missing a security code the payment needs, and the payment step received the invoice page instead of its answer. All three are fixed.
- After paying, the customer is taken back to the invoice, and it shows as paid.
- An invoice is marked paid even if the payment notice goes astray. Opening the invoice, the invoices list, or the twice-daily reminder run marks the invoice paid when its payment has completed.
- An invoice cannot be paid twice online. Once it is paid (online or by hand) or voided, its pay link closes. If a payment went through but could not yet be recorded, for example because the date is inside a period you have closed, the link also closes and the page says the payment was received.
- If you change an invoice’s total after sending it, the pay link charges the new total.
- No change to EP Ecommerce is needed. The pay link is not listed anywhere in your shop.
- You can now choose which bank account invoice payments are recorded on. Settings has a new “Bank account for invoice payments” option. Until now Invoicing picked the first bank account in alphabetical order, and you could not change it. If EP Finance Sources had set up its accounts first, that was “Bank account (Stripe payouts)” rather than the account you import your bank statements into.
- Choose the account you import your statements into. EP Finance Importer can then match each payment to its bank line instead of counting it twice.
- Nothing changes when you upgrade. Until you choose an account, payments go where they went before. The setting names that account as “Automatic”.
- Changing the account affects future payments only. Payments already recorded stay on the account they went to. Their “See the money in your ledger” button still opens that account.
- Only an active asset account can be chosen. If the chosen account is later made inactive, payments go back to the automatic account.
- An invoice that could not be added to your books now tells you so, and can be retried. If issuing an invoice could not post it to your books (for example, EP Finance was switched off, or the date was inside a period you have closed), the invoice was still issued and the screen said all was well, with no way to post it later. You now get a warning saying why. A “Post to books” button appears on that invoice and posts it once the problem is fixed. The invoice number never changes.
- Recording a payment no longer goes ahead for an invoice that is not in your books. Marking such an invoice paid now posts the invoice first. If that still cannot be done, the payment is not recorded and you are told why, instead of your books showing money owed to you that goes below zero.
- The invoicing demo no longer runs on a site with real invoices. Loading the demo deletes every invoice and starts numbering again from 1. It now refuses to run when the site has issued invoices of its own.
- The download no longer includes an internal notes file. Earlier versions carried a
CLAUDE.mdfile of developer notes in the plugin folder. Neither the plugin nor PageMotor ever read it, so nothing about how the plugin works changes. If an earlier version leftep-finance-invoicing/CLAUDE.mdon your site, it is harmless and safe to delete.
- Fixes a doubled cache-busting tag on its admin script. On PageMotor 0.11 and later the page asked for the file with two version tags on the end of its address (
?v=…?v=…), because the core had started adding its own tag and the plugin was still adding one too. The file loaded correctly, so nothing was visibly broken; the address was just malformed and every cache saw a longer key than it needed. The plugin now leaves the tag to the core on 0.11 and later, and still adds its own on older cores, where nothing else would. - No change to what that script does.
- Corrects the PageMotor 0.11.3 preparation shipped in 0.2.0. That release grouped this plugin’s API and MCP actions into families, but in a shape PageMotor 0.11.3 does not accept. On 0.11.3 the plugin would have registered none of its actions, and nothing on screen would have said so.
- This version uses the shape 0.11.3 expects, and keeps the earlier shape for sites still on an older PageMotor. One build serves both, so there is no order you have to update things in.
- Safe to install now. Nothing you can see changes.
Released 9 September 2026.
- Every invoice and quote PDF now carries a document stamp in its footer: a number and the first characters of a fingerprint taken over the invoice’s own figures.
- The fingerprint covers the figures, not the file. Two renders of an unchanged invoice agree; changing one line total, or reordering two lines while every total stays identical, does not.
- It is not a signature. It tells you whether the figures match what was recorded, not who produced the document.
- Requires EP Finance 0.6.0 or later. With anything older the invoice is produced exactly as before, without a stamp line.
0.1.11
Section titled “0.1.11”- Prepares the plugin for PageMotor 0.11.3, which requires every plugin to group its API and MCP actions into named families. On that release an action declaring no family is refused silently, so without this update the plugin’s actions would stop being offered with nothing on screen to say why.
- Families exist so that an AI working on your site sees the related actions together instead of stopping at the first one it tries.
- Safe to install on your current PageMotor. No behaviour changed.
0.1.10
Section titled “0.1.10”Released 1 September 2026.
- The plugin’s API actions no longer appear as individual top-level tools in connected MCP clients. Seven actions carried a flag that promotes an action alongside PageMotor’s own dispatch entry points, and core reserves that surface for itself.
- Nothing became unreachable. Action ids, methods, access tiers, arguments and behaviour are unchanged. Every action is still discoverable through
list-actions, described bydescribe-action, and invoked throughcall-action. Only a caller that invoked one of the promoted names directly as an MCPtools/callis affected; it should dispatch throughcall-actioninstead.
Released 22 August 2026.
-
Reminders no longer retire themselves when the send fails. The reminder stage was previously marked done immediately after the send was attempted, without checking whether any mail actually left. An inactive EP Email, a missing From address, or any transport error therefore silently ended the chase and the invoice was never followed up again.
There are now three outcomes instead of one: mail sent (stage done), no recipient on file (stage done, because retrying cannot help), and send failed (retried on the next run). The Reminders panel reports failures inline, so a dead transport no longer reads identically to “nothing was due”.
Released 6 August 2026.
- Defensive load guard. The plugin now checks its bundled files at load and wraps every file-scope require in try/catch, so a missing or corrupt bundle degrades to “plugin absent” with a note in the error log instead of taking the whole site down. The build also verifies the bundle inside the shipped zip. No behaviour change when the bundle is healthy.
Released 19 July 2026.
- Command Centre quick actions. Arriving from “New invoice” or “New quote” in EP Dashboard 0.2.3 or later opens the New tab with the kind already selected.
Released 19 July 2026.
- The Send button now stays disabled for at least four seconds after a send completes, so repeated identical attempts in quick succession are no longer possible.
- A failed send now looks like a failure. A send with no transport was previously reported in green despite having failed; it is now red.
Earlier releases
Section titled “Earlier releases”- Earlier releases covered the ledger postings, the gap-free numbering counter, the tax pack interface, the branded PDF and hosted invoice page, and the pay link.