feat: add Stripe meter ID configuration
- Add stripe_meter_id to dev, runtime, and test configs - Add STRIPE_METER_ID to k8s deployment secret references - Use real Stripe meter and price IDs from Stripe setup - Meter: mtr_test_61UHPU067veEZ7bhl41S77kvnTfgyODY - Price: price_1T81XBS77kvnTfgyPlw1jF8N ($1/device/month) - Include setup script for Stripe billing configuration
This commit is contained in:
parent
20f05584dc
commit
d0e7eb4308
4 changed files with 128 additions and 3 deletions
|
|
@ -219,4 +219,5 @@ config :towerops,
|
|||
stripe_secret_key:
|
||||
"sk_test_51T7zcQS77kvnTfgyu0DCQU2xVKzeaneVCueHaXV3jsIw6HAwGWWllEL3J8jGZOybHAtPyu6oYIiuvJHhReFtTycE00VrJYJ8Ao",
|
||||
stripe_webhook_secret: "whsec_dev_fake_secret",
|
||||
stripe_price_id: "price_dev_fake_id"
|
||||
stripe_price_id: "price_1T81XBS77kvnTfgyPlw1jF8N",
|
||||
stripe_meter_id: "mtr_test_61UHPU067veEZ7bhl41S77kvnTfgyODY"
|
||||
|
|
|
|||
|
|
@ -373,10 +373,18 @@ if config_env() == :prod do
|
|||
This is the Stripe price ID for the metered billing plan.
|
||||
"""
|
||||
|
||||
stripe_meter_id =
|
||||
System.get_env("STRIPE_METER_ID") ||
|
||||
raise """
|
||||
environment variable STRIPE_METER_ID is missing.
|
||||
This is the Stripe billing meter ID for usage reporting.
|
||||
"""
|
||||
|
||||
config :towerops,
|
||||
stripe_secret_key: stripe_secret_key,
|
||||
stripe_webhook_secret: stripe_webhook_secret,
|
||||
stripe_price_id: stripe_price_id
|
||||
stripe_price_id: stripe_price_id,
|
||||
stripe_meter_id: stripe_meter_id
|
||||
end
|
||||
|
||||
# Test environment Stripe configuration
|
||||
|
|
@ -384,5 +392,6 @@ if config_env() == :test do
|
|||
config :towerops,
|
||||
stripe_secret_key: "sk_test_fake",
|
||||
stripe_webhook_secret: "whsec_test_fake",
|
||||
stripe_price_id: "price_test_fake"
|
||||
stripe_price_id: "price_test_fake",
|
||||
stripe_meter_id: "meter_test_fake"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ spec:
|
|||
name: towerops-billing
|
||||
key: STRIPE_PRICE_ID
|
||||
optional: true
|
||||
- name: STRIPE_METER_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: towerops-billing
|
||||
key: STRIPE_METER_ID
|
||||
optional: true
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: towerops-db
|
||||
|
|
@ -189,6 +195,12 @@ spec:
|
|||
name: towerops-billing
|
||||
key: STRIPE_PRICE_ID
|
||||
optional: true
|
||||
- name: STRIPE_METER_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: towerops-billing
|
||||
key: STRIPE_METER_ID
|
||||
optional: true
|
||||
envFrom:
|
||||
# Redis connection configured via towerops-redis secret
|
||||
- secretRef:
|
||||
|
|
|
|||
103
setup_stripe_meter.exs
Normal file
103
setup_stripe_meter.exs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env elixir
|
||||
|
||||
# Setup script for Stripe billing meter
|
||||
|
||||
stripe_key = "sk_test_51T7zcQS77kvnTfgyu0DCQU2xVKzeaneVCueHaXV3jsIw6HAwGWWllEL3J8jGZOybHAtPyu6oYIiuvJHhReFtTycE00VrJYJ8Ao"
|
||||
product_id = "prod_U6DpFdl21ftiDz"
|
||||
|
||||
IO.puts("Creating Stripe billing meter...")
|
||||
|
||||
# Create billing meter
|
||||
form_data =
|
||||
URI.encode_query(%{
|
||||
"display_name" => "Devices Monitored",
|
||||
"event_name" => "devices_monitored",
|
||||
"default_aggregation[formula]" => "sum",
|
||||
"value_settings[event_payload_key]" => "value"
|
||||
})
|
||||
|
||||
{output, exit_code} =
|
||||
System.cmd(
|
||||
"curl",
|
||||
[
|
||||
"-X",
|
||||
"POST",
|
||||
"https://api.stripe.com/v1/billing/meters",
|
||||
"-u",
|
||||
"#{stripe_key}:",
|
||||
"-H",
|
||||
"Stripe-Version: 2024-11-20.acacia",
|
||||
"-H",
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
"-d",
|
||||
form_data
|
||||
],
|
||||
stderr_to_stdout: true
|
||||
)
|
||||
|
||||
if exit_code == 0 do
|
||||
case Jason.decode(output) do
|
||||
{:ok, meter} ->
|
||||
IO.puts("\n✓ Billing meter created successfully!")
|
||||
IO.puts(" Meter ID: #{meter["id"]}")
|
||||
IO.puts(" Display name: #{meter["display_name"]}")
|
||||
IO.puts(" Event name: #{meter["event_name"]}")
|
||||
IO.puts("\nNow creating metered price...")
|
||||
|
||||
# Create metered price linked to the meter
|
||||
price_form =
|
||||
URI.encode_query(%{
|
||||
"product" => product_id,
|
||||
"currency" => "usd",
|
||||
"recurring[interval]" => "month",
|
||||
"recurring[usage_type]" => "metered",
|
||||
"recurring[meter]" => meter["id"],
|
||||
"billing_scheme" => "per_unit",
|
||||
# $1.00 in cents
|
||||
"unit_amount" => "100",
|
||||
"nickname" => "Per Device Monthly"
|
||||
})
|
||||
|
||||
{price_output, price_exit} =
|
||||
System.cmd(
|
||||
"curl",
|
||||
[
|
||||
"-X",
|
||||
"POST",
|
||||
"https://api.stripe.com/v1/prices",
|
||||
"-u",
|
||||
"#{stripe_key}:",
|
||||
"-H",
|
||||
"Stripe-Version: 2024-11-20.acacia",
|
||||
"-H",
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
"-d",
|
||||
price_form
|
||||
],
|
||||
stderr_to_stdout: true
|
||||
)
|
||||
|
||||
if price_exit == 0 do
|
||||
case Jason.decode(price_output) do
|
||||
{:ok, price} ->
|
||||
IO.puts("\n✓ Price created successfully!")
|
||||
IO.puts(" Price ID: #{price["id"]}")
|
||||
IO.puts(" Amount: $#{price["unit_amount"] / 100}/device/month")
|
||||
IO.puts("\n" <> String.duplicate("=", 60))
|
||||
IO.puts("SETUP COMPLETE!")
|
||||
IO.puts(String.duplicate("=", 60))
|
||||
IO.puts("\nAdd these to your Kubernetes secret:")
|
||||
IO.puts(" STRIPE_METER_ID=#{meter["id"]}")
|
||||
IO.puts(" STRIPE_PRICE_ID=#{price["id"]}")
|
||||
|
||||
{:error, _} ->
|
||||
IO.puts("\nError creating price: #{price_output}")
|
||||
end
|
||||
end
|
||||
|
||||
{:error, _} ->
|
||||
IO.puts("\nError: #{output}")
|
||||
end
|
||||
else
|
||||
IO.puts("\nCurl failed: #{output}")
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue