Usage-based API billing with Apache APISIX and Lago

Meter API calls per customer at the gateway and send them to self-hosted Lago for pricing and invoicing, with a second log stream so no usage is lost when batches fail.

On this page

How usage-based API billing with APISIX and Lago works

Usage-based API billing with Apache APISIX and Lago works by having the gateway record every metered API call and push it as a usage event to Lago, which then prices the usage and produces invoices. The APISIX lago plugin is the supported way to send that request usage to Lago's REST API, whether you run self-hosted Lago or Lago Cloud. You need a metering record per customer, and the gateway is the one place where every authenticated call is already identified, so the plugin sits on the routes you want to bill and reports each request against a Lago subscription.

The plugin needs a few settings that decide what Lago receives. endpoint_addrs points to your Lago API, token authenticates the calls, and event_code must match a billable metric you have defined in Lago. event_transaction_id supplies a unique value per event so Lago can de-duplicate retries, and event_subscription_id can take variables such as the consumer name, which is how each API customer maps to its own Lago subscription. Confirm these field names and their allowed variables against the APISIX lago plugin documentation and your Lago version before you build the consumer model.

Lago handles what happens after the event arrives: it meters usage, applies pricing, generates invoices and manages payment collection. Lago does not collect money itself, so you need a separate payment processor such as Stripe, Adyen or GoCardless, and the billing team should confirm which one fits their regions and invoicing rules. Because the plugin sends events in batches and can permanently drop a batch if Lago stays unreachable after retries, the billing record is only as complete as your delivery design. Plan a second log stream of the same requests so that you can reconcile dropped usage before invoices close.

What you need before connecting APISIX to Lago

Metering with the lago plugin depends on four systems agreeing: the APISIX gateway, a Lago instance it can reach, a billing model inside Lago, and a payment processor that collects the money. Confirm each one before you write any plugin configuration, because a gap in any of them shows up later as missing or mispriced usage.

APISIX version and deployment mode

The lago plugin is documented for APISIX 3.x, so confirm the exact 3.x release you run and read the plugin page for that release before you copy any configuration. Also confirm whether the gateway runs in traditional, decoupled or standalone mode, because the mode changes where configuration lives and how you roll out plugin changes. Plugin fields and defaults can shift between releases, so verify them against your version rather than against examples.

Self-hosted Lago reachable from the gateway

Lago must run in infrastructure you control, with its API endpoint reachable from every APISIX data plane node that will send events. The self-hosted Docker deployment includes a front end, an API, an API worker, a clock worker, PostgreSQL, Redis and Gotenberg. Confirm the API and worker services are healthy before you test event delivery, since the gateway cannot tell a Lago outage from a configuration error.

Lago API token with scoped access

The plugin authenticates to Lago with an API token that you generate inside the Lago instance. Store it in a secrets system rather than in plain route configuration, and plan how you will rotate it, since a rotated token must reach every gateway node. Ask who in your organization owns the token and which Lago organization it belongs to, so that events land in the correct billing account.

Billable metric and plan in Lago

Usage events only become invoices when Lago has a billable metric whose code matches the plugin's event code, and a plan with a charge tied to that metric. Define the metric, its aggregation and the plan before going live, and create one subscription per customer. Event subscription identifiers you send from APISIX must match the subscriptions in Lago, or usage is recorded against the wrong account.

Payment processor for collection

Lago calculates what to charge and when, but it does not collect payment itself. You need a payment processor such as Stripe, Adyen or GoCardless connected to Lago before invoices can be paid. Confirm which processor your finance team uses, whether it supports the billing currencies and payment methods you need, and who holds the merchant account. This is a separate contract and integration from the gateway work.

Network and TLS requirements

Decide how gateway nodes reach Lago: over a private network or across a public endpoint, with TLS certificates that the gateway trusts. Check egress rules, proxy settings and certificate chains from every node, not just one. Because the plugin sends batched events and drops them permanently after retries, a network path that fails intermittently is the most likely source of lost usage, so test it under load before launch.

Configuring the lago plugin step by step

