You can't tell from the total. Hours are in question when they fail any one of three tests: a named person at the contracted level, a delivered item, or an approved change. One billing month of paperwork shows which. We'd audit a single invoice before accusing anyone, send the agency a short exception list, then cap, renegotiate or replace depending on what failed.
Is it overcharging, expensive or under-scoped?
Those are three different problems, and a high bill alone doesn't tell you which you have. White Internet, which publishes a guide to checking software supplier invoices, separates them: billing accuracy (does the invoice match the contract), delivery performance (is the work done to the expected standard and pace) and business value (is the project still worth investing in).
Paperwork settles the first two. The third is a market question, and the only honest way to answer it is a second quote for the same scope from another vendor. Don't call a vendor expensive until you have one.
How to audit one agency invoice in an afternoon
Start with one billing period, or one disputed milestone if you have one. Auditing a year of invoices is how this turns into a fight before it's a question.
1. Request one billing period's paperwork
Ask for five things in one email:
- the invoice with line detail
- timesheets by person
- the contract's rate card and named-staff schedule
- written approvals for any extra work
- delivery records, meaning releases and closed tickets
A bad answer is a delay, a summary instead of detail, or timesheets that only show totals per role.
2. Match every line to the contract
Check each invoice line against five things: what the contract says you pay for, any changes you authorised, the invoice detail, the delivery records, and whether you signed the work off as delivered. For hourly work that means: is the rate the agreed rate, is the role the agreed role, does the period match, and is the work inside the scope? Mark every line that fails any of those. Don't judge yet.
3. Match hours to named people and their level
Take each timesheet name and look it up in the contract's named-staff schedule. Is that person at the level they're billed at? How many hours did your senior people actually work? Prizmstack, a vendor that publishes quote-checking advice, tells buyers to confirm named people, experience levels and how many quoted hours senior staff work. That advice is aimed at quotes, but a running invoice is better: the timesheet gives you the answer.
A bad answer: a seat billed as senior and logged by someone the schedule lists as mid, or senior hours that are a fraction of what the rate card implied.
4. Sort every extra-work line into one of five types
The same White Internet guide splits extra work into five types, each with its own question:
- New requirement: did you ask for it, and in writing? Example: a reporting screen nobody mentioned until week six.
- Defect correction: what do the warranty or defect terms say? Example: a bug in something already delivered.
- Unresolved requirement: who was responsible for discovery, and what was assumed? Example: "export to CSV" was in the brief but nobody defined which columns. Incomplete discovery can create cost without anyone overbilling on purpose.
- External change: how does your agreement allocate this risk? Example: a payment provider retires its old API and the integration has to be rewritten.
- Repeated implementation: why was the original approach chosen, and who carries the cost? Example: a feature built once, thrown away and built again.
A defect fixed on your dime and a feature built twice can look identical on an invoice and mean opposite things.
5. Tie each block of hours to something you can use
For every block, ask what you can open, run or read as a result. Prizmstack's advice also flags vague line items like "project management" with no deliverables: compare the hours to the outputs. A PM can legitimately justify their hours with a roadmap, release notes or a risk log (a short list of what could go wrong, who owns each item and what's being done about it).
Hourly billing with no cap rewards taking longer, according to Hurricane Studio, which sells a technical co-founder service. So a block of hours with nothing to show is the first one to question. Hurricane calls three months or more with no working software the clearest sign of trouble.
6. Send a one-page exception list
Put each concern on one row: invoice line, amount, concern, evidence requested, and the agency's response. Send it in writing and give them a date to reply. Escalate stepwise. Pay what isn't in question, and ask a lawyer in your contract's jurisdiction before you hold back the rest.
Worked example: one month, four engineers and a PM
These are example contract terms, not market rates. The contract names two senior engineers at EUR 100 an hour, two mid-level engineers at EUR 70 and one PM at EUR 90. In the month, each engineer logs 160 hours and the PM logs 80.
| Line | Hours | Rate (EUR) | Amount (EUR) |
|---|---|---|---|
| 2 senior | 320 | 100 | 32,000 |
| 2 mid | 320 | 70 | 22,400 |
| PM | 80 | 90 | 7,200 |
| Total | 720 | 61,600 |
Now run steps 3 to 5 against the paperwork.
| Finding | Check | Math | In question (EUR) |
|---|---|---|---|
| One senior seat logged by a mid-level person | Step 3 | 160 h x (100 - 70) | 4,800 |
| 30 h "login fix" for a release 2.3 bug, mid rate | Step 4 | 30 h x 70 | 2,100 |
| PM hours, 11.1% of the month | Step 5 | Not disputed | none |
The PM line stays out of the exception list because the hours are plausible. You still ask for the roadmap or risk log that backs them. The list totals 6,900 of 61,600, or 11.2% of the invoice.
Call that money to ask about, not an overcharge. The senior seat may be a promotion nobody wrote down, and the login fix may be covered by your defect terms. Either way, you now walk into the conversation with two lines and a number, not a feeling.
What if the senior you paid for isn't the one working?
This is the finding that stings most. Digiday's 2017 reporting on marketing agencies describes clients complaining they get more junior people than agreed. It explains the mechanism: agencies bill by rate-card level, so a senior seat bills higher than a junior one, and when a client limits what it will pay, agencies tend to staff cheaper juniors. Software teams bill the same way, so the mechanism is worth checking for.
Step 3 is the test. Here is what to ask for on top of it: the name, level and start date of every person on the invoice. What you can't prove is a person's actual skill from a title. A mid-level engineer with a senior label may be excellent, and your complaint is then about the rate, not the work.
Going forward, the fix is contract language: named staff, and notice before anyone on the schedule changes. We'd ask for credit on the rate gap for past months, and for the terms in our guide on what to renegotiate when the contract comes up for renewal. Digiday also found that promises of dedicated full-time people are hard to enforce, which is why the named-staff term carries the weight.
Cap, renegotiate or replace: what each finding points to
Staying and fixing it is the first option, and often the right one.
| What the audit found | Move |
|---|---|
| Hours match, you just spend too much | Cap spend; cut scope |
| Rate or level mismatch | Credit request; named-staff term |
| Unapproved extra work | Written approval rule |
| No delivery for the hours | Independent technical review, then replace |
If you cap, use the three spending controls White Internet lists together: an expenditure cap, prior approval above a threshold and a regular forecast. An independent technical review means a senior engineer with no tie to the agency reads the code and release history and tells you what the hours bought. If you also want to stop paying by the hour, the trade-offs are in fixed price against time and materials.
Before you replace anyone, confirm in writing that you hold the repositories, cloud accounts and domains. Hold the access first, so a dispute can't put it at risk. The steps are in taking over a codebase when the agency won't cooperate.
What this means for your next renewal
Run the audit before the renewal date, while you can still decline the next term. Decide in advance who sends the exception list and by what date the agency must reply, so the findings land before the signature, not after.
The table above gives the move for each finding. One outcome sits outside it. If the audit shows you're mostly paying for coordination you don't need, such as PM hours and account management around a team you could manage yourself, the question changes from "which agency" to "should this work move in-house." Our guide to moving agency work in-house on cooperative terms is the next read. The wider set of options sits under software development engagement models.
Hiring senior engineers you can see on the invoice through HighCircl
If the audit leaves you wanting to see who works on your product and what the margin is, that's the model we run. HighCircl places senior engineers only, with no mid-level or junior people on the team. Our margin is 20%, capped, added on top of what the engineer earns and disclosed separately. We're a vendor too, so audit our invoices the same way. See senior engineers through HighCircl.
FAQ
How do I know if my dev agency is overcharging me?
Don't judge by the total. Ask for one month of line-item invoices, timesheets by person and the contract's rate card, then check each hour against three tests: a named person at the agreed level, a delivered item, an approved change. Hours that fail any one of those tests are what you raise with the agency.
Can I ask my agency for timesheets by person?
You can ask. Hourly billing rests on time records, so the request is routine. Whether you have a contractual right depends on your contract and jurisdiction, so check the wording or ask a lawyer. If they only offer role totals, note that in your exception list.
Can an agency swap a senior developer for a junior?
It depends on what your contract says about named staff and notice of changes. Digiday's reporting on marketing agencies shows the mechanism: billing by rate-card level makes a cheaper person on a senior seat profitable. Compare timesheet names with the contract's staff schedule to find out.
Can I withhold payment on a disputed invoice?
Get legal advice first. White Internet advises it before withholding payment or terminating. Pay what isn't in dispute, list the disputed lines with the evidence you've asked for, and let a lawyer in your contract's jurisdiction tell you what's safe to hold back.
Does a fixed price remove the problem?
It moves it. Fixed-price work puts the weight on change orders. Prizmstack suggests checking whether change orders bill above the base rate, who decides what is out of scope, and whether clarifications get billed as changes.
