stripe-ruby-mock 3.0.1 → 3.1.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +2 -5
- data/CHANGELOG.md +28 -15
- data/Gemfile +1 -0
- data/lib/stripe_mock.rb +4 -0
- data/lib/stripe_mock/api/client.rb +1 -1
- data/lib/stripe_mock/api/instance.rb +1 -1
- data/lib/stripe_mock/api/webhooks.rb +2 -0
- data/lib/stripe_mock/client.rb +2 -1
- data/lib/stripe_mock/data.rb +127 -25
- data/lib/stripe_mock/data/list.rb +31 -6
- data/lib/stripe_mock/instance.rb +7 -2
- data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/charges.rb +6 -4
- data/lib/stripe_mock/request_handlers/checkout_session.rb +16 -0
- data/lib/stripe_mock/request_handlers/customers.rb +22 -13
- data/lib/stripe_mock/request_handlers/ephemeral_key.rb +1 -1
- data/lib/stripe_mock/request_handlers/express_login_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +12 -7
- data/lib/stripe_mock/request_handlers/invoices.rb +4 -3
- data/lib/stripe_mock/request_handlers/payment_methods.rb +8 -5
- data/lib/stripe_mock/request_handlers/prices.rb +44 -0
- data/lib/stripe_mock/request_handlers/sources.rb +12 -6
- data/lib/stripe_mock/request_handlers/subscriptions.rb +29 -19
- data/lib/stripe_mock/request_handlers/tokens.rb +6 -4
- data/lib/stripe_mock/request_handlers/validators/param_validators.rb +32 -0
- data/lib/stripe_mock/test_strategies/base.rb +26 -0
- data/lib/stripe_mock/version.rb +1 -1
- data/lib/stripe_mock/webhook_fixtures/balance.available.json +6 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +186 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +164 -0
- data/spec/instance_spec.rb +4 -6
- data/spec/list_spec.rb +23 -0
- data/spec/server_spec.rb +4 -2
- data/spec/shared_stripe_examples/account_link_examples.rb +16 -0
- data/spec/shared_stripe_examples/balance_examples.rb +6 -0
- data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
- data/spec/shared_stripe_examples/checkout_examples.rb +20 -1
- data/spec/shared_stripe_examples/customer_examples.rb +11 -13
- data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
- data/spec/shared_stripe_examples/invoice_examples.rb +8 -8
- data/spec/shared_stripe_examples/payment_method_examples.rb +332 -68
- data/spec/shared_stripe_examples/price_examples.rb +183 -0
- data/spec/shared_stripe_examples/subscription_examples.rb +115 -8
- data/spec/spec_helper.rb +4 -0
- data/spec/stripe_mock_spec.rb +2 -2
- data/spec/support/stripe_examples.rb +5 -1
- data/stripe-ruby-mock.gemspec +6 -1
- metadata +25 -11
@@ -17,26 +17,29 @@ module StripeMock
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def retrieve_customer_subscription(route, method_url, params, headers)
|
20
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
20
21
|
route =~ method_url
|
21
22
|
|
22
|
-
customer = assert_existence :customer, $1, customers[$1]
|
23
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
23
24
|
subscription = get_customer_subscription(customer, $2)
|
24
25
|
|
25
26
|
assert_existence :subscription, $2, subscription
|
26
27
|
end
|
27
28
|
|
28
29
|
def retrieve_customer_subscriptions(route, method_url, params, headers)
|
30
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
29
31
|
route =~ method_url
|
30
32
|
|
31
|
-
customer = assert_existence :customer, $1, customers[$1]
|
33
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
32
34
|
customer[:subscriptions]
|
33
35
|
end
|
34
36
|
|
35
37
|
def create_customer_subscription(route, method_url, params, headers)
|
38
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
36
39
|
route =~ method_url
|
37
40
|
|
38
41
|
subscription_plans = get_subscription_plans_from_params(params)
|
39
|
-
customer = assert_existence :customer, $1, customers[$1]
|
42
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
40
43
|
|
41
44
|
if params[:source]
|
42
45
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -73,10 +76,10 @@ module StripeMock
|
|
73
76
|
end
|
74
77
|
|
75
78
|
def create_subscription(route, method_url, params, headers)
|
79
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
76
80
|
if headers && headers[:idempotency_key]
|
77
81
|
if subscriptions.any?
|
78
82
|
original_subscription = subscriptions.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
|
79
|
-
puts original_subscription
|
80
83
|
return subscriptions[original_subscription[:id]] if original_subscription
|
81
84
|
end
|
82
85
|
end
|
@@ -86,15 +89,7 @@ module StripeMock
|
|
86
89
|
|
87
90
|
customer = params[:customer]
|
88
91
|
customer_id = customer.is_a?(Stripe::Customer) ? customer[:id] : customer.to_s
|
89
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
90
|
-
|
91
|
-
if subscription_plans && customer
|
92
|
-
subscription_plans.each do |plan|
|
93
|
-
unless customer[:currency].to_s == plan[:currency].to_s
|
94
|
-
raise Stripe::InvalidRequestError.new("Customer's currency of #{customer[:currency]} does not match plan's currency of #{plan[:currency]}", 'currency', http_status: 400)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
92
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
98
93
|
|
99
94
|
if params[:source]
|
100
95
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -102,7 +97,7 @@ module StripeMock
|
|
102
97
|
customer[:default_source] = new_card[:id]
|
103
98
|
end
|
104
99
|
|
105
|
-
allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor billing days_until_due idempotency_key enable_incomplete_payments cancel_at_period_end default_tax_rates payment_behavior pending_invoice_item_interval)
|
100
|
+
allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor billing days_until_due idempotency_key enable_incomplete_payments cancel_at_period_end default_tax_rates payment_behavior pending_invoice_item_interval default_payment_method collection_method off_session trial_from_plan expand)
|
106
101
|
unknown_params = params.keys - allowed_params.map(&:to_sym)
|
107
102
|
if unknown_params.length > 0
|
108
103
|
raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400)
|
@@ -133,6 +128,10 @@ module StripeMock
|
|
133
128
|
end
|
134
129
|
end
|
135
130
|
|
131
|
+
if params[:trial_period_days]
|
132
|
+
subscription[:status] = 'trialing'
|
133
|
+
end
|
134
|
+
|
136
135
|
if params[:cancel_at_period_end]
|
137
136
|
subscription[:cancel_at_period_end] = true
|
138
137
|
subscription[:canceled_at] = Time.now.utc.to_i
|
@@ -151,14 +150,16 @@ module StripeMock
|
|
151
150
|
end
|
152
151
|
|
153
152
|
def retrieve_subscriptions(route, method_url, params, headers)
|
153
|
+
# stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
154
154
|
route =~ method_url
|
155
155
|
|
156
156
|
Data.mock_list_object(subscriptions.values, params)
|
157
|
-
#customer = assert_existence :customer, $1, customers[$1]
|
157
|
+
#customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
158
158
|
#customer[:subscriptions]
|
159
159
|
end
|
160
160
|
|
161
161
|
def update_subscription(route, method_url, params, headers)
|
162
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
162
163
|
route =~ method_url
|
163
164
|
|
164
165
|
subscription_id = $2 ? $2 : $1
|
@@ -166,7 +167,7 @@ module StripeMock
|
|
166
167
|
verify_active_status(subscription)
|
167
168
|
|
168
169
|
customer_id = subscription[:customer]
|
169
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
170
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
170
171
|
|
171
172
|
if params[:source]
|
172
173
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -197,6 +198,10 @@ module StripeMock
|
|
197
198
|
end
|
198
199
|
end
|
199
200
|
|
201
|
+
if params[:trial_period_days]
|
202
|
+
subscription[:status] = 'trialing'
|
203
|
+
end
|
204
|
+
|
200
205
|
if params[:cancel_at_period_end]
|
201
206
|
subscription[:cancel_at_period_end] = true
|
202
207
|
subscription[:canceled_at] = Time.now.utc.to_i
|
@@ -222,13 +227,14 @@ module StripeMock
|
|
222
227
|
end
|
223
228
|
|
224
229
|
def cancel_subscription(route, method_url, params, headers)
|
230
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
225
231
|
route =~ method_url
|
226
232
|
|
227
233
|
subscription_id = $2 ? $2 : $1
|
228
234
|
subscription = assert_existence :subscription, subscription_id, subscriptions[subscription_id]
|
229
235
|
|
230
236
|
customer_id = subscription[:customer]
|
231
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
237
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
232
238
|
|
233
239
|
cancel_params = { canceled_at: Time.now.utc.to_i }
|
234
240
|
cancelled_at_period_end = (params[:at_period_end] == true)
|
@@ -257,14 +263,17 @@ module StripeMock
|
|
257
263
|
elsif params[:items]
|
258
264
|
items = params[:items]
|
259
265
|
items = items.values if items.respond_to?(:values)
|
260
|
-
items.map { |item| item[:plan]
|
266
|
+
items.map { |item| item[:plan] ? item[:plan] : item[:price] }
|
261
267
|
else
|
262
268
|
[]
|
263
269
|
end
|
270
|
+
plan_ids.compact!
|
264
271
|
plan_ids.each do |plan_id|
|
265
272
|
assert_existence :plan, plan_id, plans[plan_id]
|
273
|
+
rescue Stripe::InvalidRequestError
|
274
|
+
assert_existence :price, plan_id, prices[plan_id]
|
266
275
|
end
|
267
|
-
plan_ids.map { |plan_id| plans[plan_id] }
|
276
|
+
plan_ids.map { |plan_id| plans[plan_id] || prices[plan_id]}
|
268
277
|
end
|
269
278
|
|
270
279
|
# Ensure customer has card to charge unless one of the following criterias is met:
|
@@ -276,6 +285,7 @@ module StripeMock
|
|
276
285
|
return if customer[:invoice_settings][:default_payment_method]
|
277
286
|
return if customer[:trial_end]
|
278
287
|
return if params[:trial_end]
|
288
|
+
return if subscription[:default_payment_method]
|
279
289
|
|
280
290
|
plan_trial_period_days = plan[:trial_period_days] || 0
|
281
291
|
plan_has_trial = plan_trial_period_days != 0 || plan[:amount] == 0 || plan[:trial_end]
|
@@ -8,6 +8,8 @@ module StripeMock
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def create_token(route, method_url, params, headers)
|
11
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
12
|
+
|
11
13
|
if params[:customer].nil? && params[:card].nil? && params[:bank_account].nil?
|
12
14
|
raise Stripe::InvalidRequestError.new('You must supply either a card, customer, or bank account to create a token.', nil, http_status: 400)
|
13
15
|
end
|
@@ -15,13 +17,13 @@ module StripeMock
|
|
15
17
|
cus_id = params[:customer]
|
16
18
|
|
17
19
|
if cus_id && params[:source]
|
18
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
20
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id]
|
19
21
|
|
20
22
|
# params[:card] is an id; grab it from the db
|
21
23
|
customer_card = get_card(customer, params[:source])
|
22
24
|
assert_existence :card, params[:source], customer_card
|
23
25
|
elsif params[:card].is_a?(String)
|
24
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
26
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id]
|
25
27
|
|
26
28
|
# params[:card] is an id; grab it from the db
|
27
29
|
customer_card = get_card(customer, params[:card])
|
@@ -32,7 +34,7 @@ module StripeMock
|
|
32
34
|
params[:card][:last4] = params[:card][:number][-4,4]
|
33
35
|
customer_card = params[:card]
|
34
36
|
elsif params[:bank_account].is_a?(String)
|
35
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
37
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id]
|
36
38
|
|
37
39
|
# params[:bank_account] is an id; grab it from the db
|
38
40
|
bank_account = verify_bank_account(customer, params[:bank_account])
|
@@ -41,7 +43,7 @@ module StripeMock
|
|
41
43
|
# params[:card] is a hash of cc info; "Sanitize" the card number
|
42
44
|
bank_account = params[:bank_account]
|
43
45
|
else
|
44
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
46
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id] || customers[Stripe.api_key][cus_id]
|
45
47
|
customer_card = get_card(customer, customer[:default_source])
|
46
48
|
end
|
47
49
|
|
@@ -110,9 +110,41 @@ module StripeMock
|
|
110
110
|
|
111
111
|
end
|
112
112
|
|
113
|
+
def validate_create_price_params(params)
|
114
|
+
price_id = params[:id].to_s
|
115
|
+
product_id = params[:product]
|
116
|
+
|
117
|
+
@base_strategy.create_price_params.keys.each do |attr_name|
|
118
|
+
message = "Missing required param: #{attr_name}."
|
119
|
+
raise Stripe::InvalidRequestError.new(message, attr_name) if params[attr_name].nil?
|
120
|
+
end
|
121
|
+
|
122
|
+
if prices[price_id]
|
123
|
+
message = already_exists_message(Stripe::Price)
|
124
|
+
raise Stripe::InvalidRequestError.new(message, :id)
|
125
|
+
end
|
126
|
+
|
127
|
+
unless products[product_id]
|
128
|
+
message = not_found_message(Stripe::Product, product_id)
|
129
|
+
raise Stripe::InvalidRequestError.new(message, :product)
|
130
|
+
end
|
131
|
+
|
132
|
+
unless SUPPORTED_CURRENCIES.include?(params[:currency])
|
133
|
+
message = invalid_currency_message(params[:currency])
|
134
|
+
raise Stripe::InvalidRequestError.new(message, :currency)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def validate_list_prices_params(params)
|
139
|
+
if params[:lookup_keys] && !params[:lookup_keys].is_a?(Array)
|
140
|
+
raise Stripe::InvalidRequestError.new('Invalid array', :lookup_keys)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
113
144
|
def require_param(param_name)
|
114
145
|
raise Stripe::InvalidRequestError.new("Missing required param: #{param_name}.", param_name.to_s, http_status: 400)
|
115
146
|
end
|
147
|
+
|
116
148
|
end
|
117
149
|
end
|
118
150
|
end
|
@@ -41,6 +41,15 @@ module StripeMock
|
|
41
41
|
}.merge(params)
|
42
42
|
end
|
43
43
|
|
44
|
+
def create_price(params={})
|
45
|
+
Stripe::Price.create create_price_params(params)
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_price_params(params={})
|
49
|
+
{
|
50
|
+
:currency => StripeMock.default_currency,
|
51
|
+
}.merge(params)
|
52
|
+
end
|
44
53
|
|
45
54
|
def list_subscriptions(limit)
|
46
55
|
Stripe::Subscription.list(limit: limit)
|
@@ -97,10 +106,27 @@ module StripeMock
|
|
97
106
|
}.merge(params)
|
98
107
|
end
|
99
108
|
|
109
|
+
def create_checkout_session_params(params = {})
|
110
|
+
{
|
111
|
+
payment_method_types: ['card'],
|
112
|
+
line_items: [{
|
113
|
+
name: 'T-shirt',
|
114
|
+
quantity: 1,
|
115
|
+
amount: 500,
|
116
|
+
currency: 'usd',
|
117
|
+
}],
|
118
|
+
}.merge(params)
|
119
|
+
end
|
120
|
+
|
121
|
+
|
100
122
|
def create_coupon(params = {})
|
101
123
|
Stripe::Coupon.create create_coupon_params(params)
|
102
124
|
end
|
103
125
|
|
126
|
+
def create_checkout_session(params = {})
|
127
|
+
Stripe::Checkout::Session.create create_checkout_session_params(params)
|
128
|
+
end
|
129
|
+
|
104
130
|
def delete_all_coupons
|
105
131
|
coupons = Stripe::Coupon.list
|
106
132
|
coupons.data.map(&:delete) if coupons.data.count > 0
|
data/lib/stripe_mock/version.rb
CHANGED
@@ -0,0 +1,186 @@
|
|
1
|
+
{
|
2
|
+
"id": "evt_00000000000000",
|
3
|
+
"object": "event",
|
4
|
+
"api_version": "2018-02-28",
|
5
|
+
"created": 1578401135,
|
6
|
+
"data": {
|
7
|
+
"object": {
|
8
|
+
"id": "pi_00000000000000",
|
9
|
+
"object": "payment_intent",
|
10
|
+
"allowed_source_types": ["card", "sepa_debit"],
|
11
|
+
"amount": 200,
|
12
|
+
"amount_capturable": 0,
|
13
|
+
"amount_received": 0,
|
14
|
+
"application": null,
|
15
|
+
"application_fee_amount": null,
|
16
|
+
"canceled_at": null,
|
17
|
+
"cancellation_reason": null,
|
18
|
+
"capture_method": "automatic",
|
19
|
+
"charges": {
|
20
|
+
"object": "list",
|
21
|
+
"data": [
|
22
|
+
{
|
23
|
+
"id": "py_00000000000000",
|
24
|
+
"object": "charge",
|
25
|
+
"amount": 200,
|
26
|
+
"amount_refunded": 0,
|
27
|
+
"application": null,
|
28
|
+
"application_fee": null,
|
29
|
+
"application_fee_amount": null,
|
30
|
+
"balance_transaction": null,
|
31
|
+
"billing_details": {
|
32
|
+
"address": {
|
33
|
+
"city": null,
|
34
|
+
"country": null,
|
35
|
+
"line1": null,
|
36
|
+
"line2": null,
|
37
|
+
"postal_code": null,
|
38
|
+
"state": null
|
39
|
+
},
|
40
|
+
"email": "john.doe@example.com",
|
41
|
+
"name": "John Doe",
|
42
|
+
"phone": null
|
43
|
+
},
|
44
|
+
"captured": true,
|
45
|
+
"created": 1578401129,
|
46
|
+
"currency": "eur",
|
47
|
+
"customer": "cus_00000000000000",
|
48
|
+
"description": null,
|
49
|
+
"destination": "acct_00000000000000",
|
50
|
+
"dispute": null,
|
51
|
+
"disputed": false,
|
52
|
+
"failure_code": null,
|
53
|
+
"failure_message": null,
|
54
|
+
"fraud_details": {},
|
55
|
+
"invoice": null,
|
56
|
+
"livemode": false,
|
57
|
+
"metadata": {},
|
58
|
+
"on_behalf_of": null,
|
59
|
+
"order": null,
|
60
|
+
"outcome": {
|
61
|
+
"network_status": "approved_by_network",
|
62
|
+
"reason": null,
|
63
|
+
"risk_level": "not_assessed",
|
64
|
+
"seller_message": "Payment complete.",
|
65
|
+
"type": "authorized"
|
66
|
+
},
|
67
|
+
"paid": false,
|
68
|
+
"payment_intent": "pi_00000000000000",
|
69
|
+
"payment_method": "pm_00000000000000",
|
70
|
+
"payment_method_details": {
|
71
|
+
"sepa_debit": {
|
72
|
+
"bank_code": "37040044",
|
73
|
+
"branch_code": null,
|
74
|
+
"country": "DE",
|
75
|
+
"fingerprint": "00000000000000",
|
76
|
+
"last4": "3001",
|
77
|
+
"mandate": "mandate_00000000000000"
|
78
|
+
},
|
79
|
+
"type": "sepa_debit"
|
80
|
+
},
|
81
|
+
"receipt_email": null,
|
82
|
+
"receipt_number": null,
|
83
|
+
"receipt_url": "https://pay.stripe.com/receipts/acct_00000000000000/py_00000000000000/rcpt_00000000000000",
|
84
|
+
"refunded": false,
|
85
|
+
"refunds": {
|
86
|
+
"object": "list",
|
87
|
+
"data": [],
|
88
|
+
"has_more": false,
|
89
|
+
"total_count": 0,
|
90
|
+
"url": "/v1/charges/py_00000000000000/refunds"
|
91
|
+
},
|
92
|
+
"review": null,
|
93
|
+
"shipping": null,
|
94
|
+
"source": null,
|
95
|
+
"source_transfer": null,
|
96
|
+
"statement_descriptor": "ACME Corp",
|
97
|
+
"statement_descriptor_suffix": null,
|
98
|
+
"status": "failed",
|
99
|
+
"transfer_data": {
|
100
|
+
"amount": null,
|
101
|
+
"destination": "acct_00000000000000"
|
102
|
+
},
|
103
|
+
"transfer_group": "group_pi_00000000000000"
|
104
|
+
}
|
105
|
+
],
|
106
|
+
"has_more": false,
|
107
|
+
"total_count": 1,
|
108
|
+
"url": "/v1/charges?payment_intent=pi_00000000000000"
|
109
|
+
},
|
110
|
+
"client_secret": "pi_00000000000000",
|
111
|
+
"confirmation_method": "automatic",
|
112
|
+
"created": 1578401129,
|
113
|
+
"currency": "eur",
|
114
|
+
"customer": "cus_00000000000000",
|
115
|
+
"description": null,
|
116
|
+
"invoice": null,
|
117
|
+
"last_payment_error": {
|
118
|
+
"code": "payment_intent_payment_attempt_failed",
|
119
|
+
"doc_url": "https://stripe.com/docs/error-codes/payment-intent-payment-attempt-failed",
|
120
|
+
"message": "The payment failed.",
|
121
|
+
"payment_method": {
|
122
|
+
"id": "pm_00000000000000",
|
123
|
+
"object": "payment_method",
|
124
|
+
"billing_details": {
|
125
|
+
"address": {
|
126
|
+
"city": null,
|
127
|
+
"country": null,
|
128
|
+
"line1": null,
|
129
|
+
"line2": null,
|
130
|
+
"postal_code": null,
|
131
|
+
"state": null
|
132
|
+
},
|
133
|
+
"email": "john.doe@example.com",
|
134
|
+
"name": "John Doe",
|
135
|
+
"phone": null
|
136
|
+
},
|
137
|
+
"created": 1578400666,
|
138
|
+
"customer": "cus_00000000000000",
|
139
|
+
"livemode": false,
|
140
|
+
"metadata": {},
|
141
|
+
"sepa_debit": {
|
142
|
+
"bank_code": "37040044",
|
143
|
+
"branch_code": "",
|
144
|
+
"country": "DE",
|
145
|
+
"fingerprint": "00000000000000",
|
146
|
+
"last4": "3001"
|
147
|
+
},
|
148
|
+
"type": "sepa_debit"
|
149
|
+
},
|
150
|
+
"type": "invalid_request_error"
|
151
|
+
},
|
152
|
+
"livemode": false,
|
153
|
+
"metadata": {},
|
154
|
+
"next_action": null,
|
155
|
+
"next_source_action": null,
|
156
|
+
"on_behalf_of": null,
|
157
|
+
"payment_method": null,
|
158
|
+
"payment_method_options": {
|
159
|
+
"card": {
|
160
|
+
"installments": null,
|
161
|
+
"request_three_d_secure": "automatic"
|
162
|
+
}
|
163
|
+
},
|
164
|
+
"payment_method_types": ["card", "sepa_debit"],
|
165
|
+
"receipt_email": null,
|
166
|
+
"review": null,
|
167
|
+
"setup_future_usage": null,
|
168
|
+
"shipping": null,
|
169
|
+
"source": null,
|
170
|
+
"statement_descriptor": "ACME Corp",
|
171
|
+
"statement_descriptor_suffix": null,
|
172
|
+
"status": "requires_source",
|
173
|
+
"transfer_data": {
|
174
|
+
"destination": "acct_00000000000000"
|
175
|
+
},
|
176
|
+
"transfer_group": null
|
177
|
+
}
|
178
|
+
},
|
179
|
+
"livemode": false,
|
180
|
+
"pending_webhooks": 3,
|
181
|
+
"request": {
|
182
|
+
"id": null,
|
183
|
+
"idempotency_key": null
|
184
|
+
},
|
185
|
+
"type": "payment_intent.payment_failed"
|
186
|
+
}
|