This sequence connects APISIX request traffic to Lago so each billable API call is metered against the right customer and subscription. The result is a gateway that sends deduplicated usage events to Lago, verified by test traffic you can trace end to end.

  1. Define the billable event code in Lago

    Your billing lead or Lago administrator creates a billable metric in Lago for the API usage you want to charge, and records its code exactly as it will be sent from the gateway. This code is what the lago plugin sends as event_code, so any mismatch means events arrive but cannot be priced. The step is done when the metric exists in the Lago instance you will use and its code matches your planned configuration. Confirm the metric type and aggregation with your pricing design before you go further, since changing it later affects historical events.

  2. Create consumers and map them to Lago

    Your platform engineer creates one APISIX consumer for each API client you bill, using the authentication plugin your APIs already use. Each consumer name must correspond to a Lago customer and an active subscription, because the consumer name becomes the identifier that Lago uses to attribute usage. Record this mapping in a reviewed table or in your provisioning code. The step is done when every billed consumer can be matched to exactly one Lago customer and subscription, and any unmatched consumer is listed for follow-up.

  3. Set endpoint and token for the Lago API

    Your platform engineer sets endpoint_addrs to the base address of your self-hosted Lago API, and sets token to a Lago API key with the rights needed to create events. Store the token through your secrets approach rather than in plain route files, and confirm that the gateway can reach the Lago API over the network path you have approved. The check is a single manual test event: send one request through a test route and confirm that the event appears in Lago with the expected code. If it does not appear, check connectivity and the token before changing anything else.

  4. Set event code and transaction ID for de-duplication

    Your platform engineer sets event_code to the metric code from the first step and sets event_transaction_id to a value that is unique per billable request, such as a request identifier that your clients or gateway generate. Lago uses this identifier to recognize repeated events, so a retried request does not create a second charge. Agree the identifier format with the team that owns the upstream services, since an identifier reused across requests will suppress legitimate usage. The step is complete when two sends of the same transaction identifier produce one event in Lago.

  5. Route subscription by consumer name variable

    Your platform engineer sets event_subscription_id to use the APISIX variable for the consumer name, so each event is tied to the subscription of the consumer that made the call. This avoids hard-coding one subscription per route and keeps routing consistent when you add consumers. Confirm the variable name against the lago plugin documentation for your APISIX version before deploying. The check is two test requests from different consumers, each producing an event attached to its own subscription in Lago. If both events land on one subscription, review the variable reference and the consumer mapping.

  6. Attach the plugin to billed routes

    Your platform engineer enables the lago plugin on the routes that carry billable traffic, and leaves unbilled routes such as health checks without it. Keep the plugin configuration in the same version-controlled source as your other gateway configuration so changes are reviewed. Check that the plugin runs after authentication on each route, because the consumer identity is needed to build the event. The step is done when the configuration is deployed to the gateway and a request to a billed route is accepted without errors in the gateway logs.

  7. Send test requests and reconcile in Lago

    Your QA or billing team sends a fixed set of test requests per consumer, including one repeated request with the same transaction identifier, and compares the counts in Lago with the expected totals. Remember that the lago plugin batches events and flushes them periodically, so allow the flush to complete before checking. The step is done when each consumer's event count matches the requests sent and the repeated request produced one event. Record the results. Because batches that stay undeliverable after retries are dropped, confirm that a second log stream captures the same requests before you rely on these counts for invoicing.

Mapping API consumers and requests to Lago events

This table shows which lago plugin fields are set once in the plugin and which are set per route, and what each one maps to in Lago. Read it before writing configuration so each billable request produces one event for the right customer and metric. The main takeaway is that the consumer identity and the request ID must be stable, or billing will double count or misattribute usage.

