API Reference
Auto-generated reference for the supabase-billing gem — every public module, class, method, constant, and attribute extracted from the source.
This page is generated by pnpm run gen:billing-api from the supabase-billing
source. Edit the gem (then re-run the script) — do not hand-edit this file.
See docs/scripts/gen-billing-api.mjs for the generator.
The script reads:
supabase-billing/lib/— every.rbfile (excluding model templates, which are rendered separately below)lib/generators/supabase_billing/install/templates/app/models/billing— model declarations (associations, table mappings)
Sections below mirror the source-file layout. Module / class headings use
their fully-qualified Ruby names; method headings prefix instance methods
with # and class methods with . (matching YARD convention).
Library
lib/generators/supabase_billing/install/install_generator.rb
class SupabaseBilling::Generators::InstallGenerator < ::Rails::Generators::Base
rails g supabase_billing:install (US-001).
Emits the canonical billing schema migration: a single timestamped
migration under db/migrate/ that creates the eight canonical tables
(billing_customers, plans, entitlements, plan_entitlements,
subscriptions, subscription_items, usage_limits, usage_events)
plus the four provider-mapping tables (provider_customers,
provider_subscriptions, provider_products, provider_events),
along with the Supabase RLS policies that scope reads to the
authenticated user via auth.uid().
Preflights that supabase-rails is installed (Gemfile + initializer)
before doing anything — the gem builds on supabase-rails and refuses
to run without it.
Constants
SUPPORTED_PROVIDERS=%w[stripe adapty].freezeSUPPORTED_STRIPE_INGESTION=%w[webhook sync_engine].freezePOST_INSTALL_SEPARATOR=("=" * 72).freezeBILLING_MODEL_FILES=(multi-line literal)
Methods
.next_migration_number
def self.next_migration_number(_dirname)Rails' built-in timestamp for migration filenames. Mirrors
ActiveRecord::Generators::Migration#next_migration_number so the
generator works without ActiveRecord loaded.
#preflight_supabase_rails
def preflight_supabase_rails#preflight_providers
def preflight_providers#create_migration_file
def create_migration_file#create_models
def create_models#create_initializer
def create_initializer#create_yaml_config
def create_yaml_config#include_acts_billable_in_user_model
def include_acts_billable_in_user_modelWires the entitlement engine into the host app's User model
(US-005). The model is generated by rails g supabase:user_model and lives at app/models/user.rb; the
include Acts::Billable line is the one-shot bridge that
exposes user.entitled?, user.subscribed?, etc.
Idempotent: if the line is already present we skip the injection, so reruns don't double-include the concern.
#mount_engine_in_host_routes
def mount_engine_in_host_routesMounts the Supabase::Billing::Engine at /supabase_billing
so the host app exposes the webhook endpoints. Idempotent: if
a mount line is already present, we skip the injection.
In :sync_engine mode the engine is still mounted, but its
config/routes.rb draws zero routes (see AC: "in :sync_engine
mode, the /supabase_billing/webhooks/stripe route is not
mounted"). The mount itself is cheap; what controls visibility
is the engine's internal routeset.
#print_post_install_checklist
def print_post_install_checklist#providers
def providersMemoized, parsed and validated provider list. Raises (or prompts interactively if no flag) when zero providers would be selected.
#parse_providers
def parse_providers(raw)#prompt_for_providers
def prompt_for_providers#validate_stripe_ingestion!
def validate_stripe_ingestion!#include_rls?
def include_rls?--- Template hooks (referenced from create_supabase_billing_schema.rb.tt) ---
#stripe_ingestion
def stripe_ingestion#provider_list
def provider_list#supabase_rails_in_gemfile?
def supabase_rails_in_gemfile?--- Preflight helpers --------------------------------------------------
#supabase_rails_initializer_present?
def supabase_rails_initializer_present?lib/supabase/billing.rb
module Supabase::Billing
Methods
#configure
def configure#config
def config#reset_config!
def reset_config!#debug
def debug(user)#sync_status
def sync_status(user)module SupabaseBilling
Top-level convenience module so SupabaseBilling.configure reads as well
as Supabase::Billing.configure. Declared as a distinct module (not a
constant alias) so the generator's existing module SupabaseBilling
namespace keeps inferring supabase_billing:install.
Declared before the rails-dependent requires below so that the
engine's isolate_namespace ::SupabaseBilling (loaded via the
railtie) finds the constant already in place.
Methods
.configure
def self.configure(&block).config
def self.config.debug
def self.debug(user).sync_status
def self.sync_status(user)lib/supabase/billing/acts/billable.rb
Acts::Billable is the entitlement engine's public API: include it on
the host app's User model (the one generated by rails g supabase:user_model) and the four AC methods — subscribed?,
plan, entitled?(:key), limit(:key) — read from the canonical
Billing::* tables, with safe defaults when the user has no
subscription.
Results cache per-request via Supabase::Billing::Current so a single
controller action that calls entitled?(:foo) multiple times only
hits the DB once. Disable via
Supabase::Billing.config.cache_entitlements_per_request = false for
apps that need always-fresh reads.
Defined as a top-level Acts::Billable module so the AC-literal
include Acts::Billable form works in a host User model. The
Supabase::Billing::Acts::Billable constant below is a one-way alias
so internal code can resolve via the gem's namespace.
module Acts
Acts::Billable is the entitlement engine's public API: include it on
the host app's User model (the one generated by rails g supabase:user_model) and the four AC methods — subscribed?,
plan, entitled?(:key), limit(:key) — read from the canonical
Billing::* tables, with safe defaults when the user has no
subscription.
Results cache per-request via Supabase::Billing::Current so a single
controller action that calls entitled?(:foo) multiple times only
hits the DB once. Disable via
Supabase::Billing.config.cache_entitlements_per_request = false for
apps that need always-fresh reads.
Defined as a top-level Acts::Billable module so the AC-literal
include Acts::Billable form works in a host User model. The
Supabase::Billing::Acts::Billable constant below is a one-way alias
so internal code can resolve via the gem's namespace.
module Acts::Billable
Associations
has_one :billing_customer
Constants
ACTIVE_SUBSCRIPTION_STATUSES=%w[active trialing].freeze
Methods
#subscribed?
def subscribed?#plan
def plan#entitled?
def entitled?(entitlement_key)#limit
def limit(entitlement_key)#usage
def usage(entitlement_key)Returns the total usage recorded against entitlement_key in the
current billing period (the active subscription's
current_period_start / current_period_end). Returns 0 when the
user has no billing_customer, no active subscription, or the
entitlement doesn't exist.
#remaining
def remaining(entitlement_key)Returns limit(:key) - usage(:key), or nil when the entitlement
has no numeric cap (i.e. unlimited, no subscription, or boolean
entitlement).
#record_usage
def record_usage(entitlement_key, amount: 1, recorded_at: nil)Records a usage event against the user's billing_customer and
invalidates the per-request cache for the entitlement so a
subsequent limit(:key) / entitled?(:key) / usage(:key) /
remaining(:key) re-reads from the DB.
#acts_billable_invalidate_cache
def acts_billable_invalidate_cache(entitlement_key = nil)Drops the cached entitlement values for this user. Pass an
entitlement key to drop only that key's entries (both entitled?
and limit); pass nil to drop everything for this user.
#acts_billable_active_subscription
def acts_billable_active_subscription#acts_billable_usage_for
def acts_billable_usage_for(entitlement_key)Sums usage_events.amount for the user's current billing period.
Period boundaries come from the active subscription's
current_period_start / current_period_end; without a subscription
or without a configured period_start, we fall back to "no lower
bound" so usage is still observable for self-hosted flows that
haven't wired the period anchor yet.
#acts_billable_plan_entitlement_for
def acts_billable_plan_entitlement_for(entitlement_key)#acts_billable_cached
def acts_billable_cached(method, entitlement_key = nil)#acts_billable_const
def acts_billable_const(name)lib/supabase/billing/adapters/adapty/event_processor.rb
class Supabase::Billing::Adapters::Adapty::EventProcessor
Processes a parsed Adapty webhook event payload (Hash) by:
- Storing the raw event in
provider_eventsfor replay/debugging. - Upserting the matching
provider_subscriptionsrow keyed off the Adaptyprofile_id(subscription events) ortransaction_id(non-subscription purchases). - Reflecting state into the canonical
subscriptionsrow.
Handles the seven AC-mandated events:
- subscription_started
- subscription_renewed
- subscription_cancelled
- subscription_expired
- subscription_refunded
- non_subscription_purchase
- access_level_updated
Adapty's customer_user_id is the Supabase auth.users.id UUID
string (mobile clients call Adapty.identify(session.user.id.uuidString)
after sign-in). We normalize incoming UUIDs to lowercase before the
billing_customers.user_id lookup — Adapty's server-to-server calls
send uppercase per their convention, but Postgres uuid comparisons
are case-insensitive in storage; we lowercase explicitly so a string
comparison against users.id (uuid) coerces cleanly.
Unknown event types / unknown users / unmapped products are logged and skipped rather than raised so a single bad row never poisons the webhook endpoint.
Constants
HANDLED_EVENT_TYPES=(multi-line literal)DEFAULT_MODEL_NAMES=(multi-line literal)PROVIDER="adapty"EVENT_STATUS_MAP=(multi-line literal)
Attributes
attr_reader :loggerattr_reader :config
Methods
#initialize
def initialize(models: nil, logger: nil, config: Supabase::Billing.config, now: nil)#call
def call(event)Process a single Adapty event Hash (already parsed from JSON). Returns true if the event was handled (or intentionally skipped), false only when the event payload is malformed.
#now
def now#models
def models#resolve_models
def resolve_models#extract_event_id
def extract_event_id(event)---- event id + storage ---------------------------------------------
Adapty supplies an event_id field on every server-to-server
webhook; fall back to a deterministic synthetic id derived from
(profile_id, event_type, event_datetime) when absent so the
provider_events.provider_event_id unique index still gives us
idempotency.
#store_provider_event
def store_provider_event(event_id, event_type, event)#mark_event_processed
def mark_event_processed(event_id)#event_payload_hash
def event_payload_hash(event)#handle_event
def handle_event(event_type, event)---- dispatch -------------------------------------------------------
#handle_subscription_event
def handle_subscription_event(event_type, billing_customer, plan, props)---- subscription event handling ------------------------------------
#upsert_provider_subscription
def upsert_provider_subscription(provider_subscription_id, event_type, props)#upsert_canonical_subscription
def upsert_canonical_subscription(event_type:, billing_customer:, plan:, props:)#find_or_initialize_subscription_for
def find_or_initialize_subscription_for(billing_customer, props)#canonical_status
def canonical_status(event_type, props)#handle_non_subscription_purchase
def handle_non_subscription_purchase(billing_customer, plan, props)---- non-subscription purchase --------------------------------------
#lookup_billing_customer
def lookup_billing_customer(customer_user_id, props)---- lookups + linking ----------------------------------------------
#lookup_plan_for_product
def lookup_plan_for_product(vendor_product_id, access_level_id)#link_provider_customer
def link_provider_customer(billing_customer, props)#normalize_user_id
def normalize_user_id(raw)---- helpers -------------------------------------------------------- Webhook payloads are normalized to lowercase before the DB lookup (Adapty's server-to-server API calls send uppercase per their convention; mobile SDKs typically send mixed/uppercase). Returns nil for blank/invalid input.
#event_properties
def event_properties(event)#parse_time
def parse_time(value)#truthy?
def truthy?(value)#log
def log(level, message)lib/supabase/billing/adapters/adapty/signature_verifier.rb
class Supabase::Billing::Adapters::Adapty::SignatureVerifier
Verifies the Authorization header on an incoming Adapty webhook
against the configured Adapty webhook secret using a constant-time
comparison. Adapty's server-to-server webhook scheme is a shared
secret passed verbatim in Authorization (no HMAC over the body),
so verification here is a fixed-length secret equality check.
Implemented in-gem (not via the adapty gem) so the gem stays
dependency-free at runtime.
Methods
.verify!
def self.verify!(authorization_header:, secret:)#initialize
def initialize(authorization_header:, secret:)#verify!
def verify!#secure_compare
def secure_compare(a, b)lib/supabase/billing/adapters/stripe/event_processor.rb
class Supabase::Billing::Adapters::Stripe::EventProcessor
Processes a parsed Stripe event payload (Hash) by:
- Storing the raw event in
provider_eventsfor replay/debugging. - Upserting the matching
provider_subscriptionsrow. - Reflecting state into the canonical
subscriptionsrow.
Currently handles the four AC-mandated events:
- customer.subscription.created
- customer.subscription.updated
- customer.subscription.deleted
- invoice.payment_succeeded
Unknown event types / unknown Stripe customers / unknown Stripe prices are logged and skipped rather than raised so a single bad row never poisons the webhook endpoint.
Models are resolved lazily via constant lookup at call-time so
the gem stays decoupled from the host app's autoloader; specs
inject explicit models: to run against an isolated AR setup.
Constants
HANDLED_EVENT_TYPES=(multi-line literal)DEFAULT_MODEL_NAMES=(multi-line literal)PROVIDER="stripe"STATUS_MAP=(multi-line literal)
Attributes
attr_reader :loggerattr_reader :config
Methods
#initialize
def initialize(models: nil, logger: nil, config: Supabase::Billing.config, now: nil)#call
def call(event)Process a single Stripe event Hash (already parsed from JSON). Returns true if the event was handled (or intentionally skipped), false only when the event payload is malformed.
#now
def now#models
def models#resolve_models
def resolve_models#store_provider_event
def store_provider_event(event_id, event_type, event)---- event storage ---------------------------------------------------
#mark_event_processed
def mark_event_processed(event_id)#event_payload_hash
def event_payload_hash(event)#handle_subscription_upsert
def handle_subscription_upsert(event)---- customer.subscription.created / .updated -----------------------
#upsert_provider_subscription
def upsert_provider_subscription(stripe_sub_id, sub_object)#upsert_canonical_subscription
def upsert_canonical_subscription(billing_customer:, plan:, sub_object:)#find_or_initialize_subscription_for
def find_or_initialize_subscription_for(billing_customer, sub_object)The provider_subscriptions row links to the canonical row by
subscription_id. On the first event for a Stripe sub, the
provider row exists but has no subscription_id, so we look
up by the most recent existing canonical sub for this customer,
or build a fresh one.
#handle_subscription_deleted
def handle_subscription_deleted(event)---- customer.subscription.deleted ----------------------------------
#handle_invoice_payment_succeeded
def handle_invoice_payment_succeeded(event)---- invoice.payment_succeeded --------------------------------------
#lookup_billing_customer
def lookup_billing_customer(stripe_customer_id)---- lookups + helpers ----------------------------------------------
#lookup_plan_for_price
def lookup_plan_for_price(price_id)#first_price_id
def first_price_id(sub_object)#dig
def dig(hash, *keys)#epoch_to_time
def epoch_to_time(value)#log
def log(level, message)lib/supabase/billing/adapters/stripe/signature_verifier.rb
class Supabase::Billing::Adapters::Stripe::SignatureVerifier
Verifies the Stripe-Signature header on an incoming webhook
against the configured webhook secret using Stripe's documented
scheme: HMAC-SHA256 of "#{timestamp}.#{payload}" keyed by the
secret, compared in constant time, with a tolerance window on
the timestamp to reject obviously-replayed events.
Implemented in-gem (not via the stripe gem) so the gem stays
dependency-free at runtime.
Constants
DEFAULT_TOLERANCE=300 # 5 minutes, matching Stripe's recommendation
Methods
.verify!
def self.verify!(payload:, signature_header:, secret:, tolerance: DEFAULT_TOLERANCE, now: Time.now)#initialize
def initialize(payload:, signature_header:, secret:, tolerance: DEFAULT_TOLERANCE, now: Time.now)#verify!
def verify!#parse_header
def parse_header(header)#compute_signature
def compute_signature(timestamp, payload, secret)#secure_compare
def secure_compare(a, b)lib/supabase/billing/adapters/stripe/sync_engine_preflight.rb
class Supabase::Billing::Adapters::Stripe::SyncEnginePreflight
Verifies that the stripe.* schema produced by
stripe/stripe-sync-engine exists with the columns this adapter
depends on. Run once at boot when stripe_ingestion = :sync_engine.
If drift is detected, raises SchemaDriftError naming the
supported sync-engine version range so the developer can pin
their stripe-sync-engine deployment to a compatible release
rather than ship wrong entitlements silently.
Constants
SUPPORTED_SYNC_ENGINE_VERSIONS=">= 0.62.0, < 1.0.0"SCHEMA_NAME="stripe"EXPECTED_SCHEMA=(multi-line literal)
Attributes
attr_reader :connection
Methods
.run!
def self.run!(connection)#initialize
def initialize(connection)#run!
def run!#ensure_schema_present!
def ensure_schema_present!#existing_tables
def existing_tables#columns_for
def columns_for(table)#raise_drift!
def raise_drift!(detail)lib/supabase/billing/adapters/stripe/sync_engine_reflector.rb
class Supabase::Billing::Adapters::Stripe::SyncEngineReflector
In :sync_engine mode, no webhook endpoint is mounted.
stripe/stripe-sync-engine populates the stripe.* schema
asynchronously from Stripe's API; this reflector reads from
those tables and projects state into the canonical
subscriptions / provider_subscriptions rows so the
entitlement API (user.entitled?) returns the same answer in
both ingestion modes.
Unknown / unmapped customers and prices are logged and skipped, never raised — matching the webhook adapter's behavior so swapping modes can't break existing apps.
Constants
DEFAULT_MODEL_NAMES=(multi-line literal)PROVIDER="stripe"
Attributes
attr_reader :logger
Methods
#initialize
def initialize(connection:, models: nil, logger: nil)#call
def call#models
def models#resolve_models
def resolve_models#reflect_subscription
def reflect_subscription(row)#first_price_id_for
def first_price_id_for(stripe_sub_id)#upsert_provider_subscription
def upsert_provider_subscription(stripe_sub_id, row)#upsert_canonical_subscription
def upsert_canonical_subscription(billing_customer:, plan:, row:, status:)#lookup_billing_customer
def lookup_billing_customer(stripe_customer_id)#lookup_plan_for_price
def lookup_plan_for_price(price_id)#to_time
def to_time(value)#log
def log(msg)lib/supabase/billing/configuration.rb
class Supabase::Billing::Configuration
Constants
STRIPE_INGESTION_MODES=%i[webhook sync_engine].freeze
Attributes
attr_accessor :adapty_webhook_secretattr_accessor :stripe_webhook_secretattr_reader :stripe_ingestionattr_reader :plans
Methods
#initialize
def initialize#stripe_ingestion=
def stripe_ingestion=(mode)#plan
def plan(key, name: nil, **metadata, &block)#plan_keys
def plan_keys#fetch_plan
def fetch_plan(key)lib/supabase/billing/current.rb
class Supabase::Billing::Current < ActiveSupport::CurrentAttributes
Request-scoped storage for the entitlement cache. Rails resets
ActiveSupport::CurrentAttributes subclasses between requests via
the executor, so the cache is automatically cleared at the request
boundary — no manual reset hook required.
The cache is keyed on [user_id, method, entitlement_key] (or
[user_id, method] for subscribed? / plan). Acts::Billable
owns the keying scheme; this class is just the storage.
Methods
#entitlement_cache
def entitlement_cachelib/supabase/billing/debug.rb
module Supabase::Billing::Debug
Console-friendly inspectors for a single user's canonical billing
state. Built for the "I got a support ticket, what's actually in the
DB for this user?" workflow — every value is JSON-serializable
(Strings / Hashes / Arrays / Numerics / Booleans / nil / ISO-8601
timestamps) so the output can be pasted into a ticket or piped
through JSON.generate without further marshalling.
Safe defaults everywhere: missing billing_customer, missing
subscription, missing plan, missing entitlement link all degrade to
nil / [] / {} rather than raising. A nil user is also
tolerated so a console session can probe the helpers without
having a User instance handy.
Constants
PROVIDERS=%w[stripe adapty].freezeACTIVE_SUBSCRIPTION_STATUSES=%w[active trialing].freeze
Methods
#debug
def debug(user)#sync_status
def sync_status(user)#billing_customer_for
def billing_customer_for(user)#active_subscriptions_for
def active_subscriptions_for(customer)#entitlements_for
def entitlements_for(plan)#usage_for
def usage_for(customer, subscription, entitlements)#sync_status_for_provider
def sync_status_for_provider(customer, provider)#last_provider_customer_timestamp
def last_provider_customer_timestamp(customer, provider)#last_provider_subscription_timestamp
def last_provider_subscription_timestamp(customer, provider)#serialize_customer
def serialize_customer(customer, user)#serialize_subscription
def serialize_subscription(subscription)#serialize_plan
def serialize_plan(plan)#entitlement_value
def entitlement_value(link)#safe_const
def safe_const(name)#stringify_id
def stringify_id(id)#iso
def iso(time)lib/supabase/billing/engine.rb
class Supabase::Billing::Engine < ::Rails::Engine
Mountable Rails engine that exposes the Stripe (and, in later
stories, Adapty) webhook endpoints. The engine is isolated so
supabase_billing lives in its own URL/helper namespace.
The actual route mount is conditional on
Supabase::Billing.config.stripe_ingestion:
:webhook— mountsPOST /webhooks/stripe.:sync_engine— no Stripe webhook route is mounted; reflection reads from thestripe.*schema instead.
AC: the two modes are mutually exclusive — there is no hybrid ingestion path in the MVP.
lib/supabase/billing/plan.rb
class Supabase::Billing::Plan
Constants
VALID_ENTITLEMENT_VALUE_DESC="Numeric, true, or false"
Attributes
attr_reader :keyattr_reader :nameattr_reader :metadata
Methods
#initialize
def initialize(key, name: nil, **metadata)#entitlements
def entitlements(hash = nil)#entitlement
def entitlement(entitlement_key, value:)#stripe_prices
def stripe_prices(prices = nil)#adapty_products
def adapty_products(products = nil)#to_h
def to_h#add_entitlement
def add_entitlement(entitlement_key, value)#valid_entitlement_value?
def valid_entitlement_value?(value)#coerce_provider_ids
def coerce_provider_ids(value, field)lib/supabase/billing/railtie.rb
class Supabase::Billing::Railtie < ::Rails::Railtie
Exposes the supabase_billing:* rake tasks to the host Rails app
and wires the boot-time sync-engine preflight (US-006) when the
adapter is configured for :sync_engine ingestion.
lib/supabase/billing/sync.rb
class Supabase::Billing::Sync
Reconciles the DSL-declared plans + entitlements into the host app's ActiveRecord tables. Idempotent: rerunning makes no changes if nothing in the DSL has changed since the last sync.
Plans that disappear from the DSL are archived (their archived_at
column is stamped) rather than hard-deleted, so historical
subscriptions still resolve their plan reference.
Models are resolved lazily via constant lookup at call-time so the gem can be required outside a Rails app; tests inject explicit model classes to run against an isolated AR setup.
Constants
DEFAULT_MODEL_NAMES=(multi-line literal)
Attributes
attr_reader :configattr_reader :logger
Methods
#total
def total#initialize
def initialize(config: Supabase::Billing.config, logger: nil, models: nil, now: nil)#call
def call#result
def result#now
def now#models
def models#resolve_models
def resolve_models#ar_transaction
def ar_transaction(&block)#sync_entitlements
def sync_entitlements---- entitlements ------------------------------------------------------
#entitlement_kinds
def entitlement_kindsHash of { entitlement_key(Symbol) => "numeric" | "boolean" } collected across every plan in the DSL. Raises if the same key appears with incompatible kinds (numeric in one plan, boolean in another).
#kind_for
def kind_for(value)#sync_plans_and_links
def sync_plans_and_links---- plans + plan_entitlements + provider_products --------------------
#upsert_plan
def upsert_plan(dsl_plan)#sync_plan_entitlements
def sync_plan_entitlements(plan_record, dsl_plan, entitlement_records_by_key)#sync_provider_products
def sync_provider_products(plan_record, dsl_plan)#archive_removed_plans
def archive_removed_plans---- archival ---------------------------------------------------------
#dsl_plans
def dsl_plans---- shared helpers ---------------------------------------------------
#log_action
def log_action(action, resource, key, details = nil)lib/supabase/billing/version.rb
module Supabase::Billing
Constants
VERSION="0.1.0"
Models
lib/generators/supabase_billing/install/templates/app/models/billing/application_record.rb.tt
class Billing::ApplicationRecord < ::ApplicationRecord
lib/generators/supabase_billing/install/templates/app/models/billing/billing_customer.rb.tt
class Billing::BillingCustomer < ApplicationRecord
Table: billing_customers
Associations
belongs_to :user→::Userhas_many :subscriptions→Billing::Subscriptionhas_many :provider_customers→Billing::ProviderCustomerhas_many :usage_events→Billing::UsageEvent
lib/generators/supabase_billing/install/templates/app/models/billing/entitlement.rb.tt
class Billing::Entitlement < ApplicationRecord
Table: entitlements
Associations
has_many :plan_entitlements→Billing::PlanEntitlementhas_many :plans→Billing::Planhas_many :usage_limits→Billing::UsageLimithas_many :usage_events→Billing::UsageEvent
lib/generators/supabase_billing/install/templates/app/models/billing/plan.rb.tt
class Billing::Plan < ApplicationRecord
Table: plans
Associations
has_many :plan_entitlements→Billing::PlanEntitlementhas_many :entitlementshas_many :subscriptions→Billing::Subscriptionhas_many :provider_products→Billing::ProviderProduct
lib/generators/supabase_billing/install/templates/app/models/billing/plan_entitlement.rb.tt
class Billing::PlanEntitlement < ApplicationRecord
Table: plan_entitlements
Associations
belongs_to :plan→Billing::Planbelongs_to :entitlement→Billing::Entitlement
lib/generators/supabase_billing/install/templates/app/models/billing/provider_customer.rb.tt
class Billing::ProviderCustomer < ApplicationRecord
Table: provider_customers
Associations
belongs_to :billing_customer→Billing::BillingCustomer
lib/generators/supabase_billing/install/templates/app/models/billing/provider_event.rb.tt
class Billing::ProviderEvent < ApplicationRecord
Table: provider_events
lib/generators/supabase_billing/install/templates/app/models/billing/provider_product.rb.tt
class Billing::ProviderProduct < ApplicationRecord
Table: provider_products
Associations
belongs_to :plan→Billing::Plan
lib/generators/supabase_billing/install/templates/app/models/billing/provider_subscription.rb.tt
class Billing::ProviderSubscription < ApplicationRecord
Table: provider_subscriptions
Associations
belongs_to :subscription→Billing::Subscription
lib/generators/supabase_billing/install/templates/app/models/billing/subscription.rb.tt
class Billing::Subscription < ApplicationRecord
Table: subscriptions
Associations
belongs_to :billing_customer→Billing::BillingCustomerbelongs_to :plan→Billing::Planhas_many :subscription_items→Billing::SubscriptionItemhas_many :usage_limits→Billing::UsageLimithas_many :provider_subscriptions→Billing::ProviderSubscription
lib/generators/supabase_billing/install/templates/app/models/billing/subscription_item.rb.tt
class Billing::SubscriptionItem < ApplicationRecord
Table: subscription_items
Associations
belongs_to :subscription→Billing::Subscription
lib/generators/supabase_billing/install/templates/app/models/billing/usage_event.rb.tt
class Billing::UsageEvent < ApplicationRecord
Table: usage_events
Associations
belongs_to :billing_customer→Billing::BillingCustomerbelongs_to :entitlement→Billing::Entitlement
lib/generators/supabase_billing/install/templates/app/models/billing/usage_limit.rb.tt
class Billing::UsageLimit < ApplicationRecord
Table: usage_limits
Associations
belongs_to :subscription→Billing::Subscriptionbelongs_to :entitlement→Billing::Entitlement