Avo for finance teams

Run billing operations from inside your Rails app

Credits, corrections, and overdue invoices, worked from the same database the product runs on. Field-level permissions and an audit trail, instead of exports and engineering tickets.

250+ paying companies · 2.7M downloads of the avo gem

policy · segregation of duties per field, per action
policy allows support billing controller
See invoice status
See amounts and balances
Request a credit note
Approve a credit note

The person who raises a credit is not the person who approves it, and the policy that decides is Ruby in your repo, reviewed like any other code.

01

01 · the stakes

Where billing ops loses time, and trust

The numbers finance answers for live in the production database, but the tools to see and correct them usually don't. You don't have to be a fintech for this to hurt: any product that bills customers has a billing back office, and it usually runs on exports, tickets, and adjustments nobody can trace later.

  • 01

    Month-end runs on exports

    Reconciliation happens in spreadsheets built from CSVs someone exported on request. The numbers are stale by the time they're read, and every question that comes up means asking an engineer for another export.

  • 02

    Every adjustment routes through engineering

    Issuing a credit note, marking an invoice paid, fixing a billing record: finance knows the policy, engineering has the access. Each adjustment becomes a ticket, and the queue is longest exactly when the close deadline is nearest.

  • 03

    The truth is split between your app and the processor

    The payment processor's dashboard knows the charges; your database knows the customers, plans, and entitlements. Neither shows the whole picture, so answering "what happened with this account" means joining two systems by hand.

  • 04

    Adjustments leave no trail

    When a balance was corrected in a console session, there is no record of who, when, or why. That is an uncomfortable answer to give an auditor, and one you cannot reproduce the next time someone asks.

02

02 · the Avo version

Your models are already the hard part. Avo is the rest.

Avo mounts inside your Rails app, so invoices, subscriptions, and payments stay in your database and finance works on them directly. The adjustments become confirmed, logged actions, the close-week queues become saved views, and the dashboards read from the source of truth instead of an export. And the tool with read access to every amount and payment identifier stops sitting behind auth someone wrote in a hurry: the authorization and hardening around that access are our job to keep right.

Adjustments the moment the decision is made

Issue a credit note, mark an invoice paid, write off a balance: each is an Avo action with a confirmation step and a required reason, running one code path you wrote. The correction lands when finance decides it, not when the ticket clears.

The requester is never the approver

Avo reads your Pundit policies down to the field and the action, so raising a credit and approving one can be different roles, and amounts render only for the people cleared to see them. Who can change what is Ruby in your repo, not a rule someone remembers.

Queues for the invoices that need chasing

Overdue invoices, failed payments, credits pending approval: scopes and dynamic filters turn each into a saved view finance works down daily, oldest first, and hardest during close week, when the queue matters most.

Dashboards on live numbers

Revenue, outstanding balances, and failed-payment counts on dashboards built from your own queries against the production database. Invoice aging is your own bucketed query rendered as a card, so month-end starts from live figures instead of last Tuesday's export.

The auditor's question is a query, not a project

Pair Avo with model-level auditing and every adjustment records the acting user and the reason, in tables you can query and hand over when someone asks. On Enterprise, Avo's audit logging also records who viewed a record.

An Invoice resource with a credit note action that requires a reason:

class Avo::Resources::Invoice < Avo::BaseResource
  self.includes = [:customer]

  def fields
    field :number, as: :text, readonly: true
    field :amount, as: :number, visible: -> { current_user.finance? }
    field :status, as: :select, enum: ::Invoice.statuses
    field :due_on, as: :date
    field :customer, as: :belongs_to
  end

  def actions
    action Avo::Actions::IssueCreditNote
  end
end

class Avo::Actions::IssueCreditNote < Avo::BaseAction
  self.name = "Issue credit note"
  self.confirm_button_label = "Issue credit"

  def fields
    field :credit_amount, as: :number, required: true
    field :reason, as: :textarea, required: true
  end

  def handle(query:, fields:, current_user:, **)
    query.each { |invoice| invoice.credit!(amount: fields[:credit_amount], reason: fields[:reason], by: current_user) }
    succeed "Credited #{query.count} invoice(s)"
  end
end
03

03 · the timeline

From first resource to the team running on it

Hour one

Generate resources for Invoice, Subscription, and Payment and finance can browse live billing data with each customer's invoices and payments linked from their record.

Day one

Hook up the authentication you already use, write policies so finance edits while support reads, and ship the first action, a credit note with a required reason, so the first adjustment leaves the console.

End of the week

Overdue and failed-payment queues are saved views worked daily, the revenue dashboard reads from production, and month-end starts from live numbers with a trail behind every adjustment.

case study · the build-vs-buy math

“It's almost like having another developer on the team just focused on that side of things... it's paid for itself many times over”
Iain Beeston, Chief Technology Officer at Thrivve Partners · Read the Thrivve Partners story

04 · start today

Get finance off the engineering queue this week

Avo is per app with unlimited users, so the whole team works from it without the bill scaling with headcount. When you hit an edge Avo doesn't cover, you drop to plain Rails instead of filing a feature request.

Things finance teams run from Avo

Avo for your team

Avo by industry

Frequently asked questions

Can finance work billing from a Rails app instead of exports?
Yes. Invoices, subscriptions, and payments are ordinary Rails models, and Avo turns them into a billing workspace on top of your existing tables: saved views for the queues, actions for the adjustments, dashboards for the numbers. Because it runs inside your app, the data is always current.
Can we issue credits and corrections without a developer?
Yes. Each adjustment becomes an Avo action: a button with a confirmation step and a required reason, calling the same model method your product uses. Finance acts directly, the logic stays in one reviewed code path, and nobody opens a production console.
How do we control who can change billing records?
Your Pundit policies enforce it, down to the field and the action, so finance can adjust amounts while support only reads statuses, and requesting a credit can be a different permission from approving one. The rules are Ruby in your repo, reviewable in a PR and versioned in git.
Can we get revenue dashboards without a separate BI tool?
For operational billing numbers, yes. Avo's dashboards are built from your own queries against the production database, so revenue, invoice aging, and failed-payment counts are live. For deep analytical modeling a BI tool still earns its place. For the numbers finance checks daily, the dashboard next to the data is enough.
How do we answer an auditor's "who changed this"?
Pair Avo with model-level auditing and every change is recorded with the acting user, in your own database, where you can query and export it. Actions requiring a reason mean the justification is captured at the moment of the adjustment, not reconstructed later. Enterprise audit logging adds who viewed a record.
Does billing data leave our servers?
No. Avo is a Rails engine mounted in your application, so every record stays in your database and every request is served by your app. There is no hosted platform between finance and the numbers, so the security review stays short and the audit scope stays yours.