No Deposit, No Files
Money that arrives on time is not a discipline problem. It is a systems problem — and the fix is a deposit that holds the work whether or not you feel like insisting.
Delphine Roussel · Marketing operations consulting · Featured capability: Deposits, invoicing and automatic chasing
Results at a glance
- 61 → 19 — average days from invoice to payment
- €0 — unpaid-deposit write-offs across three quarters
- ~€9,000 — cash pulled earlier into the year by a 50% deposit
Composite scenario. The person named here is not a customer: the protagonists are composites drawn from real usage patterns, and the figures are proportional to a solo freelancer or small studio rather than measured from one account. Every mechanism described is implemented in the product as written.
The consultant
Delphine Roussel runs lifecycle and marketing-operations engagements for B2B SaaS companies from Lyon, mostly HubSpot and Customer.io rebuilds priced between €8,000 and €40,000. She is very good at the work and, by her own account, was bad at every part of the business that came after it.
The breaking point
There was no single incident, which is worse, because there is nobody to blame. Delphine's contracts said 50% up front. In practice she sent the audit deck first, because the client was excited and she wanted to keep momentum, and then requested the deposit.
Most clients paid. One did not. A Series A company took her 40-page lifecycle audit, told her the deposit was "in the next payment run", and stopped replying. She had already handed over the entire strategic value of the engagement — the recommendations were the deliverable, and they now had them. She wrote off €6,200 and did not send a single chasing email, because every draft she wrote read either apologetic or aggressive and she could not make herself send either.
The structural problem was worse than the one write-off. Her chasing was manual, so it happened when she was calm and stopped when she was busy — which is precisely inverted, because she was busiest immediately after delivering the most work. Two invoices sat past 70 days that year purely because she never got to them.
How Stria solved it
Delphine now raises a deposit invoice flagged to gate kickoff, and the project sits at awaiting_deposit until it clears. Here is the design decision that changed her behaviour rather than just her intentions.
The hold is enforced at the function that mints the signed file URL, not in the page that renders the file list. That function derives the object path from the database rather than from the request, so a client holding a share link cannot ask Stria to sign an arbitrary path — and withholding files from the client's view alone would have been cosmetic, since the underlying URL would still have worked. The check also fails closed: a timeout, a permission error, or any answer it cannot interpret withholds the file. Only one specific case, the gating predicate not being deployed at all, is treated as "no gate configured."
She was told about a bug that had been found and fixed, and it is the reason she believes the gate. The collectability test used to enumerate the statuses open and overdue, which meant a client who paid one euro of a €2,000 deposit flipped the invoice to partially_paid and released every withheld file. A gate a token payment can open is not a gate. It is now a single shared predicate that every receivable surface uses, so the eight places that used to answer this question separately cannot drift apart again.
There is also an audited escape hatch with a written reason, capped at 500 characters, because waiving a deposit is a normal commercial act and a gate without an override is a trap. Delphine has used it twice, both times deliberately.
Payment runs through Stripe Checkout on her own connected Stripe account as a direct charge. There is no application fee and no transfer data, so it works on a plain Standard account and the money lands in her balance with her payout timing and her own dispute exposure. Stria charges no platform fee on top of it. Several details matter here more than the headline:
- No card field is ever rendered by Stria. The browser is redirected to Stripe's hosted page, which keeps her on the lighter PCI self-assessment.
- The amount is never in the request. The request body carries an invoice id; the amount, currency and destination account are read from the invoice row server-side. There is no request shape that pays a different figure.
- The idempotency key includes the amount, not just the invoice. If a late fee lands between two payment attempts, the key changes and a fresh session is raised rather than replaying the stale pre-fee amount.
- Paid status is written only from the Stripe webhook, never when a browser reaches a success URL it could have typed by hand.
Then the chasing, which she no longer does. A nightly job reconciles overdue invoices, applies late fees from her own policy — a percentage, a flat amount and a grace period she sets, and only after a final notice has actually gone out — and sends up to three reminders per invoice with a five-day minimum gap between them.
The three are not the same email: friendly, then firm, then a final notice that names the fee. One body sent three times teaches a client that the third one means nothing. Every message goes out under her own studio's brand rather than Stria's, with amounts and dates formatted in the client's locale and currency. An unbranded final notice reads like spam, and one headed with a vendor's name reads like a stranger's collection agency. Invoices being collected by Stripe's own dunning are excluded server-side, so no client is ever chased twice for the same money.
Two screens carry the rest. A cross-client receivables ledger gives her one row per issued invoice with the outstanding amount, days overdue, whether the invoice was ever actually sent, and whether a late fee is available — drafts and voids excluded, because a draft was never issued. And an automation-health view joins the scheduled-job list to the heartbeat every job writes, answering a question she did not know to ask: are the reminder jobs actually running? Uncollected money cannot hide behind a task that silently stopped being scheduled.
Results and business impact
Average days from invoice to payment across all clients fell from 61 to 19.
- Zero unpaid-deposit write-offs across three quarters, against €6,200 the year before.
- Two late fees totalling roughly €1,800 charged automatically. She waived one deliberately and kept the other.
- A 50% standard deposit, raised from 30%, because the hold made it enforceable rather than merely stated. That moved somewhere near €9,000 of the year's cash earlier into the year.
The change she rates highest is not on that list. Delphine declined to renew with a chronically slow client for the first time, and she attributes that directly to being able to see, on one screen, exactly what the relationship had been costing her in float. Before, the cost was real but invisible, so it never made it into the decision.
Why this feature matters
An invoice you meant to chase is unpaid work, and a deposit you asked for but did not wait for is a loan you did not agree to make.
Both failures are behavioural, which means the fix has to be structural. The deposit has to hold the files whether or not you feel like insisting on the day. The third reminder has to go out on the night you are too tired to send it. And you have to be able to check that the thing sending it is actually still running.
Try it yourself
The deposit hold, invoicing on your own Stripe account and the receivables ledger are all reachable on the free plan — enough to run one real engagement end to end, deposit through payment, before you pay for anything. Start a 14-day trial at getstria.com, connect your own Stripe account, and the money is yours the whole way through.
More case studies
- How a Shopify dev recovered £9,400 in change orders
- "We never approved that": ending a 9-week dispute
Start your 14-day trial · Try a free scope check · All case studies