Payments API

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 adapters) feed into this service.
  • BillingCustomerResolverService — Links normalized billing mutations to the WordPress buyer and brm_billing_customers row. It uses CheckoutCustomerDetailsRuntime so buyer email/name map to native WordPress fields while billing recipient/address details stay in the billing snapshot.
  • 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(), and get_user_one_time_payments().
  • BillingPaymentOfferKeyBackfillService — Background owner for copying legacy one-time payment data_json.offer_key values into the indexed brm_billing_payments.offer_key column. The scheduled hook is brm_billing_payment_offer_key_backfill_batch; batches are cursor-based and guarded by ConcurrencyGuardService.
  • BillingSourceConfigService — Reads/writes offers (brm_payments_offers), provider credentials (brm_payments_settings), and source configs (brm_payments_sources). Use get_offers(), get_offer($key), get_webhook_billing_profile(), resolve_offer_key_for_product_ids(), get_offer_checkout_providers(), and get_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.
  • CheckoutElementRuntime 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.
  • CheckoutProfileFieldsRuntime — Payments adapter for Member Profile fields that are explicitly enabled for checkout. It renders/snapshots checkout fields, validates the REST profile_fields payload, attaches values to billing mutations, applies successful values to user profile meta, and exposes system mappings such as group_name without creating a second profile-field config owner in Payments.

Since 0.9.94, checkout preview mode is stored under brm_payments_settings['checkout_preview']. It is a rendering aid only: capability reads may expose native provider choices to Bricks before credentials and offer mappings are connected, but checkout creation, embedded checkout bootstrap, and PayPal confirm routes must reject preview-only attempts before provider/session creation. The Payments overview tab can also generate reversible demo subscriptions, payments, receipts, failed payments, cancelled subscriptions, and native gift rows for template playgrounds. Demo billing rows are written through BillingOrchestratorService with provider/source brm_demo, connection_mode = preview, and a demo batch ID; demo native gifts are written through GiftWriteService with source_object_type = demo_checkout_session. Demo billing includes missing checkout-consent proof so it never becomes a real access grant, and demo rows are hidden or removed when preview mode is disabled.

One-time payment offer checks should use the indexed brm_billing_payments.offer_key column once brm_billing_query_perf_schema_version is current. Keep writing data_json.offer_key for compatibility, but do not add new runtime filters that scan payment JSON. Temporary JSON fallback belongs in BillingDataService only and should be removed after the backfill has been completed across supported release windows.