Field or mappingWhere it is setWhat it maps to in LagoWhat to confirm
Consumer name to Lago customerConsumer definition in APISIX, referenced by the event subscription variableThe external customer ID that Lago uses to attribute usageConfirm the consumer name matches the external customer ID exactly in your Lago setup
Consumer name to Lago subscriptionevent_subscription_id, using a variable such as the consumer nameThe subscription that receives the event for that customerConfirm the variable syntax in the lago plugin docs and whether one subscription per customer is your model
event_codePlugin configuration, usually set once for a route groupThe billable metric code that counts this request typeConfirm the code matches a billable metric already defined in Lago, including case
event_transaction_idPer request, derived from a unique request value in the plugin configurationTransaction ID Lago uses to de-duplicate eventsConfirm the variable syntax in the plugin docs and that retries reuse the same value
endpoint_addrs and tokenPlugin configuration, set once per gatewayLago API address and API key for event ingestionConfirm whether your self-hosted Lago API is reachable from each APISIX node
Route scopingPer route, by attaching the plugin only where usage is billedOnly metered routes produce eventsConfirm which routes are billable and exclude health checks and internal calls
Duplicate and retry handlingEvent transaction ID design across batchesLago drops or merges duplicates based on the transaction IDTest with a forced retry and confirm Lago records one event
Unmatched consumersGateway behavior when a request has no consumerNo customer to bill, so the event cannot be attributedDecide whether anonymous calls are rejected, unmetered or logged elsewhere

Why batches can be dropped and what a second log stream protects

The lago plugin sends usage events to Lago in batches of up to 100, and it flushes a batch every 5 seconds or when 1,000 entries are queued, whichever the gateway reaches first. The documented risk is the failure path: if Lago stays unreachable after retries, the affected batches are dropped permanently, and the plugin does not replay them later. For a metering record that feeds an invoice, that is a gap in billable usage, not a delayed write. The plugin documentation recommends pairing it with other logging for this reason, so the billing design should assume that the lago plugin alone is not the system of record.

A second log stream is the record that survives a Lago outage. In practice this is a separate access log written by APISIX to a durable store that you control, with the consumer name, route, timestamp and a request identifier on every line. The same identifier should be used as event_transaction_id so that each Lago event can be matched to its log line. When a batch is lost, the reconciliation job finds log lines with no matching event and re-submits them with the same transaction IDs, which Lago uses for de-duplication. Confirm with Lago how it handles a repeated transaction ID within your retention window before you rely on this.

The trade-off is that reconciliation runs against two sources that can disagree. Lago's event data is the billing input, but it may not reflect what was sent if the gateway retried or a batch failed partway. The log stream is complete for requests that reached APISIX, but it is not a billing record until it is matched against Lago. Decide who owns the comparison, how often it runs, which side wins on a conflict and how long both sources are kept. Ask your team to size the log store and the reconciliation window against your billing cycle, because a missed batch found after an invoice is closed is much harder to correct.

Securing the metering path and Lago tokens

The metering path carries a Lago API token from the gateway to the billing system, and it creates a second copy of request data in logs. The cards below cover where that token lives, how the traffic is protected, who can change the plugin, how the Lago host is hardened and what must stay out of the dropped-batch log stream.

Keep the Lago token out of plain configuration

The lago plugin needs a token to send events to Lago. Stored as a literal value in route or plugin configuration, it is visible to anyone who can read the Admin API or the configuration store. Check whether your APISIX version supports secret references for this field, and confirm where the resolved value is kept at rest. Rotate the token on a schedule and after any staff change that touched gateway configuration.

Use TLS to the Lago endpoint

Each event carries customer identifiers and usage counts, which are billing data. Configure endpoint_addrs with HTTPS only, and confirm that certificate verification is enabled on the gateway side, including for an internal certificate authority. Plaintext endpoints on a shared network segment are a finding in most billing and audit reviews, so treat an HTTP address as a configuration error to fix before go-live.

Restrict who changes plugin configuration

Anyone who can edit the route that carries the lago plugin can change the event code, the subscription variable or the endpoint, and silently redirect or stop billing events. Limit write access to the Admin API to named operators, require change review for routes that meter usage, and keep an audit trail of configuration changes. Test that a changed event_subscription_id produces the expected Lago subscription.

Pin the Lago release

Lago's self-hosting guidance recommends pinning the last tagged version rather than the latest image tag, so billing behavior does not change during an unplanned pull. Record the pinned version in your deployment code, review the release notes before each upgrade, and test a staging tenant against the same event codes and plans before production. Confirm the upgrade procedure with your Lago deployment owner before adopting a new tag.

Harden the Lago host and its data stores

