{"id":13747520,"url":"https://github.com/tansengming/stripe-rails","last_synced_at":"2025-05-14T14:08:40.417Z","repository":{"id":878963,"uuid":"5981353","full_name":"tansengming/stripe-rails","owner":"tansengming","description":"A Rails Engine for integrating with Stripe","archived":false,"fork":false,"pushed_at":"2024-08-12T18:19:07.000Z","size":606,"stargazers_count":763,"open_issues_count":19,"forks_count":124,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-05-13T12:04:52.237Z","etag":null,"topics":["hacktoberfest","rails-engine","ruby","stripe","stripe-event"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tansengming.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2012-09-27T11:43:29.000Z","updated_at":"2025-04-28T04:40:42.000Z","dependencies_parsed_at":"2024-01-13T03:01:16.591Z","dependency_job_id":"76ab4a8e-867f-4971-99c7-2a6e43943363","html_url":"https://github.com/tansengming/stripe-rails","commit_stats":{"total_commits":624,"total_committers":58,"mean_commits":"10.758620689655173","dds":0.4246794871794872,"last_synced_commit":"a0123914f6fff0b11e3dffceed17af57454585ca"},"previous_names":[],"tags_count":60,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tansengming%2Fstripe-rails","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tansengming%2Fstripe-rails/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tansengming%2Fstripe-rails/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tansengming%2Fstripe-rails/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tansengming","download_url":"https://codeload.github.com/tansengming/stripe-rails/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254159932,"owners_count":22024566,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","rails-engine","ruby","stripe","stripe-event"],"created_at":"2024-08-03T06:01:32.242Z","updated_at":"2025-05-14T14:08:40.396Z","avatar_url":"https://github.com/tansengming.png","language":"Ruby","funding_links":["https://tidelift.com/badges/github/tansengming/stripe-rails","https://tidelift.com/subscription/pkg/rubygems-stripe-rails?utm_source=rubygems-stripe-rails\u0026utm_medium=referral\u0026utm_campaign=readme"],"categories":["Ruby"],"sub_categories":[],"readme":"# Stripe::Rails: A Rails Engine for use with [stripe.com](https://stripe.com)\n[![Gem Version](https://badge.fury.io/rb/stripe-rails.svg)](https://badge.fury.io/rb/stripe-rails)\n[![Build Status](https://travis-ci.org/tansengming/stripe-rails.svg?branch=master)](https://travis-ci.org/tansengming/stripe-rails)\n[![Code Climate](https://codeclimate.com/github/tansengming/stripe-rails/badges/gpa.svg)](https://codeclimate.com/github/tansengming/stripe-rails)\n[![Test Coverage](https://codeclimate.com/github/tansengming/stripe-rails/badges/coverage.svg)](https://codeclimate.com/github/tansengming/stripe-rails/coverage)\n[![Tidelift](https://tidelift.com/badges/github/tansengming/stripe-rails)](#)\n\nThis gem can help your rails application integrate with Stripe in the following ways\n\n* manage stripe configurations in a single place.\n* makes stripe.js available from the asset pipeline.\n* manage product, prices, plans and coupons from within your app.\n* painlessly receive and validate webhooks from stripe.\n\n[Professionally supported stripe-rails is coming soon](https://tidelift.com/subscription/pkg/rubygems-stripe-rails?utm_source=rubygems-stripe-rails\u0026utm_medium=referral\u0026utm_campaign=readme)\n\n---\n\n[Installation](#installation)\n- [Setup your API keys](#setup-your-api-keys)\n- [Manually set your API version (optional)](#manually-set-your-api-version-optional)\n\n[Setup your payment configuration](#setup-your-payment-configuration)\n- [Configuring your plans and coupons](#configuring-your-plans-and-coupons)\n\n[Stripe Elements](#stripe-elements)\n- [Custom Elements](#custom-elements)\n\n[Webhooks](#webhooks)\n\n- [Signed Webhooks](#signed-webhooks)\n  - [Testing Signed Webhooks Locally](#testing-signed-webhooks-locally)\n- [Disabling auto mount](#disabling-auto-mount)\n- [Responding to webhooks](#responding-to-webhooks)\n- [Critical and non-critical hooks](#critical-and-non-critical-hooks)\n- [Filtering Callbacks](#filtering-callbacks)\n- [Catchall Callback](#catchall-callback)\n\n[Unit testing](#unit-testing)\n\n[Thanks](#thanks)\n\n[Code of Conduct](#code-of-conduct)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'stripe-rails'\n```\n\nIf you are going to be using [stripe.js][1] to securely collect credit card information\non the client, then you will need to add the stripe javascript tags into your template.\nstripe-rails provides a helper to make this easy:\n\n```erb\n\u003c%= stripe_javascript_tag %\u003e\n```\n\nor, you can render it as a partial:\n\n```erb\n\u003c%= render :partial =\u003e 'stripe/js' %\u003e\n```\n\nIn both cases, stripe-rails will choose a version of stripe.js appropriate for your\ndevelopment environment and automatically configure it to use\nyour publishable API key. By default it uses `stripe-debug.js` for your `development`\nenvironment and `stripe.js` for everything else, but you can manually configure it\nper environment.\n\n```ruby\nconfig.stripe.debug_js = true  # use stripe-debug.js\nconfig.stripe.debug_js = false # use stripe.js\n```\n\nBy default the helper renders the `v3` version of `stripe.js`. You can provide an\nalternate version to the helper to generate the appropriate tag:\n\n```erb\n\u003c%= stripe_javascript_tag(:v2) %\u003e\n```\n\n### Setup your API keys.\n\nYou will need to configure your application to authenticate with stripe.com\nusing [your api key][1]. There are two methods to do this, you can either set the environment\nvariable `STRIPE_SECRET_KEY`:\n\n```sh\nexport STRIPE_SECRET_KEY=sk_test_xxyyzz\n```\n\nor if you are on heroku:\n\n```sh\nheroku config:add STRIPE_SECRET_KEY=sk_test_xxyyzz\n```\n\nYou can also set this value from inside ruby configuration code:\n\n```ruby\nconfig.stripe.secret_key = \"sk_test_xxyyzz\"\n```\n\nIn either case, it is recommended that you *not* check in this value into source control.\n\nYou can verify that your api is set up and functioning properly by running the following command:\n\n```sh\nrake stripe:verify\n```\n\nIf you are going to be using stripe.js, then you will also need to set the value of your\npublishable key. A nice way to do it is to set your test publishable for all environments:\n\n```ruby\n# config/application.rb\n# ...\nconfig.stripe.publishable_key = 'pk_test_XXXYYYZZZ'\n```\n\nAnd then override it to use your live key in production only\n\n```ruby\n# config/environments/production.rb\n# ...\nconfig.stripe.publishable_key = 'pk_live_XXXYYYZZZ'\n```\n\nThis key will be publicly visible on the internet, so it is ok to put in your source. If\nyou prefer to environment variables, you can also set `STRIPE_PUBLISHABLE_KEY`:\n\n```sh\nexport STRIPE_PUBLISHABLE_KEY=pk_test_XXXYYYZZZ\n```\n\nIf no API key is provided, `stripe-rails` will show a warning: \"No stripe.com API key was configured ...\". You can silence this warning by setting the `ignore_missing_secret_key` option to `true`:\n\n```ruby\n# config/environments/production.rb\n# ...\nconfig.stripe.ignore_missing_secret_key = true\n```\n\n### Manually set your API version (optional)\n\nIf you need to test a new API version in development, you can override the version number manually.\n\n```ruby\n# config/environments/development.rb\n# ...\nconfig.stripe.api_version = '2015-10-16'\n```\n\n## Setup your payment configuration\n\nIf you're using subscriptions, then you'll need to set up your application's payment plans\nand discounts. `Stripe::Rails` lets you automate the management of these definitions from\nwithin the application itself. To get started:\n\n```sh\nrails generate stripe:install\n```\n\nthis will generate the configuration files containing your plan and coupon definitions:\n\n```console\ncreate  config/stripe/products.rb\ncreate  config/stripe/plans.rb\ncreate  config/stripe/prices.rb\ncreate  config/stripe/coupons.rb\n```\n\n### Configuring your plans and coupons\n\nUse the plan builder to define as many plans as you want in `config/stripe/plans.rb`\n\n```ruby\nStripe.plan :silver do |plan|\n  plan.name = 'ACME Silver'\n  plan.amount = 699 # $6.99\n  plan.interval = 'month'\nend\n\nStripe.plan :gold do |plan|\n  plan.name = 'ACME Gold'\n  plan.amount = 999 # $9.99\n  plan.interval = 'month'\nend\n\nStripe.plan :bronze do |plan|\n  # Use an existing product id to prevent a new plan from\n  # getting created\n  plan.product_id = 'prod_XXXXXXXXXXXXXX'\n  plan.amount = 999 # $9.99\n  plan.interval = 'month'\n\n  # Use graduated pricing tiers\n  # ref: https://stripe.com/docs/api/plans/object#plan_object-tiers\n  plan.tiers = [\n    {\n      unit_amount: 1500,\n      up_to: 10\n    },\n    {\n      unit_amount: 1000,\n      up_to: 'inf'\n    }\n  ]\n  plan.tiers_mode = 'graduated'\n\n  # set the usage type to 'metered'\n  plan.usage_type = 'metered'\nend\n```\n\nThis will define constants for these plans in the Stripe::Plans module so that you\ncan refer to them by reference as opposed to an id string.\n\n```ruby\nStripe::Plans::SILVER # =\u003e 'silver: ACME Silver'\nStripe::Plans::GOLD # =\u003e 'gold: ACME Gold'\n```\n\nIf you have to support an existing plan with a Stripe plan id that can not\nbe used as a Ruby constant, provide the plan id as a symbol when\ndefining the plan, but provide the name for the constant to define with `constant_name`:\n\n```ruby\nStripe.plan \"Silver-Plan\".to_sym do |plan|\n  plan.constant_name = 'SILVER_PLAN' # \u003c---\n  plan.name = 'ACME Silver'\n  plan.amount = 699\n  plan.interval = 'month'\nend\n\nStripe::Plans::SILVER_PLAN # =\u003e will be defined\n# Will map to plan :id =\u003e \"Silver-Plan\" on Stripe\n```\n\n**Note** - If you're planning on running `rake stripe:prepare` to\n  create your subscription plans, Stripe will restrict plan ids to match\n  this regexp (`/\\A[a-zA-Z0-9_\\-]+\\z/`) when created via API but still\n  allows creation of plan ids that don't follow this restriction when\n  manually created on stripe.com.\n\nCoupons are created in much the same way:\n\n```ruby\nStripe.coupon :super_elite_free_vip do |coupon|\n  coupon.duration = 'forever'\n  coupon.percent_off = 100\n  coupon.max_redemptions = 5\nend\n```\n\n\nAs are Products:\n\n```ruby\nStripe.product :primo do |product|\n  product.name = 'PRIMO as a service'\n  product.type = 'service'\n  product.statement_descriptor = 'PRIMO'\nend\n```\n\nAnd Prices:\n\n```ruby\nStripe.price :bronze do |price|\n  # Use an existing product id to prevent a new product from\n  # getting created\n  price.product_id = Stripe::Products::PRIMO.id\n  price.billing_scheme = 'tiered'\n  price.recurring = {\n    interval: 'month',\n    usage_type: 'metered'\n  }\n\n  # Use graduated pricing tiers\n  # ref: https://stripe.com/docs/api/prices/object#price_object-tiers\n  price.tiers = [\n    {\n      unit_amount: 1500,\n      up_to: 10\n    },\n    {\n      unit_amount: 1000,\n      up_to: 'inf'\n    }\n  ]\n  price.tiers_mode = 'graduated'\nend\n````\n\nTo upload your plans, products, prices and coupons onto stripe.com, run:\n\n```sh\nrake stripe:prepare\n```\n\nThis will create any plans, products, prices and coupons that do not currently exist, and treat as a NOOP any\nobjects that already exist, so you can run this command safely as many times as you wish. Now you can\nuse any of these objects in your application.\n\nNOTE: You must destroy plans and prices manually from your stripe dashboard.\n\n## Stripe Elements\n\nStripe::Rails allows you to easily include [Stripe Elements](https://stripe.com/payments/elements) in your application.\n\n\u003e Stripe Elements are rich, pre-built UI components that help you create your own pixel-perfect checkout flows across desktop and mobile.\n\nSimply include the `stripe_elements_tag` anywhere below the `stripe_javascript_tag` and pass it the path to the controller action which will handle the Stripe token once the form is submitted:\n\n```erb\n\u003c%= stripe_javascript_tag %\u003e\n\u003c%= stripe_elements_tag submit_path: billing_path %\u003e\n```\n\nAdditionally, you can pass a block containing custom form elements to stripe_elements_tag:\n\n## Custom Elements\n\n\u003e Stripe::Rails allows you to easily include your own custom form elements\n\u003e within the Stripe form by including those form elements in a block passed to\n\u003e `stripe_elements_tag`:\n\n```erb\n\u003c%= stripe_javascript_tag %\u003e\n\u003c%= stripe_elements_tag(submit_path: billing_path) do %\u003e\n  \u003c%= label_tag 'email', 'Email' %\u003e\n  \u003c%= text_field :user, :email %\u003e\n\u003c% end %\u003e\n```\n\n### Configuration options\n\nStripe::Rails comes bundled with default CSS and Javascript for Stripe elements, making it easy to drop in to your app. You can also specify your own assets paths:\n\n```erb\n\u003c%= stripe_elements_tag submit_path: billing_path,\n                        css_path: 'your/asset/path',\n                        js_path: 'your/asset/path' %\u003e\n```\n\nIf you decide to use your own CSS and Javascript for Stripe Elements, please refer to the [Stripe elements docs](https://stripe.com/docs/stripe-js/elements/quickstart).\n\nTo change the form text you can add the following keys to your locale files\n\n```yaml\n# config/locales/en.yml\nen:\n  stripe_rails:\n    elements:\n      label_text: Your label text\n      submit_button_text: Your button text\n```\n\n## Webhooks\n\nStripe::Rails automatically sets up your application to receive webhooks from stripe.com whenever\na payment event is generated. To enable this, you will need to configure your [stripe webhooks][3] to\npoint back to your application. By default, the webhook controller is mounted at '/stripe/events' so\nyou would want to enter in `http://myproductionapp.com/stripe/events` as your url for live mode,\nand `http://mystagingapp.com/stripe/events` for your test mode.\n\nIf you want to mount the stripe engine somewhere else, you can do so by setting the `stripe.endpoint`\nparameter. E.g.\n\n```ruby\nconfig.stripe.endpoint = '/payment/stripe-integration'\n```\n\nYour new webhook URL would then be `http://myproductionapp/payment/stripe-integration/events`\n\n### Signed Webhooks\n\nValidation of your webhook's signature uses your webhook endpoint signing secret.\nBefore you can verify signatures, you need to retrieve your endpoint’s secret from your\nStripe Dashboard. Select an endpoint for which you want to obtain\nthe secret, then select the Click to reveal button.\n\n```ruby\n# config/application.rb\n# ...\nconfig.stripe.signing_secrets = ['whsec_XXXYYYZZZ']\n```\n\nEach secret is unique to the endpoint to which it corresponds. If you use multiple endpoint,\nyou must obtain a secret for each one. After this setup, Stripe starts to sign each webhook\nit sends to the endpoint. Because of this, we recommend setting this variable with environment\nvariables:\n\n```sh\nexport STRIPE_SIGNING_SECRET=whsec_XXXYYYZZZ\nexport STRIPE_CONNECT_SIGNING_SECRET=whsec_AAABBBCCC\n```\n\n```ruby\nconfig.stripe.signing_secrets = [ENV.fetch('STRIPE_SIGNING_SECRET'), ENV.fetch('STRIPE_CONNECT_SIGNING_SECRET')]\n```\n\nThe first secret that successfully matches for each incoming webhook will be used to verify the incoming events.\n\n#### Testing Signed Webhooks Locally\n\nIn order to test signed webhooks, you'll need to trigger test webhooks from your Stripe dashboard,\nand configure your local environment to receive remote network requests. To do so, we recommend using\n[ngrok](https://ngrok.com/) to configure a secure tunnel to `localhost`.\n\nOnce configured and running, `ngrok` will give you a unique URL which can be used to set up a webhook\nendpoint. Webhook endpoints are configured in your Dashboard's [Webhook settings](https://dashboard.stripe.com/account/webhooks)\nsection. Make sure you are in **Test** mode and click `Add endpoint`, and provide your `ngrok` URL along with the `stripe.endpoint` suffix.\n\nAn example webhook URL would then be `https://bf2a5d21.ngrok.io/stripe/events`.\n\nOnce your endpoint is configured, you can reveal the **Signing secret**. This will need to be set\nas documented above:\n\n```ruby\n# config/application.rb\n# ...\nconfig.stripe.signing_secrets = ['whsec_XXXYYYZZZ']\n```\n\nAnd you'll need to restart your rails server with:\n\n```sh\nrails restart\n```\n\nNow you're ready to click **Send test webhook**, and trigger whichever events you'd like to test from Stripe itself.\n\n### Disabling auto mount\n\nSometimes, you don't want the stripe engine to be auto-mounted so that\nyou control *exactly* what priority it will take in your routing\ntable. This is especially important if you have a catch-all route\nwhich should appear after all other routes. In order to disable\nauto-mounting of the Stripe engine:\n\n```ruby\n# in application.rb\nconfig.stripe.auto_mount = false\n```\n\nThen, you will have to manually mount the engine in your main application.\n\n```ruby\n# in your application's routes.rb:\nmount Stripe::Engine =\u003e \"/stripe\"\n```\n\n### Responding to webhooks\n\nOnce you have your webhook URL configured you can respond to a stripe webhook *anywhere* in your\napplication just by including the Stripe::Callbacks module into your class and declaring a\ncallback with one of the callback methods. For example, to update a customer's payment status:\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  include Stripe::Callbacks\n\n  after_customer_updated! do |customer, event|\n    user = User.find_by_stripe_customer_id(customer.id)\n    if customer.delinquent\n      user.is_account_current = false\n      user.save!\n    end\n  end\nend\n```\n\nor to send an email with one of your customer's monthly invoices\n\n```ruby\nclass InvoiceMailer \u003c ActionMailer::Base\n  include Stripe::Callbacks\n\n  after_invoice_created! do |invoice, event|\n    user = User.find_by_stripe_customer(invoice.customer)\n    new_invoice(user, invoice).deliver\n  end\n\n  def new_invoice(user, invoice)\n    @user = user\n    @invoice = invoice\n    mail :to =\u003e user.email, :subject =\u003e '[Acme.com] Your new invoice'\n  end\nend\n```\n\n**Note:** `Stripe::Callbacks` won't get included until the including class has been loaded. This is usually not an issue in the production environment as eager loading is enabled by default (`config.eager_load = true`). You may run into an issue in your development environment where eager loading is disabled by default.\n\nIf you don't wish to enable eager loading in development, you can configure the classes to be eager loaded like so\n\n```ruby\n# in your application's config/environments/development.rb\nconfig.stripe.eager_load = 'account', 'module/some_class', 'etc'\n```\nThis will ensure that callbacks will get loaded in those configured classes if eager loading is disabled.\n\nThe naming convention for the callback events is after__{callback_name}! where `callback_name`\nis name of the stripe event with all `.` characters substituted with underscores. So, for\nexample, the stripe event `customer.discount.created` can be hooked by `after_customer_discount_created!`\nand so on...\n\nEach web hook is passed an instance of the stripe object to which the event corresponds\n([`Stripe::Customer`][8], [`Stripe::Invoice`][9], [`Stripe::Charge`][10], etc...) as well as the [`Stripe::Event`][4] which contains metadata about the event being raised.\n\nBy default, the event is re-fetched securely from stripe.com to prevent damage to your system by\na malicious system spoofing real stripe events.\n\n\n\n### Critical and non-critical hooks\n\nSo far, the examples have all used critical hooks, but in fact, each callback method comes in two flavors: \"critical\",\nspecified with a trailing `!` character, and \"non-critical\", which has no \"bang\" character at all. What\ndistinguishes one from the other is that _if an exception is raised in a critical callback, it will cause the entire webhook to fail_.\n\nThis will indicate to stripe.com that you did not receive the webhook at all, and that it should retry it again later until it\nreceives a successful response. On the other hand, there are some tasks that are more tangential to the payment work flow and aren't\nsuch a big deal if they get dropped on the floor. For example, A non-critical hook can be used to do things like have a bot\nnotify your company's chatroom that something a credit card was successfully charged:\n\n```ruby\nclass AcmeBot\n  include Stripe::Callbacks\n\n  after_charge_succeeded do |charge|\n    announce \"Attention all Dudes and Dudettes. Ya'll are so PAID!!!\"\n  end\nend\n```\n\nChances are that if you experience a momentary failure in connectivity to your chatroom, you don't want the whole payment notification to fail.\n\n\n### Filtering Callbacks\n\nCertain stripe events represent updates to existing data. You may want to only fire the event when certain attributes of that data\nare updated. You can pass an `:only` option to your callback to filter to specify which attribute updates you're interested in. For\nexample, to warn users whenever their credit card has changed:\n\n```ruby\nclass StripeMailer\n  include Stripe::Callbacks\n\n  after_customer_updated! :only =\u003e :active_card do |customer, evt|\n    your_credit_card_on_file_was_updated_are_you_sure_this_was_you(customer).deliver\n  end\nend\n```\n\nFilters can be specified as an array as well:\n\n```ruby\nmodule Accounting\n  include Stripe::Callbacks\n\n  after_invoice_updated! :only =\u003e [:amount, :subtotal] do\n    # update our records\n  end\nend\n```\n\nAlternatively, you can just pass a proc to filter the event manually. It will receive an instance of [`Stripe::Event`][4] as\nits parameter:\n\n```ruby\nmodule StagingOnly\n  include Stripe::Callbacks\n\n  after_charge_succeeded! :only =\u003e proc {|charge, evt| unless evt.livemode} do |charge|\n    puts \"FAKE DATA, PLEASE IGNORE!\"\n  end\nend\n```\n\n### Catchall Callback\n\nThe special 'stripe.event' callback will be invoked for every single event received from stripe.com. This can be useful for things\nlike logging and analytics:\n\n```ruby\nclass StripeFirehose\n  include Stripe::Callbacks\n\n  after_stripe_event do |target, event|\n    # do something useful\n  end\nend\n```\n\nSee the [complete listing of all stripe events][5], and the [webhook tutorial][6] for more great information on this subject.\n\n## Unit testing\n\nIf you want to test your callbacks, you can use the `Stripe::Rails::Testing` module to send mocked Stripe events.\n\n```ruby\nrequire 'stripe/rails/testing'\ntest \"my callback handles new subscription\" do\n  Stripe::Rails::Testing.send_event \"customer.subscription.created\"\n  # Assertions\nend\n```\n\nYou can also overwrite some event properties: ([More info](https://github.com/rebelidealist/stripe-ruby-mock#customizing-webhooks))\n\n```ruby\nrequire 'stripe/rails/testing'\ntest \"my callback handles new subscription\" do\n  Stripe::Rails::Testing.send_event \"customer.subscription.created\", {\n    :email =\u003e \"john@doe.com\",\n    :account_balance =\u003e 40\n  }\n  # Assertions\nend\n```\n\nThe default fixtures come from [the `stripe-ruby-mock` gem](https://github.com/rebelidealist/stripe-ruby-mock/tree/master/lib/stripe_mock/webhook_fixtures).\n\n## Thanks\n\n\u003ca href=\"http://frontside.io\"\u003e![Frontside](http://frontside.io/images/logo.svg)\u003c/a\u003e\n\n`Stripe::Rails` was originally developed with love and fondness by your friends at [Frontside][7]. They are available for your custom software development needs, including integration with stripe.com.\n\n\u003ca href=\"https://www.evercondo.com\"\u003e![Evercondo](https://dl.dropboxusercontent.com/s/m3ma9356uelep53/evercondo.png)\u003c/a\u003e\n\n`Stripe::Rails` has also been supported by the fine folks at [Evercondo][11], the next generation condo management software.\n\n\n[1]: https://stripe.com/docs/stripe.js\n[2]: https://manage.stripe.com/#account/apikeys\n[3]: https://manage.stripe.com/#account/webhooks\n[4]: https://stripe.com/docs/api?lang=ruby#events\n[5]: https://stripe.com/docs/api?lang=ruby#event_types\n[6]: https://stripe.com/docs/webhooks\n[7]: http://frontside.io\n[8]: https://stripe.com/docs/api?lang=ruby#customers\n[9]: https://stripe.com/docs/api?lang=ruby#invoices\n[10]: https://stripe.com/docs/api?lang=ruby#charges\n[11]: https://www.evercondo.com\n\n\n## Code of Conduct\n\nPlease note that this project is released with a Contributor Code of\nConduct. By participating in this project you agree to abide by its\nterms, which can be found in the `CODE_OF_CONDUCT.md` file in this\nrepository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftansengming%2Fstripe-rails","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftansengming%2Fstripe-rails","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftansengming%2Fstripe-rails/lists"}