Since 1.3.0, paid BricksMembers also includes a Free-edition upgrade bridge for Members for Bricks Builder. FreeEditionUpgradeService detects Free contract markers, deactivates the Free plugin when both plugins are active, enables paid Payments and Stripe when Free Stripe EasySync data exists, and stores one-time admin notices. EasySyncWebhookAliasController keeps /wp-json/bricksmembers/v1/stripe-easysync/webhook registered for upgraded sites and delegates requests to the paid Stripe webhook controller. Do not add a second Stripe event mutation path for the alias.

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_gifting and brm_gifting_settings for shared gifting mode and recipient-account behavior
  • brm_payments_settings['gifting'] for global native Payments gift checkout behavior
  • brm_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 in offer['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, optional gift payload, and optional profile_fields from checkout-enabled Member Profile fields. 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_secret and publishable key for the active browser session only. BRM does not persist the client_secret in 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_url or cancel_url from 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.

Taxes, Provider Catalog, and Invoices

  • POST /bricksmembers/v1/billing/taxes/preview — Preview checkout tax for the active offer/address. Permission: checkout preview authorization.
  • GET /bricksmembers/v1/billing/taxes/export — Export admin tax data. Permission: admin.
  • GET /bricksmembers/v1/billing/taxes/reconcile — Read tax reconciliation data. Permission: admin.
  • GET /bricksmembers/v1/billing/admin/provider-catalog/stripe, GET /bricksmembers/v1/billing/admin/provider-catalog/paypal, and GET /bricksmembers/v1/billing/admin/provider-catalog/square — Read provider catalog data when the provider module is active. Permission: admin.
  • GET /bricksmembers/v1/billing/invoices — List current user’s invoices. Permission: logged-in.
  • GET /bricksmembers/v1/billing/invoices/{id}/download — Download an invoice PDF. Permission: invoice owner or admin.
  • POST /bricksmembers/v1/billing/invoices/{id}/regenerate — Regenerate an invoice PDF. Permission: admin.

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.

Stripe hosted and embedded checkout requests use StripeFormBodyEncoder for application/x-www-form-urlencoded bodies. Do not replace it with raw http_build_query(): nested Stripe fields such as automatic_tax[enabled], tax_id_collection[enabled], adaptive_pricing[enabled], and customer_update[address] must keep Stripe’s bracketed form keys and boolean values must be encoded as literal true/false.

Stripe adapter parameters must stay aligned with Stripe Checkout and Stripe Tax contracts: only send customer_update when a Checkout Session has an existing customer, only use customer_creation=always in modes where Stripe accepts customer creation without an existing customer, keep Stripe Tax calculation tax_behavior on individual line_items rather than as a root calculation parameter, and include customer_details[address_source] whenever a Stripe Tax calculation request includes customer_details[address].

Stripe Checkout and Stripe Tax calls share the pinned API version from StripeApiVersion::CURRENT. Keep that value aligned with Stripe’s current supported API version, and update the native provider contract tests whenever the pin changes.

The Payments tax admin UI resolves product tax codes through BillingTaxAdminOptionsService. It uses Stripe’s GET /v1/tax_codes endpoint when Stripe credentials are available and falls back to a curated Stripe-compatible list for common BRM products such as SaaS, online courses, training, services, tangible goods, and nontaxable items. BillingTaxService::DEFAULT_TAX_CODE is txcd_20060158 (On-demand online courses – streamed audio/video) so course sellers start from a safer default than Stripe’s generic electronic-services bucket. Readiness refresh and runtime unavailable-engine messages are centralized in BillingTaxService; provider engines should return stable error codes such as stripe_tax_registration_missing and let the service translate them into user-facing diagnostics.

Stripe embedded checkout uses the versioned Stripe.js URL from StripeApiVersion::JS_URL and the Checkout Sessions Elements mode. The frontend initializes Stripe through initCheckoutElementsSdk when the loaded Stripe.js build exposes it and falls back to initCheckout for compatible builds. The payment form must be rendered by BRM Checkout Payment Form; it owns the Stripe mount container, PayPal button container, and Square preview container. The checkout trigger keeps the builder-authored button label as the final payment confirmation text, so country-specific legal wording such as “zahlungspflichtig bestellen” is not replaced by a generic runtime label.

Stripe Tax readiness is a Stripe-account concern, not a checkout-payload concern. BRM can create the correct preview and Checkout Session payloads only when the Stripe account has tax enabled, usable credentials, and at least one active Stripe Tax registration for the merchant’s collection obligations. Readiness failures such as a missing active registration should stay actionable in admin/runtime diagnostics and must not be hidden as a generic provider error. Embedded wallet and domain-bound payment methods also depend on Stripe payment method domain registration for the checkout domain.

PayPal checkout requests use stable PayPal-Request-Id values built from the BRM checkout token/session context so retries remain idempotent. Square native checkout calls go through SquareApiClient, which centralizes Square-Version, authorization headers, JSON handling, idempotency keys, and customer/subscription refresh calls used by webhook normalization.

Native gifting extends the checkout request with an optional gift payload. PaymentsRestRegistrar registers the hosted and embedded checkout routes, and PaymentsCheckoutController validates the payload when both the Gifting and Payments modules are active, the offer allows gifting, the provider supports the requested billing model, and recipient validation passes.

Checkout-enabled profile fields extend the same hosted and embedded checkout routes with an optional profile_fields object. PaymentsCheckoutRequestValidator delegates validation to CheckoutProfileFieldsRuntime, which rejects unknown field keys, sanitizes values by field type, snapshots field metadata, and stores the snapshot in the checkout-session row. BillingOrchestratorService attaches that snapshot to the payment/subscription mutation before access and group provisioning run.

Checkout customer details are normalized separately by CheckoutCustomerDetailsRuntime. Buyer identity uses WordPress-native fields (user_email, display_name, first_name, last_name) instead of duplicate custom profile fields. Payments-owned fields cover company name, customer address, optional separate billing recipient/address, tax customer type, tax IDs, and the first-class group/team name. Provider adapters receive the normalized effective billing details; Stripe Tax preview sends customer_details[address_source]=billing whenever an address is sent, and Stripe Checkout only sends customer_update when an existing Stripe customer is present.

On Bricks frontend surfaces, the atomic checkout context does not disappear silently when no provider option can be resolved. Instead it renders a visible unavailable state 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 ships one checkout surface in Bricks: the atomic checkout suite.

  • Atomic checkout v2BRM Checkout Context plus child elements under src/Elements/Checkout/ in the bricksmembers builder 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 CheckoutElementRuntime and CheckoutRenderContext.

The current recommended checkout child elements are provider selector, checkout fields, consent, payment form, error surface, and trigger. BRM Checkout Fields is the canonical renderer for WordPress-native buyer fields, Payments-owned address/billing/tax fields, group name, native gift fields, and selected checkout-enabled profile fields. Builders can use multiple instances, and each instance stores an ordered field repeater with a source selector, concrete field selector, and optional label, placeholder, or help-text overrides. There is no separate checkout profile-fields or checkout gift-fields element in the current checkout architecture.

Checkout consent normalization and proof snapshots are owned by CheckoutConsentService. The signed consent payload and stored proof include the checkbox copy, help text, Terms link, Privacy Policy link, withdrawal information link, withdrawal form link, and the legal-text hash used to prove which visible legal copy was accepted.

The provider selector remains generated by CheckoutElementRuntime::render_provider_selector(), but the adapter exposes Bricks controls for text, marks, and internal button styling. Official SVG marks are the default for Stripe, PayPal, and Square; builders can switch to text initials or upload per-provider custom mark images. Non-ACSS styles emit both BRM fallback classes and Bricks utility classes such as bricks-button, bricks-background-secondary, and bricks-button-lg. ACSS styles emit btn, the selected ACSS style, and the selected size, with outline styles normalized to the same btn--* plus btn--outline pattern used by the other BRM elements.

The payment form child still renders provider containers instead of nestable child elements. That is intentional: Stripe Elements, PayPal buttons, and Square previews must be controlled by the checkout runtime. Styling belongs in the element controls that target the generated provider surface and preview fields, not in a second payment-field mutation path.

Checkout tax controls now live in BRM Checkout Fields. The frontend posts a canonical customer_details payload that includes buyer fields, customer address, optional separate billing details, customer type, tax IDs, and group name. New templates should not require custom HTML inputs. The legacy attributes below remain documented only as the backward-compatibility contract for older saved pages or advanced hand-authored checkouts.

  • data-brm-tax-panel="1" marks an optional authored panel that checkout v2 hides when tax is disabled for the current offer.
  • data-brm-tax-host="1" marks the authored tax UI root. If the host is empty, checkout v2 fills the default markup; if it already contains tax controls, checkout v2 binds those controls without replacing them.
  • data-brm-checkout-address-country, data-brm-checkout-address-postal, and optional data-brm-checkout-address-state mark normal Bricks-authored address inputs used by tax preview. The default runtime localizes ISO country codes plus country/region option data so the frontend can show readable country labels and country-specific region dropdowns where known. Older authored country text inputs are upgraded in place to selects, and older region inputs are paired with a runtime select when the selected country has known subdivisions. Stripe uses this preview for the on-page estimated summary while final tax remains owned by Stripe Checkout; one-time PayPal/Square flows use the preview as required pre-checkout tax input.
  • data-brm-checkout-summary-subtotal, data-brm-checkout-summary-tax, and data-brm-checkout-summary-total mark order-summary text targets. Checkout v2 updates subtotal and total from the selected BRM currency before provider handoff and updates tax-aware totals from the tax preview response when BRM-side preview is active. Optional row attributes data-brm-checkout-summary-tax-row and data-brm-checkout-summary-total-row let the runtime show or hide tax-aware rows with the active offer.
  • data-brm-tax-b2b-toggle="1", data-brm-tax-vat-id="1", data-brm-tax-fields="1", data-brm-tax-summary="1", data-brm-tax-line="1", data-brm-tax-total="1", data-brm-tax-vat-status="1", and data-brm-tax-reverse-charge="1" are the frontend binding contract for tax preview state.
  • {brm_checkout:tax_*} tags are text helpers only. Runtime rendering remains in BillingDynamicTags; assistant metadata lives in DynamicTagAssistantEntryProvider and DynamicTagAssistantTagDescriber.

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).