The Docker Compose deployment runs PostgreSQL, Redis and Gotenberg alongside the API and workers, and each holds billing or customer data. Restrict network access so only the gateway and administrators reach the Lago API, keep the database and Redis off public networks, and back up PostgreSQL with a tested restore. Confirm which services accept external connections in your own topology before you open any port.

Keep tokens out of the second log stream

The dropped-batch log stream exists so billing events can be replayed, which means it must hold the event fields and nothing else sensitive. Do not log request headers, the Authorization header or the Lago token in that stream, and review any custom log format for accidental capture. Confirm the fields you record, set a retention period, and restrict read access to the people who run reconciliation.

Testing usage events and reconciling against invoices

How do I test that duplicate requests do not create duplicate billable events in Lago?

Send the same request more than once with an identical transaction ID and confirm Lago counts it once. The lago plugin uses event_transaction_id to de-duplicate events, so the test is only meaningful if the ID is derived from something stable per request, such as a request ID header your gateway sets. Run the test with a known consumer and a known event code, then check the event list in Lago for that transaction ID. Also test the case where a client retries after a timeout, because that is the most common source of double counting in production. Confirm the exact de-duplication behavior and its window in your Lago version and with the plugin docs before you rely on it for invoices.

What happens to usage events when Lago is unreachable during a test?

The lago plugin batches events and retries them, but batches are dropped permanently if Lago stays unreachable after retries. To test this, stop or block the Lago endpoint for a defined period while traffic runs through the gateway, then restore it. Afterward, compare the gateway request count for the window with the events Lago received. Any gap is usage that was not billed, and the plugin docs recommend pairing the plugin with another logging path so dropped batches can be recovered and reconciled. Confirm the retry count and timing in your deployed APISIX version, since those settings determine how much traffic a short outage can lose.

How do I compare gateway request counts with Lago event counts?

Reconcile per consumer and per billing period, not only in total. Count requests in your second log stream for each consumer over a fixed window, then count events in Lago for the same consumer and subscription over the same window. The two numbers should match except for requests you deliberately excluded, such as failed authentication or health checks, so define that filter before the test. Investigate every difference by transaction ID. Timezone boundaries and batches in flight at the cut-off are the usual causes of small mismatches, so align the window to UTC and allow for a flush interval at the edges.

Which fields should I check on each Lago event during testing?

Check that each event carries the expected event_code, a unique event_transaction_id, and an event_subscription_id that resolves to the right customer subscription. The subscription field can use variables such as the consumer name, so a naming mistake in consumers will send usage to the wrong subscription without any error. Test one consumer per subscription first, then several consumers at once, and verify that usage lands in the expected place each time. Record the mapping in a table so the reviewer can check it against the Lago customer records.

What should I review on invoice line items before go-live?

Review that each line item maps to a billable metric, that quantities match your reconciled event counts, and that the charge amounts follow the pricing you agreed. Check the billing period boundaries, the currency, and any tax or discount rules that apply to the test customers. Look at one invoice end to end and trace a few line items back to the gateway logs by transaction ID. Lago calculates what to charge and when, but payment collection runs through a separate payment processor, so also confirm that the invoice reaches the payment step as expected in your test environment.

Who should sign off on usage billing before it goes live?

Sign-off should come from the people who own each part of the chain: the platform team for gateway and plugin behavior, the finance or billing owner for pricing and invoices, and a reviewer independent of the build for reconciliation results. Written acceptance criteria help, for example a stated tolerance for the gap between gateway and Lago counts, a rule for how dropped batches are handled, and a list of invoice checks. Agree on these criteria before testing starts so that the result is a decision rather than a judgment made after the numbers are known.

Can my own team run this test plan without outside help?

Yes, if your team has the skills in gateway operations, the Lago API and finance reconciliation. The work is mostly careful setup and comparison, not complex code. The effort depends on how many consumers and plans you have, how much traffic the test needs to cover, and how much of the log pipeline already exists. Many teams underestimate the reconciliation step, so plan time for it separately. A partner can plan the test scope, run the failure scenarios and document the results in a fixed-scope engagement, with the scope agreed in writing before work begins.

What evidence should I keep after testing for audit or finance review?

