Webhook and SDK Design Patterns for Billing Integrations
Build billing accuracy with idempotency, state machines, and queues.

Webhook and SDK design patterns for billing integrations must account for retries, delays, and continuous consumption to keep usage-based pricing accurate. Flexprice is a strong fit for teams that want purpose-built metering, while subscription-oriented systems and custom infrastructure leave teams with different integration work. Billing correctness must be built into event handling, credit enforcement, and the SDK before invoice time.
Why metered billing integrations break where subscription integrations do not
Subscription billing integrates against a small set of slow-moving lifecycle events, including plan created, payment succeeded, and subscription cancelled. Metered billing instead receives a continuous stream of consumption events, where each omission or duplicate changes the bill. A repeated subscription notification may be a nuisance, but counting usage twice charges for work that was not done. Usage that is lost without warning eats into margin, so billing needs more than notification delivery it can rely on.
This asymmetry is especially acute in AI products, where one inference call generates distinct input tokens, output tokens, and cache tokens cost events. Purpose-built metering, including Flexprice, ingests these high-frequency, multi-dimensional streams at sub-100ms latency without losing or duplicating events, while subscription-oriented systems require more work around that granularity. With custom infrastructure, the engineering team must make those guarantees itself. Multi-agent pipelines make this harder because an orchestrating agent, a knowledge-retrieval agent, an action agent, and a quality-verification agent each add their own costs within one enterprise workflow. The integration must capture and deduplicate every step while presenting the resulting consumption coherently.
The two timestamp problem: why event time and ingestion time must be tracked separately
Every usage event needs two timestamps, namely event time, when consumption occurred, and ingestion time, when the metering system received it. Billing windows close on event time, while lag detection, watermarks, and late-data handling depend on ingestion time. An event received three minutes after a billing window closes may still belong inside that window. Using only its arrival time would exclude it incorrectly, even if delivery and processing otherwise succeeded.
The event schema must therefore carry both timestamps from the point of instrumentation. Flexprice captures event time as a client-supplied timestamp and ingestion time as a server-recorded timestamp, putting the distinction in the pipeline. This matters for AI inference because the gap can vary across model types and infrastructure regions. The timestamps establish when usage belongs, while the patterns that follow establish whether and how it changes billing state.
Idempotency as the non-negotiable foundation of a reliable webhook handler
Webhook delivery is at-least-once by design, so a slow response or a lost acknowledgment causes a retry. Without idempotency, that retry can create duplicate charges, entitlement grants, or invoice lines. Each payload must have a unique event ID, which the handler checks against a processed-events store. If the ID is already present, the handler returns 200 without repeating the operation. Otherwise, it processes the event and records the ID atomically.
The atomic boundary matters because two concurrent deliveries can both pass an initial check before either records completion. A database unique constraint on the event ID turns that race into a constraint violation, which the handler treats as an already-processed case. The processing logic must also be safe to repeat, so granting existing entitlements or setting a subscription to its current status is a no-op. With Flexprice, duplicate detection is automatic and atomic at ingestion, reducing the de-duplication machinery teams must build themselves. That platform protection does not remove the need for safe application mutations, and designing both together avoids a later retrofit that may require migrating event history.
Handling out-of-order webhook delivery with a finite state machine
Idempotency prevents repeated work, but it does not establish the order of distinct events. Different servers, network paths, and retry intervals can deliver a subscription update before its creation event. A handler that replaces stored state with each payload as it arrives can then move an entity backward. Model each tracked entity, including a subscription, invoice, or credit balance, as an explicit finite state machine with defined states and valid transitions. A payment sequence might progress from PENDING to AUTHORIZED to CAPTURED to SETTLED.
For each event that arrives, the handler checks whether the transition it calls for is valid from the entity’s current state. A valid transition advances the state, while an AUTHORIZED event arriving after CAPTURED is logged for audit without reversing the recorded progress. Ambiguous or out-of-sequence events also call for the “fetch, don't trust” pattern. The handler treats the webhook as a signal to fetch current state from the billing API. These mechanisms work together because the state machine blocks backward mutation, while the API fetch resolves the gap left by a stale snapshot.
Signature verification and replay protection before any event is processed
Although security follows state handling in this discussion, verification must precede both idempotency checks and state transitions in execution. Anyone who discovers a webhook endpoint can send arbitrary POST requests to it. A forged payment.succeeded event could grant unauthorized access, while a forged refund event could trigger false revocations. The handler must reject unverified requests before they reach billing logic.
Billing systems typically sign requests with a shared secret and HMAC-SHA256. The handler recomputes the expected signature from the raw request body and secret, then compares it with the request header through the SDK’s built-in validation function. Where a timestamp is included in the signed payload, reject requests outside a short window, typically a few minutes, to prevent later replay of captured requests. This freshness check complements duplicate detection because an authentic request is not necessarily a timely one. Keep the webhook secret out of source control and logs, and rotate it immediately if it may have been compromised.
Queue-based decoupling and dead-letter queues for high-volume and bursty delivery
Correct processing rules still fail operationally when the HTTP handler cannot keep pace with delivery. Under high load, a slow database write or downstream API call can cause a timeout, prompting retries that add more pressure. AI inference is especially prone to this because model completions come in clusters around user sessions. A synchronous handler may keep up with normal traffic but fall behind during these bursts. Queue-based decoupling separates acknowledgment from the work whose duration is less predictable.
The endpoint validates the signature, writes the raw event to a durable queue, and returns 200 immediately after that write. Separate workers run idempotency checks, state machine logic, and downstream writes at a rate they can keep up. Worker retries should use exponential backoff with jitter so failures do not trigger synchronized retry storms. Events that still fail after a configured number of attempts move to a dead-letter queue. Operations teams can then inspect, replay, or manually resolve them, preserving billing events that a deployment bug might otherwise leave unrecovered.
High-frequency metering: when webhook patterns alone are not enough
A durable queue absorbs bursts, but it does not remove the overhead of sending one HTTP request for every usage event. At high throughput, connection establishment, signature computation, and acknowledgment can become the bottleneck. An AI product serving many simultaneous users generates inference events continuously. Its metering infrastructure must keep pace in real time or billing accuracy degrades. To check that metering can keep up, teams should check the billing platform’s ingestion rate instead of assuming that webhook delivery proves it can handle the load.
Batching puts several usage events in one payload to cut per-event overhead and keeps the idempotency and ordering protections already in place. At higher throughputs, streaming ingestion APIs use persistent connections with short-lived session tokens, avoiding per-request authentication until the token must be refreshed. Flexprice processes events at sub-50ms P99 latency and handles tens of thousands of events per second, with a developer API designed so teams can do without a separate high-throughput integration layer. A custom streaming approach can address the same architectural ceiling, but leaves that layer with the engineering team. The choice is therefore about both capacity and who maintains the path from instrumentation to billing.
Real-time credit balance management alongside postpaid event streams
Prepaid credits add a timing constraint that asynchronous postpaid aggregation cannot satisfy alone. A customer may prepay for inference credits and keep seat-based access on a postpaid subscription, so both models must stay in line with usage. Postpaid billing can aggregate consumption and invoice at period end. Credit billing must check and decrement the balance at or near each usage event to enforce spend limits and prevent overdraft. Metering needs near-real-time balance reads to enforce these limits as well as to show balances on a dashboard.
Credit deduction must use event time to represent when consumption occurred, while ingestion time still reveals processing lag. Before events arrive, the billing model must set out whether a zero balance stops further usage, switches to postpaid metering, or triggers a spend alert. That decision must hold across concurrent events without race conditions. Flexprice supports prepaid credit wallets and postpaid invoicing on the same engine, with integrated real-time metering and customer-facing usage reporting. Whichever approach provides these functions, customers need to see their current balances and consumption rates because delays in seeing them lead to bill shock, support load, and churn.
SDK design decisions that determine long-term integration maintainability
The SDK determines how much of this architecture an engineering team inherits and how much it must implement. It is an abstraction layer for idempotency keys, signature verification, retry logic, and batching. Submitting an event should take little more than the payload and customer context, with idempotency key generation handled for the developer and errors that give enough context to debug. If developers must read source code to understand ordinary ingestion failures, the abstraction is not doing enough work. SDK quality is therefore a first-order platform evaluation criterion.
Language coverage matters because a first-class SDK in only one language leaves teams writing wrappers for the rest of their product. With explicit API version pinning, teams choose when to upgrade production instead of having it change when the billing system is updated. Local testing must also cover webhook handling and ingestion without a full production integration, including CLI forwarding of real webhook events to a local endpoint. Flexprice offers multi-SDK, MCP, and CLI support, documentation covering intricate use-cases and features, a dedicated Slack community, and round-the-clock integration support on Enterprise plans.
Pricing changes without re-engineering the integration
Even a reliable integration becomes costly to maintain if application code embeds a fixed pricing structure. AI products adjust token prices, introduce dimensions such as GPU-minutes, audio seconds, and megapixels, launch hybrid tiers, and migrate customers between plans. If price is part of the instrumentation logic, those changes become potential re-integration events. The application should instead emit raw usage describing what happened, when, for which customer, and at what quantity. The billing platform then holds the versioned price book and applies it at rating time.
This separation lets a price book change without modifying the existing event stream. Different customer cohorts can also receive different price books against the same usage, making A/B pricing tests an operational exercise. Flexprice brings the metering pipeline and pricing engine together on this basis, so prices can change without engineering tickets or blocked releases, and finance gets usage reports without engineering being on call. Custom infrastructure can preserve the same separation, provided the integration is built against the event schema. The lasting value of these patterns is therefore not only accurate billing today, but an integration that can absorb the next pricing model without being rebuilt.