Free EasySync compatibility: upgraded Free sites may still receive Stripe events at POST /bricksmembers/v1/stripe-easysync/webhook. That endpoint is registered only when Free contract markers exist and hands off to the native Stripe webhook controller after module checks.

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} with a Core\Event object for each normalized event. Current billing event constants include billing_customer_linked, billing_subscription_created, billing_subscription_updated, billing_subscription_activated, billing_subscription_past_due, billing_subscription_paused, billing_subscription_cancelled, billing_subscription_expired, billing_payment_succeeded, billing_payment_failed, billing_payment_refunded, billing_checkout_started, and billing_checkout_completed.

add_action( 'brm_event_billing_subscription_activated', function( \BaselMedia\BricksMembers\Core\Event $event ) {
    $user_id = $event->get_user_id();
    $offer_key = $event->get_context_value( 'offer_key', '' );
    // Custom logic
} );

Options

  • brm_payments_offers — Offer definitions (key, label, levels, billing_model, recurring trial_days, presentation fields, image attachment, and 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, brmUserInvoicesQuery, brmBillingOffersQuery. Since 0.9.95, brmBillingOffersQuery can filter offer loops by a comma-separated Offer Keys control in addition to the giftable-only control. Billing conditions currently registered in Bricks are brm_has_active_subscription, brm_subscription_status, brm_has_offer, brm_has_current_loop_offer, brm_billing_provider, brm_current_loop_subscription_supports_action, brm_has_multiple_subscriptions, and brm_has_single_actionable_subscription. Elements: brm-checkout-context with its checkout child elements, plus brm-billing-action. Dynamic tags: {brm_billing:*}, {brm_billing:item:*}, and checkout context tags under {brm_checkout:*}. {brm_billing:invoice_url} outputs current-user BRM invoice download links as HTML anchors in content-replacement contexts; in single-tag render contexts it still follows subscription resolution first, so invoice-only templates should use brmUserInvoicesQuery. Inside brmUserPaymentsQuery, {brm_billing:item:receipt_url} is the provider receipt, {brm_billing:item:invoice_url} remains the provider-hosted invoice, {brm_billing:item:invoice_download_url} is the BRM-generated invoice PDF URL when a related invoice row exists, and {brm_billing:item:transfer_url} is the native transfer URL for eligible one-time payment access. The Bricks payments loop includes subscription-linked payments and standalone one-time payments for the current user; the REST /payments endpoint remains subscription-linked only. Inside brmUserInvoicesQuery, invoice item tags include {brm_billing:item:id}, {brm_billing:item:status}, {brm_billing:item:amount}, {brm_billing:item:currency}, {brm_billing:item:paid_at}, {brm_billing:item:invoice_number}, {brm_billing:item:invoice_date}, {brm_billing:item:invoice_due_date}, {brm_billing:item:invoice_subtotal}, {brm_billing:item:invoice_tax}, {brm_billing:item:invoice_total}, {brm_billing:item:invoice_download_url}, and {brm_billing:item:status_badge}; {brm_billing:item:invoice_url} resolves to the same BRM invoice download URL in that loop. Invoice designer templates can use {{tax_total_label}} next to {{tax_total}}; it resolves to Tax.

Admin invoice templates live in the hidden brm_invoice_template post type and are surfaced through Payments → Invoices. Template creation delegates to InvoiceDesignerCoordinator::create_template_from_starter() for the shipped Classic and Modern starters, document saves use InvoiceDesignerActions, and recent invoice rows are read through BillingInvoiceReadService::get_recent_invoices(). Active-template selection, seller details, invoice numbering, legal text, demo invoice creation, and counter reset tools are surfaced on the Invoices tab.

The invoice placeholder catalog is owned by InvoicePlaceholderDefinitions::fields() and resolved by InvoicePlaceholderRegistry. Current tokens are {{seller_name}}, {{seller_address_line}}, {{seller_country}}, {{seller_tax_id}}, {{seller_email}}, {{seller_logo_url}}, {{buyer_name}}, {{buyer_first_name}}, {{buyer_last_name}}, {{buyer_company_name}}, {{buyer_address_line}}, {{buyer_country}}, {{buyer_tax_id}}, {{buyer_tax_id_masked}}, {{buyer_email}}, {{buyer_type}}, {{billing_name}}, {{billing_email}}, {{billing_company_name}}, {{billing_address_line}}, {{billing_country}}, {{group_name}}, {{invoice_number}}, {{invoice_series}}, {{invoice_date}}, {{due_date}}, {{fiscal_year}}, {{invoice_status}}, {{line_items}}, {{currency}}, {{subtotal}}, {{tax_total}}, {{tax_total_label}}, {{total}}, {{tax_breakdown}}, {{reverse_charge_text}}, {{paid_at}}, {{payment_method}}, {{merchant_notes}}, and {{terms_and_conditions}}. Builder metadata exposes the same set as {brm_invoice:*} dynamic tags for the invoice PDF designer context.

The invoice designer exposes line_items as a table placeholder. InvoicePlaceholderRegistry resolves rows from the immutable invoice snapshot in invoice.data_json.items or invoice.data_json.line_items first, then falls back to payment.items, payment.line_items, payment.data_json.items, or payment.data_json.line_items before using one derived row. The table columns are item, qty, unit_amount, tax_rate, tax, and amount.

Legal invoice templates should use {{buyer_tax_id}}, not {{buyer_tax_id_masked}}. The full value is resolved from encrypted tax evidence at render time through InvoicePlaceholderRegistry; invoice and transaction rows continue storing only the masked copy.

Builder behavior is owned by the atomic checkout render helpers. In Bricks editor mode, BRM Checkout Context can enable Builder Provider Preview to show native provider choices and form states before live provider mappings are connected. Atomic child elements read live checkout state from the parent CheckoutRenderContext when one is active; when a child element is selected or rendered alone in the builder, CheckoutPreviewData supplies a synthetic preview context so the element still outputs styleable checkout markup instead of an instructional placeholder. Public frontend renders do not use that standalone preview fallback, and real checkout attempts remain blocked while preview mode is active.

Get BricksMembers

Start Building Your Membership Site Today

Create, sell, and manage your content without limits. BricksMembers gives you everything you need to build membership and LMS sites with Bricks Builder.

Lifetime updates & bug fixes • Premium support • 0% transaction fees • 60-day money-back guarantee