Source: https://billingmart.com/security # The rules the code enforces How money, card data, customer access, roles, workspace isolation and AI assistants are handled — each written as the rule the server applies, not as a promise. [Report a problem](mailto:security@billingmart.com) [What an assistant can do](https://billingmart.com/agents) ## Money is written by the server No browser, app, key or assistant can write an amount that is trusted. The server computes it. ### Only server functions write money Invoices, payments, the ledger, counters and usage cannot be created or deleted by any client. Staff can change cosmetic fields on an invoice, and nothing once it is paid. ### Totals are re-derived, never accepted An invoice’s total is computed from its stored lines when it is sent, and a total sent by a client is ignored. A charge is for the balance due held on the server, or for part of it if the payer chooses, and never for more than is due. ### Integer minor units, one formula Every amount is a whole number of cents (or the currency’s minor unit) stored beside its currency. The console preview and the function that sends an invoice import the same totals function. ### A second press never charges twice Before the gateway is called, a transaction claims the payment attempt and a time-boxed lease. A second press of Pay replays the first answer instead of charging again. A customer can pay part of a balance, each part is its own payment, and no payment is ever for more than is due. ## A card number is never stored The pay page is its own origin with its own rules, and a card number never reaches a database or a log. ### A separate pay origin pay.billingmart.com serves the invoice pay page, the payment-link page and the staff card-entry page under a strict Content-Security-Policy, with no analytics. The one third-party script it loads is Google reCAPTCHA, which App Check uses to tell people from bots. Customers enter a card to pay on this origin. The only other card field in the product is Stripe’s, where a workspace owner pays for a plan. ### The card number is a local variable It exists only inside the server functions that pass it to the payment gateway, to charge a card or to save one, and only while they run. What is stored is the last four digits and the card type. ### Gateway answers are filtered before storage Every response from the payment gateway passes an allow-list and a digit-masking pass before it is stored or logged. ### Gateway credentials are sealed Each workspace’s gateway credentials are encrypted with AES-256-GCM, readable only by server code, changed only with a second settings password, and switched to live only after a real self-test passes. ## A customer sees only their own bills Access follows a verified email address or phone number, not an account id or a guessable link. ### Verified contacts only A customer reaches a bill through a contact that is verified: the customer confirmed it with a link or a code. An unverified address resolves to nothing. ### The pay link is a snapshot A public pay link shows the lines and the amount due. Internal notes, references, history and who created it are never on it, and it expires. ### Sign-in without a password The customer portal signs in with an emailed link or a texted code that proves the contact each time. ## Every person has a role, and every change has an author What a person may do is decided on the server from their role in that workspace, today. ### Roles on the server Owner, admin, staff and viewer are enforced by the database rules and the functions. The console hides what a role cannot do, but hiding is not what stops it. ### Recent sign-in and a second factor Sensitive settings need a recent sign-in: five minutes unless the person chose a longer window after a code, up to eight hours. Approving an assistant’s or the Agent’s money or admin request always needs a second factor. Money actions taken directly in the console ask for one once enforcement is switched on for the platform, and warn until then. ### The audit log cannot be told who acted Every change made through the server is recorded with the actor taken from the verified sign-in token, never from what the request says. A few edits a team member makes directly under the database rules, such as time, expense and mileage entries, are not in the log. ## One workspace cannot read another The database denies everything by default, and a test suite tries to read across workspaces. It is run before each deploy. ### Default deny The database denies everything that is not explicitly allowed. Each collection a client can reach has an explicit rule and a test, and a collection without a rule cannot be read by any client. ### A cross-workspace leak suite A dedicated suite signs in as one workspace and attempts reads and writes against another. It is part of the rules tests, which are run by hand before each deploy; no automatic check blocks a merge on it. ### App Check on the data App Check is enforced on Firestore and Storage, so they accept requests only from an attested copy of the web app. The phone apps will use the same check when they are released. ### Webhooks cannot be pointed inward An endpoint must be https and must not resolve to a private, loopback, link-local or metadata address, checked again on every delivery. ## Assistants draft and ask An AI assistant connected to a workspace can read and prepare work. To send it or move money it asks, and the connection’s mode decides who approves. ### Some permissions cannot be granted Sending invoices, recording or refunding payments and managing webhooks are outside what an assistant’s credential can ever hold. ### Requests follow the connection’s mode Anything that reaches a customer or moves money becomes a request with a summary the server writes. In Ask, the default, each request waits for a signed-in person to approve it; Plan is a dry run that saves, sends and charges nothing; in Auto, which only the workspace owner can switch on for a connection (signing in again with a second factor, on a plan with auto-approve rules), the owner’s capped rule approves the requests it covers, and for a connected assistant refunds, voids, card or bank entry and the other never-auto requests still wait for a person. ### Some requests always wait for a person For a connected assistant, refunds, voids, credit notes and write-offs, starting a card or bank payment, and an email or text message it wrote itself are never approved by a rule. A person approves each one, even in Auto. ### Auto runs more for the built-in Agent A person the owner allows can put their own Agent in Auto for eight hours, after signing in again with a second factor, on a plan that includes auto-approve rules and with the owner’s rules switched on. The owner’s capped rules then approve what they cover, which for the Agent can include refunds, voids, credit notes and write-offs. Card or bank entry and every admin action still wait for a person. ### Models return data, not markup Every AI generator answers in schema-checked JSON, and fields outside the schema are discarded. A generated template or theme is a draft, and a draft an agent wrote itself waits for a person to publish it. The one free-text answer is the built-in Agent’s chat reply, which is plain text shown as text, never markup or a link. ## What we have not done yet, and how to reach us There is no certification or third-party audit to point to yet. An independent review is part of the launch plan. ### Report a problem Write to security@billingmart.com with what you found and how to reproduce it. Please do not test against other people’s workspaces. ## Read the rules before you trust them The developer guides describe the same rules from the API’s side. [Start free](https://app.billingmart.com/sign-up) [Developer guides](https://billingmart.com/developers) --- This is the Markdown copy of https://billingmart.com/security. Live plans, prices and limits are published as JSON at https://billingmart.com/plans.json and https://billingmart.com/agent-info.json.