This reference covers the Payments module services, REST endpoints, filters, and integration points. The Payments module is optional and enabled via brm_enable_payments in BricksMembers → Modules.
Core Services
All services live under \BaselMedia\BricksMembers\Services\ and use the singleton pattern.
- BillingOrchestratorService — Single write entry point for normalized billing mutations. Handles idempotency, persistence order, status normalization, event dispatching, and access-sync handoff. All adapters (native, integrated, webhook) feed into this service.
- BillingDataService — Read-model for current subscription state, payment history, and frontend/dynamic-tag consumers. Use
get_user_subscriptions(),get_active_subscription(),get_latest_subscription(),get_subscription_payments(),get_last_payment(), andget_user_one_time_payments(). - BillingSourceConfigService — Reads/writes offers (
brm_payments_offers), provider credentials (brm_payments_settings), and source configs (brm_payments_sources). Useget_offers(),get_offer($key),get_webhook_billing_profile(),resolve_offer_key_for_product_ids(),get_offer_checkout_providers(), andget_offer_default_checkout_provider(). - BillingActionService — Executes member actions: manage billing, cancel subscription, refresh state. Use
resolve_manage_url(),cancel_subscription(),get_subscription_action_support(). - BillingAccessSyncService — Decides when access levels are granted/revoked based on normalized billing state. This is the only place where billing state triggers level mutations.
- BillingContextResolverService — Resolves the current loop subscription or offer for dynamic tags and Billing Action element.
- CheckoutSessionService — Persists BRM checkout-session rows in
wp_brm_checkout_sessions, attaches external provider session IDs, and records completion state for confirm/webhook recovery. - CheckoutElementSupport and CheckoutRenderContext — Own the atomic Bricks checkout v2 render/bootstrap path, signed checkout intent payloads, and request-scoped checkout offer context for child elements and checkout-aware dynamic tags.
Payments and Gifting Relationship
Native Payments gifting does not create a second business owner inside the Payments module. Payments owns checkout capture, offer config, provider handoff, and billing normalization. The Gifting module still owns the gift mutation contract.
- GiftWriteService is the canonical native gift write owner after billing persistence succeeds.
- GiftHistoryReadService is the shared-table read owner for native gift lookup and admin records.
- GiftClaimController owns the public claim route adapter at
?brm_action=claim_gift&gift_token=.... - BillingAccessSyncService suppresses purchaser access for unclaimed native gifts until claim succeeds.
Native gift checkout reads three settings layers:
brm_enable_giftingandbrm_gifting_settingsfor shared gifting mode and recipient-account behaviorbrm_payments_settings['gifting']for global native Payments gift checkout behaviorbrm_payments_offers[$offer_key]['gifting']for offer-level gifting enablement
Commerce Mapping Resolution
0.9.82 centralizes catalog identifier matching so access mappings and billing offer resolution stay aligned across commerce integrations.
\BaselMedia\BricksMembers\Utilities\ProductLevelResolver::resolve_levels()— Shared helper for level resolution from product-style identifiers.BillingSourceConfigService::resolve_offer_key_for_product_ids()— Shared helper for resolving the BRM offer key from commerce identifiers stored inoffer['providers'][$provider]['product_ids'].- WooCommerce passes product IDs and variation IDs.
- FluentCart passes product IDs and variation IDs.
- SureCart passes product IDs plus price IDs and variant IDs.
Use the same catalog identifiers in both your access mapping settings and your billing offer mappings when you want the purchase that grants access to also resolve to the expected BRM billing offer.
REST Endpoints
All routes are under /wp-json/bricksmembers/v1/billing/. Namespace: bricksmembers/v1, base: billing.
Checkout & Manage
- POST /bricksmembers/v1/billing/checkout — Create a hosted checkout session or the shared PayPal native checkout bootstrap. Params include
offer_key,provider,checkout_intent,checkout_mode, and optionalgiftpayload. Returns a provider redirect URL for hosted flows. Permission: public (login enforced by provider flow). - POST /bricksmembers/v1/billing/create-embedded-checkout — Create an embedded checkout bootstrap for the atomic checkout v2 flow. Returns provider bootstrap data. For Stripe, the response includes the Checkout Session
client_secretand publishable key for the active browser session only. BRM does not persist theclient_secretin its tables or options. - GET /bricksmembers/v1/billing/checkout-status — Read-only return-flow recovery for Stripe embedded checkout. Validates the BRM checkout token plus Stripe session ID, reads the current Stripe Checkout Session state, and resolves the final BRM
success_urlorcancel_urlfrom the stored checkout-session row. - POST /bricksmembers/v1/billing/manage — Create billing portal/manage session. Params:
subscription_id,return_url. Returns redirect URL. Permission: logged-in. - POST /bricksmembers/v1/billing/cancel — Cancel subscription. Params:
subscription_id,at_period_end. Permission: logged-in. - POST /bricksmembers/v1/billing/refresh — Refresh subscription state from provider. Params:
subscription_id. Permission: logged-in. - POST /bricksmembers/v1/billing/paypal/confirm — PayPal subscription confirmation callback. Permission: public.
Public checkout failures intentionally return a generic message to the browser, while provider/exception details are logged server-side. That keeps billing diagnostics available without exposing internal adapter errors to unauthenticated callers.
Native gifting extends the checkout request with an optional gift payload. PaymentsRestController validates that payload on both the hosted checkout route and the embedded checkout route, but only when both the Gifting and Payments modules are active, the offer allows gifting, the provider supports the requested billing model, and recipient validation passes.
On Bricks frontend surfaces, brm-billing-checkout does not disappear silently when no provider option can be resolved. Instead it renders a visible unavailable state (Checkout is currently unavailable.) inside the normal checkout wrapper. This is separate from runtime checkout failures: empty or incomplete configuration shows the unavailable state, while provider/session creation failures still surface a generic error message.
Bricks Checkout Surfaces
The Payments module currently ships two checkout surfaces in Bricks. They coexist intentionally.
- BRM Checkout (Legacy) — single-element checkout surface in
src/Elements/BillingCheckoutElement.php. Keep it for existing pages that already depend on the older button/link workflow. - Atomic checkout v2 —
BRM Checkout Contextplus child elements undersrc/Elements/Checkout/in thebricksmembers-billingbuilder category. This is the recommended surface for new pages.
The atomic suite keeps the render layer thin. The Bricks entry files are only element adapters. Offer resolution, provider availability, signed checkout-intent generation, asset bootstrapping, and request-scoped context all stay in CheckoutElementSupport and CheckoutRenderContext.
Read Endpoints
- GET /bricksmembers/v1/billing/subscriptions — List current user’s subscriptions. Permission: logged-in.
- GET /bricksmembers/v1/billing/payments — List current user’s subscription-linked payment rows. The current endpoint aggregates payments from the user’s billing subscriptions; it does not currently list standalone one-time payment rows returned by
BillingDataService::get_user_one_time_payments(). Permission: logged-in.
Provider Webhooks
- POST /bricksmembers/v1/billing/webhook/stripe
- POST /bricksmembers/v1/billing/webhook/paypal
- POST /bricksmembers/v1/billing/webhook/square
These receive native provider webhook payloads. Configure the URLs in each provider’s dashboard. Permission: public (signature verification handled internally).
For PayPal, certificate-based verification is locked to HTTPS certificate URLs on the official api.paypal.com and api.sandbox.paypal.com hosts before BRM fetches the signing certificate.
Webhook-based billing sync for non-native providers still enters through the generic /wp-json/bricksmembers/v1/webhook endpoint and the Webhook Mapping page. The Payments module reads the resulting normalized billing profile from brm_webhook_billing_profile.
Webhook Hardening and Reverse Proxies
Billing webhook endpoints apply additional request hardening before provider-specific signature validation runs. BRM derives the client IP from REMOTE_ADDR by default and only trusts forwarded headers when the request comes from a private/reserved proxy address or from a proxy explicitly allowed through filters.
brm_billing_trusted_proxy_ips— Allow specific proxy IPs to supply forwarded client IP headers.brm_billing_trusted_proxy_cidrs— Allow a proxy CIDR range to supply forwarded client IP headers.brm_billing_webhook_rate_limit_window— Override the transient window, in seconds, used for billing webhook rate limiting.brm_billing_webhook_rate_limit_max— Override the maximum requests allowed in the rate-limit window for a provider. BRM uses provider-specific defaults.brm_billing_webhook_max_body_bytes— Override the maximum raw webhook request size accepted for a provider.
If your site sits behind Cloudflare, Nginx, a load balancer, or another reverse proxy that terminates TLS before WordPress, document that proxy in the trusted-proxy filters instead of trusting all forwarded headers globally. Otherwise BRM falls back to the proxy’s direct IP for rate limiting and audit decisions.
Filters
brm_payments_resolve_manage_url
Override the manage billing URL for a subscription. Useful when using WooCommerce, FluentCart, or SureCart—return your My Account subscriptions URL instead of a provider portal.
add_filter( 'brm_payments_resolve_manage_url', function( $url, $subscription, $return_url ) {
if ( 'woocommerce' === ( $subscription['provider'] ?? '' ) ) {
return wc_get_account_endpoint_url( 'subscriptions', '', wc_get_page_permalink( 'myaccount' ) );
}
return $url;
}, 10, 3 );
Parameters: $url (string|null), $subscription (array), $return_url (string). Returns: string|null — Return a URL to override, or null to use default.
brm_payments_access_decision
Override the access decision when billing state changes. Return true to grant access, false to revoke, or null to use default logic.
Parameters: $decision (bool|null), $user_id (int), $status (string), $offer (array), $subscription (array).
Billing Events
BillingOrchestratorService fires brm_event_{type} for each normalized event. Types include: billing_subscription_created, billing_subscription_activated, billing_payment_succeeded, billing_payment_failed, billing_subscription_cancelled, billing_subscription_expired, billing_trial_ending, billing_renewal_upcoming.
add_action( 'brm_event_billing_subscription_activated', function( $event ) {
$user_id = $event['user_id'] ?? 0;
$offer_key = $event['offer_key'] ?? '';
// Custom logic
}, 10, 1 );
Options
brm_payments_offers— Offer definitions (key, label, levels, billing_model, provider config)brm_payments_settings— Provider credentials (Stripe, PayPal, Square API keys). Non-autoloaded.brm_payments_sources— Source configs (integrated, webhook)brm_webhook_billing_profile— Webhook billing sync config (enabled flag, one selected BRM offer, and mapped billing field paths such as event type, subscription ID, status, amount, currency, and manage URL). Set via the Billing Sync card on BricksMembers → Integrations → Webhook Mapping when Payments is active.
Related gifting storage lives outside the billing options above. Shared gift-mode settings stay in brm_gifting_settings, while the native gift records themselves live in the source-neutral wp_brm_gifts table owned by GiftSchemaService.
Bricks Integration
Query types: brmUserSubscriptionsQuery, brmUserPaymentsQuery, brmBillingOffersQuery. Billing conditions currently registered in Bricks are brm_has_active_subscription, brm_subscription_status, brm_has_offer, brm_billing_provider, brm_current_loop_subscription_supports_action, brm_has_multiple_subscriptions, and brm_has_single_actionable_subscription. Elements: brm-billing-checkout, brm-billing-action. Dynamic tags: {brm_billing:*} and {brm_billing:item:*}. The current brmUserPaymentsQuery surface matches the REST /payments endpoint and only exposes subscription-linked payment rows, not standalone one-time payment records.
Builder behavior is unchanged: in Bricks editor mode, checkout elements still render their normal builder placeholder even if no live provider option is currently available.
Related
- User post: Payments Module and Billing
- Developer post:
docs/dev-posts/31-gifting-runtime-and-api.html - docs/api/filters.md — Full filters reference
- docs/plans/payments-foundation-plan.md — Architecture and data model