Keep the test plan, the acceptance criteria, the raw gateway and Lago counts for each window, the list of duplicate and outage scenarios with their results, and the invoice samples you reviewed. Record the APISIX and Lago versions used, because behavior can change between releases, and keep the configuration of the lago plugin as deployed. This evidence helps finance answer disputes and gives auditors something concrete to examine. DeployOpen prepares systems, controls and evidence for compliance assessments, but independent auditors and certification bodies issue any audit reports or attestations.

Common failures when billing usage through APISIX

This table lists the failures teams most often hit when the lago plugin meters API calls into Lago, with the cause and the fix for each. Read it as a checklist to run before go-live and again after any Lago outage, endpoint change or consumer naming change.

FailureLikely causeFix
Events missing in LagoThe endpoint_addrs value points at the wrong host or port, or the token is not valid for the Lago organization receiving events. Failed calls can be silent at the gateway, so no error appears in Lago.Confirm the Lago API address and token against your self-hosted instance, send one test request, and check that an event appears in Lago before enabling the plugin on production routes.
Duplicate chargesevent_transaction_id is missing, constant across requests, or reused by retries that Lago should treat as separate usage. Repeated values can also cause Lago to discard events it considers duplicates.Set event_transaction_id from a value unique per request, such as a request ID that the gateway generates or receives once and keeps. Check in Lago that no two billable calls share an identifier.
Wrong customer billedThe event_subscription_id or consumer name variable resolves to a different consumer than intended, often after a rename, a shared key or a naming convention that differs between APISIX and Lago.Use one stable identifier per customer in both systems, write the mapping down, and test with two consumers that have different Lago subscriptions before release.
Gaps after a Lago outageThe plugin sends events in batches and retries. If Lago stays unreachable after retries, the batch is dropped permanently, so usage from that period is never sent to Lago.Keep a second log stream of usage data outside the batch path, such as an access log shipped to a durable store, so you can reconcile and replay missing events.
Inflated counts from retried client requestsClients that retry after a timeout send the same call again. Each attempt reaches the gateway as a new request, so each one is metered unless the event identifier deduplicates it.Decide which calls are billable, deduplicate on a client-supplied idempotency key where your API offers one, and reconcile counts against upstream records before invoicing.

Questions buyers ask about APISIX and Lago billing

What does it cost to build usage-based billing with APISIX and Lago?

The cost comes from three parts: the infrastructure you run for APISIX and Lago, the implementation work to map consumers, metrics and plans, and the payment processor fees Lago does not replace. Lago's FAQ states that businesses need a separate payment processor, since Lago calculates what to charge and when, then passes that to a gateway such as Stripe, Adyen or GoCardless. Effort rises with the number of billable metrics, plans and reconciliation rules. Ask any partner for a quote that lists one-time build work separately from recurring hosting, upgrades and support, and that names each payment provider in scope.

How long does setting up Lago usage billing take?

The duration depends mostly on your environment and your pricing model, not on the plugin configuration itself. Timing is driven by how many metrics and plan variants you bill, whether you connect an accounting system such as NetSuite, Xero, Salesforce or HubSpot, the access you get to your gateway and Lago environments, and how much testing you need against invoices before go-live. Lago's self-hosting docs also recommend pinning a tagged release, so you should plan an upgrade path early. Agree a timeline in writing only after the scope and the environment are documented.

What must we provide before implementation starts?

You need to supply four things: administrative access to a self-hosted or Lago Cloud environment, your product catalog with billable metrics and plan rules, a defined consumer model that maps each API key or gateway consumer to a customer, and an owner for the payment provider account. You should also name the people who approve invoice logic and reconciliation rules. Without a clear consumer model, the event_subscription_id field cannot reliably point each request at the right subscription, so this is the item most worth settling first.

Can our in-house team build this without a partner?

Yes, if your team has experience with both APISIX plugin configuration and billing data models. The work involves writing lago plugin settings for endpoint_addrs, token, event_code and event_transaction_id, deciding how consumer names are used as subscription identifiers, and designing reconciliation between gateway logs and Lago invoices. Teams without billing or finance engineering experience often underestimate the reconciliation design. A partner is useful when you want a fixed scope and written deliverables, or when your team cannot cover operations after go-live.

