# Week of 31 August 2026: everything that touches money or the account, first

> Eight commits on a Saturday: billing, the LinkedIn connection, the ICP written from a product page, and an alerting system. Five of the eight were fixes to the other three, and one of them was taking paying customers' access away.

By Adarsh Mamgain, 31 October 2026. From the Hellofew blog at https://hellofew.com/blog.

Part 2 of Building Hellofew, week by week. Every part: [Week of 24 August 2026: the schema before the product](https://hellofew.com/blog/building-week-1-the-schema-before-the-product.md), [Week of 31 August 2026: everything that touches money or the account, first](https://hellofew.com/blog/building-week-2-money-and-the-account-first.md), [Week of 7 September 2026: the loop closes, on a fake LinkedIn first](https://hellofew.com/blog/building-week-3-the-loop-closes.md), [Week of 14 September 2026: read the person before writing to them](https://hellofew.com/blog/building-week-4-read-before-you-write.md), [Weeks of 21 September 2026 to 5 October 2026: the quiet weeks, and the first two replies](https://hellofew.com/blog/building-week-5-the-quiet-weeks.md), [Week of 12 October 2026: the launch week, a name, and 94 commits](https://hellofew.com/blog/building-week-6-the-launch-week.md), [Week of 19 October 2026: writing that reads like a person, and the first fourteen replies](https://hellofew.com/blog/building-week-7-writing-that-reads-like-a-person.md), [Week of 26 October 2026: the week the replies came, and what broke on the way](https://hellofew.com/blog/building-week-8-the-week-the-replies-came.md).

The second week of the build was one day, Sunday 6 September, and it had the highest fix-to-feature ratio of any week in the log: three features, five fixes to them, all before dinner. I think that ratio is the honest shape of a week where you wire up the two things you cannot get wrong, taking money and holding somebody's LinkedIn session, and then find out what you got wrong.

## The three features

The first commit is the foundation: a real auth library, billing through Dodo Payments, the LinkedIn connection through Unipile, and the first thing the product writes, an ideal customer profile generated from a product page. That last one is still the first thing a new customer sees, and it is still free, because reading somebody's product page and telling them who to sell to is the cheapest possible way to let them judge whether the model has understood their business before they pay $49/month to find out.

The second feature is observability: structured logs, incidents with a severity tier, and an admin page to read them on. I built this before the product could send a single message, which looks like procrastination from the outside. It was not. A product that acts on a customer's LinkedIn account while they sleep has to be able to say what it did and why, and the first time it does something wrong, the log is the only witness.

The third is a command-line tool for registering the provider's webhooks, the notifications that say an account's session changed or a message arrived. Dull, and the kind of thing that gets done by hand once and then wrong forever. It has been run after every change to the webhook routes since.

## The five fixes, and the one that mattered

- A status webhook from the provider could clear the gate that decides whether an account is allowed to send. Fixed so that no webhook can ever open the gate; a webhook can only close it.
- The model was being asked for JSON without being shown the schema, and the tests were raising real incidents that paged me. Both fixed in one commit, because they were found in the same hour.
- The billing webhook wrote an audit row, and when that row failed to write, the customer's entitlement was rolled back with it. A paying customer could lose access because of a logging failure. Fixed by separating the two: the entitlement is written first and alone.
- The LinkedIn connection was not being recorded after the provider confirmed it, and the connection count was read from the wrong object in the provider's response. Both found by connecting my own account and watching nothing happen.

The billing one is the one I still think about. Nothing in the test suite would have caught it, because the audit row never failed in a test. It failed in the shape of a real webhook with a field I had not expected. The lesson is older than this product: the write that decides whether somebody is a customer must not share a transaction with anything that can fail for an unrelated reason.

## What the sending gate is, since it came up

From this week on, the question of whether an account may send is answered by one pure function that takes facts about the account and returns a decision. It refuses anything it cannot confirm: a connection count it could not read, a status it does not recognise, an account under 150 connections. The ramp is in the same file: 5 invitations a day to begin with, 20 at most after three weeks, and the ceiling of 20 a day and 80 a week sits beside it as a constant. There is no setting anywhere in the product that raises it, and there is no column in the database for one. [The limits page](/limits) is that file, rendered.

*Figure: The warm-up ramp: 5 a day for three days, then 10, 15, 18, and 20 from the fourth week.*

*The staircase the gate hands the planner, drawn from the constant that defines it. It has not changed since this week. A reconnect after a checkpoint starts it again from 5.*

The reason the first webhook bug mattered so much is that the gate is the whole safety argument. A limit that can be opened by a stray notification is not a limit. The fix that week was small; the rule it established, that nothing external can ever make an account more permissive, only less, has been applied to every status path since.
