Manual adjustments, support tooling, and audit logs: the hidden work of credits systems
Admin UIs for support, grant/revoke/refund flows, and a full audit trail are non-negotiable in production. Here's what that work actually entails.
When developers think about building a credits system, they usually focus on the happy path:
- Grant credits on signup or purchase
- Decrement on use
- Maybe run a renewal job
What gets overlooked: the operational layer
Support needs to:
- Fix mistakes
- Grant goodwill credits
- Handle refunds
Finance and legal need to know:
- Who did what
- When
- Why
That means building admin tooling, defining safe manual-adjustment flows, and maintaining a full audit trail. This work is invisible until something goes wrong. Then it's critical.
This article walks through why manual adjustments and auditability matter, what you have to build, and how to avoid the trap of "we'll just use the database."
Why manual adjustments are unavoidable
In any real system, edge cases and human decisions show up constantly.
Common scenarios
- A customer was charged twice due to a bug; support needs to refund and restore credits
- An enterprise deal includes a one-time grant of 100,000 credits; someone has to apply it
- A promo code was misconfigured and didn't fire; you need to grant the missing credits manually
- A user claims they didn't use the API during an outage; after investigation, you decide to top them up
These aren't edge cases—they're normal operations
None of these are rare. They're the normal operation of a business that cares about customers and contracts.
The danger of raw SQL
If the only way to change a balance is to run SQL against the production database, you're inviting:
- Human error
- No accountability
- No way to debug "what happened?" later
The solution: controlled adjustments
You need controlled manual adjustments: defined actions (grant, revoke, refund, adjust) that go through an application layer, with validation and audit logging.
What support actually needs
Support teams need to be able to:
1. Grant credits
For goodwill, promos, or contract terms, with:
- A reason
- Ideally an expiration or scope (e.g., "for account X" or "for plan Y")
2. Revoke or claw back credits
When a refund is issued or a grant was made in error, with:
- A reason
- A record of the action
3. Adjust balances
In exceptional cases (e.g., correct a bug that over-debited), with:
- A clear reason
- An audit trail
4. See history
For an account: what grants and adjustments were applied, by whom, when, and why. That way they can answer "why does this customer have this balance?" without asking engineering to query the DB.
Implementation requirements
This implies:
An admin UI or API that only authorized roles can use, with actions that map to your business rules (e.g., "grant" creates a ledger entry and updates balance, "refund" may create a negative grant or a separate refund record).
Full logging of every change:
- User ID (or service account)
- Timestamp
- Action type
- Target account
- Amount
- Reason
- Any reference (e.g., ticket ID, invoice ID)
Without that, you're flying blind when a customer disputes a charge or an auditor asks how a balance was determined.
The audit trail is non-negotiable
An audit trail answers: who changed what, when, and why?
What to log
For credits and plans, that means logging:
Grants and revokes (including manual ones):
- Who performed the action
- Which account
- How many credits
- Reason
- Timestamp
Consumptions (if you need to trace back "why did this usage happen?"):
- At least aggregate or sampled data
- Idempotency keys or request IDs so you can correlate with API logs
Plan or entitlement changes:
- Who changed the plan
- When it takes effect
- Why (e.g., upgrade, downgrade, support override)
"We'll add logging later" = never
Without auditability, you can't:
- Reliably debug disputes
- Satisfy auditors
- Train support effectively
"We'll add logging later" usually means it never happens or it's bolted on in a way that's incomplete.
Design for auditability from day one
Every mutation should go through a layer that writes an audit record. That often means a dedicated audit log table or stream (append-only, immutable) that your application writes to on every balance-affecting or plan-affecting action, with enough context to reconstruct the story later.
The danger of "we'll just use the database"
It's tempting to give support "read-only DB access" or a shared script that runs SQL.
The problems with direct database access
- Data corruption risk: One wrong UPDATE can corrupt data or affect the wrong account
- No audit trail: There's no structured audit of who ran what
- Business rules bypassed: Validation like "don't allow negative balance" or "expire this grant in 30 days" are skipped
Spreadsheets aren't better
The same applies to "we'll use a spreadsheet and then someone will apply changes." Manual processes don't scale and they don't audit.
You need an application layer
For manual adjustments, you need:
- An admin UI or a secure API
- Validation enforcement
- Changes applied through the same ledger and balance logic as the rest of the system
- Writes to the audit log
That's more work upfront, but it's the only way to keep operations safe and traceable.
How much tooling is enough?
You don't need a full internal CRM. You do need:
The minimum viable admin layer
-
Account identification: A way to identify the account (and optionally the plan or grant) to adjust
-
Core actions: A small set of actions (e.g., "Grant credits," "Revoke credits," "Apply refund") with required fields:
- Amount
- Reason
- Optional expiration or reference
-
Permissions: So only support or ops can perform these actions:
- Role-based access
- Separate admin app
- Scoped API keys
-
Audit logging: That captures all of the above for every change
Implementation options
That can be:
- A simple internal UI (a few forms that call your backend)
- An API that your support tool (e.g., Zendesk, custom dashboard) calls
The important part is that all balance-changing and plan-changing actions go through this layer and get logged.
Build vs. buy
If you're building a credits system in-house, budget time for this. If you're evaluating a credits API, check that it offers manual grant/revoke and an audit trail so your support team can operate without direct DB access.
credits.dev provides APIs for granting and managing credits with full traceability, so you get controlled adjustments and auditability without building and securing your own admin layer.
Summary
Manual adjustments and audit logs are the hidden work of credits systems.
Key requirements
- Support needs: Safe, controlled ways to grant, revoke, and adjust
- Finance and legal need: To know who did what and when
Build it in from the start
Building that into your system from the start avoids the "we'll just use the database" trap and keeps operations scalable and compliant:
- An application layer for adjustments
- An append-only audit trail
Don't make it an afterthought
Whether you build in-house or use a dedicated credits API, make sure this operational layer is part of the plan, not an afterthought.