usage_credits

Demo app for the 💳✨ usage_credits gem

The basics: get and spend credits

 

Subscribe to a plan: Buy credit packs: Get arbitrary bonuses: Spend credits:

Ledger status

Date Amount Category Expiration
Nov 28, 10:20 PM +10 credits signup_bonus signup –
Nov 29, 7:43 PM +20 credits referral_bonus referral –
Nov 30, 12:01 AM +20 credits referral_bonus referral –
Nov 30, 5:23 AM +20 credits referral_bonus referral –
Nov 30, 9:06 AM +20 credits referral_bonus referral –
Nov 30, 12:27 PM +20 credits referral_bonus referral –
Nov 30, 6:58 PM +20 credits referral_bonus referral –

Payment records (pay gem)

The user has paid $0.0 total

Pay::Charge (0) none
Pay::Subscription (0) none

Model records

UsageCredits::Fulfillment (0) none
UsageCredits::Transaction (7)
# {
                :id => 4357,
         :wallet_id => 2683,
            :amount => 10,
          :category => "signup_bonus",
        :expires_at => nil,
    :fulfillment_id => nil,
          :metadata => {
        "reason" => "signup"
    },
        :created_at => 2025-11-28 22:20:32.228487000 UTC +00:00,
        :updated_at => 2025-11-28 22:20:32.228487000 UTC +00:00
}
# {
                :id => 4358,
         :wallet_id => 2683,
            :amount => 20,
          :category => "referral_bonus",
        :expires_at => nil,
    :fulfillment_id => nil,
          :metadata => {
        "reason" => "referral"
    },
        :created_at => 2025-11-29 19:43:08.841774000 UTC +00:00,
        :updated_at => 2025-11-29 19:43:08.841774000 UTC +00:00
}
# {
                :id => 4359,
         :wallet_id => 2683,
            :amount => 20,
          :category => "referral_bonus",
        :expires_at => nil,
    :fulfillment_id => nil,
          :metadata => {
        "reason" => "referral"
    },
        :created_at => 2025-11-30 00:01:26.756141000 UTC +00:00,
        :updated_at => 2025-11-30 00:01:26.756141000 UTC +00:00
}
# {
                :id => 4360,
         :wallet_id => 2683,
            :amount => 20,
          :category => "referral_bonus",
        :expires_at => nil,
    :fulfillment_id => nil,
          :metadata => {
        "reason" => "referral"
    },
        :created_at => 2025-11-30 05:23:44.880865000 UTC +00:00,
        :updated_at => 2025-11-30 05:23:44.880865000 UTC +00:00
}
# {
                :id => 4361,
         :wallet_id => 2683,
            :amount => 20,
          :category => "referral_bonus",
        :expires_at => nil,
    :fulfillment_id => nil,
          :metadata => {
        "reason" => "referral"
    },
        :created_at => 2025-11-30 09:06:39.658028000 UTC +00:00,
        :updated_at => 2025-11-30 09:06:39.658028000 UTC +00:00
}
# {
                :id => 4362,
         :wallet_id => 2683,
            :amount => 20,
          :category => "referral_bonus",
        :expires_at => nil,
    :fulfillment_id => nil,
          :metadata => {
        "reason" => "referral"
    },
        :created_at => 2025-11-30 12:27:48.473116000 UTC +00:00,
        :updated_at => 2025-11-30 12:27:48.473116000 UTC +00:00
}
# {
                :id => 4363,
         :wallet_id => 2683,
            :amount => 20,
          :category => "referral_bonus",
        :expires_at => nil,
    :fulfillment_id => nil,
          :metadata => {
        "reason" => "referral"
    },
        :created_at => 2025-11-30 18:58:19.298961000 UTC +00:00,
        :updated_at => 2025-11-30 18:58:19.298961000 UTC +00:00
}
UsageCredits::Allocation (0) none

Audit trail

Audit trail
[
    [0] [
        [0] "signup_bonus",
        [1] 10,
        [2] {
            "reason" => "signup"
        }
    ],
    [1] [
        [0] "referral_bonus",
        [1] 20,
        [2] {
            "reason" => "referral"
        }
    ],
    [2] [
        [0] "referral_bonus",
        [1] 20,
        [2] {
            "reason" => "referral"
        }
    ],
    [3] [
        [0] "referral_bonus",
        [1] 20,
        [2] {
            "reason" => "referral"
        }
    ],
    [4] [
        [0] "referral_bonus",
        [1] 20,
        [2] {
            "reason" => "referral"
        }
    ],
    [5] [
        [0] "referral_bonus",
        [1] 20,
        [2] {
            "reason" => "referral"
        }
    ],
    [6] [
        [0] "referral_bonus",
        [1] 20,
        [2] {
            "reason" => "referral"
        }
    ]
]

Loaded config

Literal, raw config file
      # frozen_string_literal: true

UsageCredits.configure do |config|

  # Default test operations
  operation :small_operation do
    costs 1.credit
  end

  # operation :test_operation do
  #   costs 10.credits + 1.credits_per(:mb)
  #   validate ->(params) { params[:size].to_i <= 100.megabytes }, "File too large (max: 100 MB)"
  # end

  operation :prohibitive_operation do
    costs 1_000_000.credits
  end

  operation :this_operation_will_always_fail do
    costs 42.credits
  end


  # Define test credit packs
  credit_pack :tiny do
    gives 10.credits
    costs 99.cents
  end

  credit_pack :starter do
    gives 1000.credits
    costs 49.dollars
  end

  credit_pack :pro do
    gives 5000.credits
    bonus 100.credits  # Optional: give bonus credits
    costs 199.dollars
    currency :usd
  end


  # Define subscriptions
  subscription_plan :test_plan do
    processor_plan(:fake_processor, "abcdef123456")
    gives 10.credits.every(:month)
    unused_credits :expire
  end

  # Alert when balance drops below 100 credits
  # Set to nil to disable low balance alerts
  # config.low_balance_threshold = 20.credits

  # # Handle low credit balance alerts
  # config.on_low_balance do |user|
  #   # Send notification to user when their balance drops below the threshold
  #   ApplicationMailer.generic_email(to: user.email, body: "Heads up! You're low on credits.", subject: "Low credits alert").deliver_now
  # end

end

    
Credit-consuming operations
Credit packs
Credit subscription plans
Rest of the config
      {
  "default_currency": "usd",
  "rounding_strategy": "ceil",
  "credit_formatter": {},
  "fulfillment_grace_period": 300,
  "allow_negative_balance": false,
  "low_balance_threshold": null,
  "low_balance_callback": null
}