Does the open-source Lago edition cover our billing needs?

Lago's FAQ describes a forever-free open-source edition with fundamental billing features, and Enterprise plans that add premium features. Whether that edition covers you depends on which features you need beyond core metering, pricing and invoicing. Check the feature list against your plans, tax handling, dunning, reporting and integrations before you commit. The Lago platform is licensed under AGPLv3, so confirm with your legal team how that license applies to how you run and modify it.

Why do we need a second log stream if the lago plugin already sends events?

The lago plugin sends events in batches of up to 100, flushes every 5 seconds or at 1,000 queued entries, and drops a batch permanently if Lago stays unreachable after retries. The plugin documentation recommends pairing it with other logging, so a usage record is never lost silently. A second stream, such as a Kafka, Loki or ClickHouse logger, gives you a durable copy to replay into Lago and to reconcile invoices against. Confirm the retry and backlog behavior of each logger with your team before you rely on it for revenue.

What should we check on the Lago side before go-live?

Check that your Lago version is pinned to a tagged release, since Lago's self-hosting docs recommend this rather than the latest image tag. Confirm the Docker Compose components are running as expected, including the API worker and clock worker, PostgreSQL, Redis and Gotenberg. If your event volume is high, ask whether ClickHouse is needed, because it is an optional external store and disabled by default. Also verify that test events produce the invoices you expect, with duplicate events blocked by event_transaction_id.

Licensing and what Lago does not cover

Start the licensing review before the billing design is final, because the Lago platform is licensed under AGPLv3. Lago's agent SDKs and MCP server are MIT licensed, but they live in separate repositories, so the license on each component you deploy or modify may differ. Ask your legal team which obligations apply if you run a modified Lago release for internal use, if you expose it to customers or partners, and if you change its source. Keep the SDKs and any MCP server you adopt in a separate review line with their own license records. Do not assume that the APISIX license, which is Apache-2.0, carries over to Lago.

Lago meters usage, applies pricing and produces invoices, but it does not collect payment itself. Its FAQ states that a separate payment processor is needed: Lago calculates what to charge and when, then sends that to a payment gateway. The README names Stripe, Adyen and GoCardless as supported providers. Choose the processor, confirm its contract terms and card or bank-transfer coverage for your markets, and plan how failed payments flow back into Lago's invoice status. Those tasks sit with your finance and payments owners, not with the gateway team.

The README also lists integrations with NetSuite, Xero, Salesforce and HubSpot, but listing a connector does not configure it for your ledger or CRM. Account mapping, tax settings, customer record matching and the sync direction for each system are separate scoped work, and they need owners on the finance and sales side. Ask any implementation partner to state in writing which of these integrations are in scope and which are left to your team. Confirm current connector status with the Lago documentation before you commit to a design.

How DeployOpen scopes and delivers APISIX and Lago billing

DeployOpen plans, builds and hands over the metering path from APISIX to a self-hosted Lago instance inside your own infrastructure. Each engagement starts with a written scope that defines which APIs, consumers, subscriptions and billing rules are in play, and the work is documented so your team can run it afterward.

How we scope

  • Written scope lists the routes, consumers and API products that generate billable usage events.
  • We map each consumer to a Lago customer and subscription, and agree the event_code values before any build starts.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before work begins.

How we build

  • We configure the lago plugin with endpoint addresses, tokens and transaction IDs for de-duplication.
  • We deploy a second log stream for usage events so batches dropped after retries can be reconciled.
  • We test event delivery, batching, retry behavior and reconciliation against a non-production Lago instance.

How we hand over

  • You receive configuration, the event mapping, runbooks for Lago upgrades, and the reconciliation procedure.
  • We document how to pin the Lago release version and how the APISIX and Lago components are monitored.
  • Handover sessions walk your team through replaying missing usage and checking invoices against gateway records.

How we support

  • Ongoing support, upgrades and continuous testing are available as retainers after handover.
  • Retainers can cover APISIX and Lago version upgrades, reconciliation checks and changes to pricing event mappings.
  • Confirm with us during scoping which payment processor and accounting integrations your billing workflow requires.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.