@spree/docs 0.1.0

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.
Files changed (183) hide show
  1. package/README.md +54 -0
  2. package/dist/api-reference/platform/authentication.md +38 -0
  3. package/dist/api-reference/store-api/authentication.md +188 -0
  4. package/dist/api-reference/store-api/errors.md +277 -0
  5. package/dist/api-reference/store-api/idempotency.md +129 -0
  6. package/dist/api-reference/store-api/introduction.md +34 -0
  7. package/dist/api-reference/store-api/localization.md +279 -0
  8. package/dist/api-reference/store-api/metadata.md +160 -0
  9. package/dist/api-reference/store-api/monetary-amounts.md +65 -0
  10. package/dist/api-reference/store-api/querying.md +399 -0
  11. package/dist/api-reference/store-api/rate-limitting.md +103 -0
  12. package/dist/api-reference/store-api/relations.md +185 -0
  13. package/dist/api-reference/storefront/authentication.md +88 -0
  14. package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
  15. package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
  16. package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
  17. package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
  18. package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
  19. package/dist/api-reference/v2/introduction.md +22 -0
  20. package/dist/api-reference/v2/pagination.md +37 -0
  21. package/dist/api-reference/webhooks-events.md +883 -0
  22. package/dist/developer/admin/admin.md +205 -0
  23. package/dist/developer/admin/authentication.md +59 -0
  24. package/dist/developer/admin/components.md +711 -0
  25. package/dist/developer/admin/custom-css.md +243 -0
  26. package/dist/developer/admin/custom-javascript.md +116 -0
  27. package/dist/developer/admin/extending-ui.md +1964 -0
  28. package/dist/developer/admin/form-builder.md +444 -0
  29. package/dist/developer/admin/helper-methods.md +531 -0
  30. package/dist/developer/admin/navigation.md +805 -0
  31. package/dist/developer/admin/tables.md +491 -0
  32. package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
  33. package/dist/developer/cli/quickstart.md +137 -0
  34. package/dist/developer/contributing/creating-an-extension.md +258 -0
  35. package/dist/developer/contributing/developing-spree.md +339 -0
  36. package/dist/developer/contributing/quickstart.md +32 -0
  37. package/dist/developer/contributing/updating-extensions.md +67 -0
  38. package/dist/developer/core-concepts/addresses.md +265 -0
  39. package/dist/developer/core-concepts/adjustments.md +107 -0
  40. package/dist/developer/core-concepts/architecture.md +177 -0
  41. package/dist/developer/core-concepts/calculators.md +323 -0
  42. package/dist/developer/core-concepts/customers.md +230 -0
  43. package/dist/developer/core-concepts/events.md +624 -0
  44. package/dist/developer/core-concepts/imports-exports.md +698 -0
  45. package/dist/developer/core-concepts/inventory.md +191 -0
  46. package/dist/developer/core-concepts/markets.md +250 -0
  47. package/dist/developer/core-concepts/media.md +167 -0
  48. package/dist/developer/core-concepts/metafields.md +187 -0
  49. package/dist/developer/core-concepts/orders.md +328 -0
  50. package/dist/developer/core-concepts/payments.md +710 -0
  51. package/dist/developer/core-concepts/pricing.md +163 -0
  52. package/dist/developer/core-concepts/products.md +360 -0
  53. package/dist/developer/core-concepts/promotions.md +322 -0
  54. package/dist/developer/core-concepts/reports.md +206 -0
  55. package/dist/developer/core-concepts/search-filtering.md +237 -0
  56. package/dist/developer/core-concepts/shipments.md +212 -0
  57. package/dist/developer/core-concepts/slugs.md +111 -0
  58. package/dist/developer/core-concepts/staff-roles.md +123 -0
  59. package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
  60. package/dist/developer/core-concepts/stores.md +117 -0
  61. package/dist/developer/core-concepts/taxes.md +135 -0
  62. package/dist/developer/core-concepts/translations.md +120 -0
  63. package/dist/developer/core-concepts/users.md +299 -0
  64. package/dist/developer/core-concepts/webhooks.md +378 -0
  65. package/dist/developer/create-spree-app/quickstart.md +158 -0
  66. package/dist/developer/customization/api.md +93 -0
  67. package/dist/developer/customization/authentication.md +88 -0
  68. package/dist/developer/customization/checkout.md +204 -0
  69. package/dist/developer/customization/configuration.md +55 -0
  70. package/dist/developer/customization/decorators.md +523 -0
  71. package/dist/developer/customization/dependencies.md +232 -0
  72. package/dist/developer/customization/emails.md +21 -0
  73. package/dist/developer/customization/extensions.md +92 -0
  74. package/dist/developer/customization/metadata.md +236 -0
  75. package/dist/developer/customization/model-preferences.md +130 -0
  76. package/dist/developer/customization/permissions.md +265 -0
  77. package/dist/developer/customization/quickstart.md +229 -0
  78. package/dist/developer/customization/routes.md +24 -0
  79. package/dist/developer/customization/v4/admin-panel.md +78 -0
  80. package/dist/developer/customization/v4/authentication.md +210 -0
  81. package/dist/developer/customization/v4/checkout.md +212 -0
  82. package/dist/developer/customization/v4/deface.md +251 -0
  83. package/dist/developer/customization/v4/images.md +86 -0
  84. package/dist/developer/customization/v4/storefront.md +450 -0
  85. package/dist/developer/deployment/assets.md +87 -0
  86. package/dist/developer/deployment/aws.md +335 -0
  87. package/dist/developer/deployment/caching.md +27 -0
  88. package/dist/developer/deployment/cdn.md +39 -0
  89. package/dist/developer/deployment/database.md +155 -0
  90. package/dist/developer/deployment/docker.md +128 -0
  91. package/dist/developer/deployment/emails.md +77 -0
  92. package/dist/developer/deployment/environment_variables.md +111 -0
  93. package/dist/developer/deployment/heroku.md +51 -0
  94. package/dist/developer/deployment/render.md +95 -0
  95. package/dist/developer/getting-started/quickstart.md +82 -0
  96. package/dist/developer/how-to/custom-payment-method.md +374 -0
  97. package/dist/developer/how-to/custom-promotion.md +373 -0
  98. package/dist/developer/how-to/custom-report.md +387 -0
  99. package/dist/developer/how-to/custom-search-provider.md +230 -0
  100. package/dist/developer/multi-store/quickstart.md +71 -0
  101. package/dist/developer/multi-store/setup.md +38 -0
  102. package/dist/developer/multi-tenant/configuration.md +41 -0
  103. package/dist/developer/multi-tenant/core-concepts.md +75 -0
  104. package/dist/developer/multi-tenant/installation.md +96 -0
  105. package/dist/developer/multi-tenant/quickstart.md +20 -0
  106. package/dist/developer/multi-vendor/installation.md +45 -0
  107. package/dist/developer/multi-vendor/quickstart.md +17 -0
  108. package/dist/developer/sdk/admin/quickstart.md +22 -0
  109. package/dist/developer/sdk/authentication.md +89 -0
  110. package/dist/developer/sdk/configuration.md +225 -0
  111. package/dist/developer/sdk/quickstart.md +82 -0
  112. package/dist/developer/sdk/store/account.md +67 -0
  113. package/dist/developer/sdk/store/cart-checkout.md +140 -0
  114. package/dist/developer/sdk/store/markets.md +151 -0
  115. package/dist/developer/sdk/store/payments.md +96 -0
  116. package/dist/developer/sdk/store/products.md +149 -0
  117. package/dist/developer/sdk/store/wishlists.md +52 -0
  118. package/dist/developer/security/pci_compliance.md +15 -0
  119. package/dist/developer/security/security_policy.md +68 -0
  120. package/dist/developer/storefront/blocks.md +285 -0
  121. package/dist/developer/storefront/custom-css.md +260 -0
  122. package/dist/developer/storefront/custom-javascript.md +166 -0
  123. package/dist/developer/storefront/helper-methods.md +1288 -0
  124. package/dist/developer/storefront/links.md +298 -0
  125. package/dist/developer/storefront/nextjs/architecture.md +150 -0
  126. package/dist/developer/storefront/nextjs/customization.md +141 -0
  127. package/dist/developer/storefront/nextjs/deployment.md +180 -0
  128. package/dist/developer/storefront/nextjs/quickstart.md +92 -0
  129. package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
  130. package/dist/developer/storefront/pages.md +163 -0
  131. package/dist/developer/storefront/sections.md +569 -0
  132. package/dist/developer/storefront/storefront.md +56 -0
  133. package/dist/developer/storefront/themes.md +161 -0
  134. package/dist/developer/tutorial/admin.md +134 -0
  135. package/dist/developer/tutorial/extending-models.md +380 -0
  136. package/dist/developer/tutorial/file-uploads.md +121 -0
  137. package/dist/developer/tutorial/introduction.md +33 -0
  138. package/dist/developer/tutorial/model.md +41 -0
  139. package/dist/developer/tutorial/page-builder.md +487 -0
  140. package/dist/developer/tutorial/rich-text.md +73 -0
  141. package/dist/developer/tutorial/seo.md +332 -0
  142. package/dist/developer/tutorial/storefront.md +352 -0
  143. package/dist/developer/tutorial/testing.md +558 -0
  144. package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
  145. package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
  146. package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
  147. package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
  148. package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
  149. package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
  150. package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
  151. package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
  152. package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
  153. package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
  154. package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
  155. package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
  156. package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
  157. package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
  158. package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
  159. package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
  160. package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
  161. package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
  162. package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
  163. package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
  164. package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
  165. package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
  166. package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
  167. package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
  168. package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
  169. package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
  170. package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
  171. package/dist/developer/upgrades/quickstart.md +36 -0
  172. package/dist/integrations/analytics/google-analytics.md +64 -0
  173. package/dist/integrations/analytics/google-tag-manager.md +78 -0
  174. package/dist/integrations/integrations.md +39 -0
  175. package/dist/integrations/marketing/klaviyo.md +99 -0
  176. package/dist/integrations/payments/adyen.md +90 -0
  177. package/dist/integrations/payments/paypal.md +41 -0
  178. package/dist/integrations/payments/razorpay.md +45 -0
  179. package/dist/integrations/payments/stripe.md +109 -0
  180. package/dist/integrations/search/meilisearch.md +236 -0
  181. package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
  182. package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
  183. package/package.json +27 -0
@@ -0,0 +1,374 @@
1
+ ---
2
+ title: Build a Custom Payment Method
3
+ description: Step-by-step guide to creating a custom payment gateway integration with Payment Sessions, 3D Secure, and PCI compliance.
4
+ ---
5
+
6
+ ## Overview
7
+
8
+ This guide walks you through building a custom payment method integration for Spree. By the end, you'll have a fully functional payment gateway that:
9
+
10
+ - Appears as a payment option during checkout
11
+ - Uses Payment Sessions for PCI-compliant payment collection
12
+ - Supports 3D Secure and alternative payment methods
13
+ - Handles webhooks for reliable payment confirmation
14
+ - Optionally supports saving payment methods for future use (Payment Setup Sessions)
15
+
16
+ Before starting, make sure you understand [how payments work in Spree](/developer/core-concepts/payments).
17
+
18
+ ## Step 1: Create the Payment Method Model
19
+
20
+ Create a new model inheriting from `Spree::PaymentMethod`. This is the central class that defines how your gateway processes payments.
21
+
22
+ ```ruby app/models/my_gateway.rb
23
+ class MyGateway < Spree::PaymentMethod
24
+ preference :api_key, :string
25
+ preference :publishable_key, :string
26
+ preference :webhook_secret, :string
27
+
28
+ def payment_icon_name
29
+ 'my-gateway'
30
+ end
31
+ end
32
+ ```
33
+
34
+ ## Step 2: Register the Payment Method
35
+
36
+ Add your gateway to the list of available payment methods so it appears in the admin panel:
37
+
38
+ ```ruby config/initializers/spree.rb
39
+ Rails.application.config.after_initialize do
40
+ Spree.payment_methods << MyGateway
41
+ end
42
+ ```
43
+
44
+ After restarting your server, you can select "MyGateway" when creating a new payment method in the admin panel under **Settings > Payments**.
45
+
46
+ ## Step 3: Add Payment Session Support
47
+
48
+ Payment Sessions are the modern, PCI-compliant way to handle payments. Your gateway creates a session with the provider, the frontend collects payment details using the provider's SDK, and Spree records the result.
49
+
50
+ ### Define the STI Subclass
51
+
52
+ Create a Payment Session subclass for your gateway. This uses Single Table Inheritance (STI) on the `spree_payment_sessions` table:
53
+
54
+ ```ruby app/models/spree/payment_sessions/my_gateway.rb
55
+ module Spree
56
+ module PaymentSessions
57
+ class MyGateway < Spree::PaymentSession
58
+ # Add gateway-specific helper methods here
59
+
60
+ def client_secret
61
+ external_data['client_secret']
62
+ end
63
+ end
64
+ end
65
+ end
66
+ ```
67
+
68
+ ### Implement Session Methods on the Gateway
69
+
70
+ Override the key methods on your `PaymentMethod` subclass:
71
+
72
+ ```ruby app/models/my_gateway.rb
73
+ class MyGateway < Spree::PaymentMethod
74
+ preference :api_key, :string
75
+ preference :publishable_key, :string
76
+ preference :webhook_secret, :string
77
+
78
+ # Tell Spree this gateway uses Payment Sessions
79
+ def session_required?
80
+ true
81
+ end
82
+
83
+ # Return the STI subclass
84
+ def payment_session_class
85
+ Spree::PaymentSessions::MyGateway
86
+ end
87
+
88
+ # No source required upfront — it's created when the session completes
89
+ def source_required?
90
+ false
91
+ end
92
+
93
+ # Create a session with your payment provider
94
+ def create_payment_session(order:, amount: nil, external_data: {})
95
+ total = amount || order.total_minus_store_credits
96
+
97
+ # Call your provider's API to create a payment session
98
+ provider_session = MyProvider::Client.new(preferred_api_key).create_session(
99
+ amount: (total * 100).to_i, # amount in cents
100
+ currency: order.currency,
101
+ metadata: { order_number: order.number }
102
+ )
103
+
104
+ payment_sessions.create!(
105
+ order: order,
106
+ amount: total,
107
+ currency: order.currency,
108
+ external_id: provider_session.id,
109
+ external_data: {
110
+ client_secret: provider_session.client_secret
111
+ },
112
+ customer: order.user
113
+ )
114
+ end
115
+
116
+ # Update an existing session (e.g., when order total changes)
117
+ def update_payment_session(payment_session:, amount: nil, external_data: {})
118
+ if amount.present?
119
+ MyProvider::Client.new(preferred_api_key).update_session(
120
+ payment_session.external_id,
121
+ amount: (amount * 100).to_i
122
+ )
123
+ payment_session.update!(amount: amount)
124
+ end
125
+
126
+ payment_session
127
+ end
128
+
129
+ # Complete the session after the customer pays on the frontend.
130
+ #
131
+ # Responsibilities:
132
+ # - Verify payment status with the provider
133
+ # - Create the Spree::Payment record
134
+ # - Transition the payment to the correct state
135
+ # - Mark the session as completed/failed
136
+ #
137
+ # Must NOT complete the order — that is handled by Carts::Complete
138
+ # (called by the frontend or by the webhook handler).
139
+ def complete_payment_session(payment_session:, params: {})
140
+ # Verify the payment with your provider
141
+ result = MyProvider::Client.new(preferred_api_key).retrieve_session(
142
+ payment_session.external_id
143
+ )
144
+
145
+ if result.status == 'succeeded'
146
+ payment_session.process!
147
+
148
+ # Create the Spree::Payment record
149
+ payment = payment_session.find_or_create_payment!
150
+
151
+ # Transition the payment to completed
152
+ if payment.present? && !payment.completed?
153
+ payment.started_processing! if payment.checkout?
154
+ payment.complete! if payment.can_complete?
155
+ end
156
+
157
+ payment_session.complete!
158
+ else
159
+ payment_session.fail!
160
+ end
161
+ end
162
+
163
+ def payment_icon_name
164
+ 'my-gateway'
165
+ end
166
+ end
167
+ ```
168
+
169
+ ### How the Frontend Uses It
170
+
171
+ The frontend creates a session, then uses the provider's SDK to collect payment:
172
+
173
+ ```typescript
174
+ // 1. Get available payment methods
175
+ const methods = await client.carts.paymentMethods.list(cart.id, options)
176
+
177
+ // 2. Find your gateway (check session_required flag)
178
+ const myGateway = methods.find(m => m.session_required)
179
+
180
+ // 3. Create a payment session (after shipping is selected so amount is correct)
181
+ const session = await client.carts.paymentSessions.create(cart.id, {
182
+ payment_method_id: myGateway.id,
183
+ }, options)
184
+
185
+ // 4. Use the client_secret with your provider's frontend SDK
186
+ const result = await MyProviderSDK.confirmPayment(session.external_data.client_secret)
187
+
188
+ // 5. Complete the payment session (creates Payment record, does NOT complete order)
189
+ const completed = await client.carts.paymentSessions.complete(
190
+ cart.id, session.id,
191
+ { session_result: result.id },
192
+ options
193
+ )
194
+
195
+ // 6. Complete the order
196
+ const order = await client.carts.complete(cart.id, options)
197
+ ```
198
+
199
+ > **INFO:** **Important:** Always create the payment session **after** shipping is selected. If the order total changes (shipping rate change, coupon applied), create a new payment session with the updated amount. The `complete` call in step 5 only handles payment — step 6 finalizes the order.
200
+
201
+ ## Step 4: Handle Webhooks (Recommended)
202
+
203
+ Webhooks ensure payments are captured even if the customer closes their browser after paying. Spree provides a generic webhook endpoint at `POST /api/v3/webhooks/payments/:payment_method_id` — you don't need to create your own controller or routes.
204
+
205
+ Your gateway just needs to implement `parse_webhook_event` to normalize the provider-specific payload:
206
+
207
+ ```ruby app/models/my_gateway.rb
208
+ class MyGateway < Spree::PaymentMethod
209
+ # ... existing code ...
210
+
211
+ # Parse incoming webhook from your payment provider.
212
+ #
213
+ # @param raw_body [String] the raw request body
214
+ # @param headers [Hash] the request headers
215
+ # @return [Hash, nil] normalized result, or nil for unsupported events
216
+ # @raise [Spree::PaymentMethod::WebhookSignatureError] if signature is invalid
217
+ def parse_webhook_event(raw_body, headers)
218
+ # 1. Verify the webhook signature
219
+ signature = headers['HTTP_X_SIGNATURE']
220
+ unless MyProvider::Webhook.verify(raw_body, signature, preferred_webhook_secret)
221
+ raise Spree::PaymentMethod::WebhookSignatureError
222
+ end
223
+
224
+ # 2. Parse the payload
225
+ event = JSON.parse(raw_body)
226
+
227
+ # 3. Return a normalized result
228
+ case event['type']
229
+ when 'payment.succeeded'
230
+ session = Spree::PaymentSession.find_by(external_id: event.dig('data', 'session_id'))
231
+ return nil unless session
232
+
233
+ { action: :captured, payment_session: session }
234
+ when 'payment.failed'
235
+ session = Spree::PaymentSession.find_by(external_id: event.dig('data', 'session_id'))
236
+ return nil unless session
237
+
238
+ { action: :failed, payment_session: session }
239
+ else
240
+ nil # Unsupported event — Spree will return 200 OK and ignore it
241
+ end
242
+ end
243
+ end
244
+ ```
245
+
246
+ **That's it.** Spree handles the rest:
247
+ - Verifies the signature synchronously (returns `401` if `WebhookSignatureError` is raised)
248
+ - Enqueues a background job (`Spree::Payments::HandleWebhookJob`) for async processing
249
+ - Returns `200 OK` immediately to prevent provider retries
250
+ - The job creates/updates the `Payment` record, marks the session completed, and completes the order
251
+
252
+ The webhook URL for your payment method is available via `payment_method.webhook_url` — register this with your provider during setup.
253
+
254
+ ### Supported Webhook Actions
255
+
256
+ | Action | Description |
257
+ |--------|-------------|
258
+ | `:captured` | Payment was captured (charged). Creates payment and completes order. |
259
+ | `:authorized` | Payment was authorized (not yet captured). Creates payment and completes order. |
260
+ | `:failed` | Payment failed. Marks the session as failed. |
261
+ | `:canceled` | Payment was canceled. Marks the session as canceled. |
262
+
263
+ ## Step 5: Control Payment Method Visibility (Optional)
264
+
265
+ Override visibility methods to control where and when your payment method appears:
266
+
267
+ ```ruby app/models/my_gateway.rb
268
+ class MyGateway < Spree::PaymentMethod
269
+ # Only show for stores that support specific currencies
270
+ def available_for_store?(store)
271
+ store.supported_currencies.include?('EUR')
272
+ end
273
+
274
+ # Only show for orders above a certain amount
275
+ def available_for_order?(order)
276
+ order.total > 10 && order.currency == 'EUR'
277
+ end
278
+ end
279
+ ```
280
+
281
+ ## Step 6: Add Payment Setup Session Support (Optional)
282
+
283
+ If your provider supports saving payment methods for future use (like Stripe's SetupIntent), you can add Payment Setup Session support:
284
+
285
+ ```ruby app/models/my_gateway.rb
286
+ class MyGateway < Spree::PaymentMethod
287
+ # ... existing code ...
288
+
289
+ def setup_session_supported?
290
+ true
291
+ end
292
+
293
+ def payment_setup_session_class
294
+ Spree::PaymentSetupSessions::MyGateway
295
+ end
296
+
297
+ def create_payment_setup_session(customer:, external_data: {})
298
+ provider_setup = MyProvider::Client.new(preferred_api_key).create_setup_session(
299
+ customer_id: find_or_create_provider_customer(customer)
300
+ )
301
+
302
+ payment_setup_sessions.create!(
303
+ customer: customer,
304
+ external_id: provider_setup.id,
305
+ external_client_secret: provider_setup.client_secret
306
+ )
307
+ end
308
+
309
+ def complete_payment_setup_session(setup_session:, params: {})
310
+ result = MyProvider::Client.new(preferred_api_key).retrieve_setup_session(
311
+ setup_session.external_id
312
+ )
313
+
314
+ if result.status == 'succeeded'
315
+ # Create a saved payment source
316
+ credit_card = Spree::CreditCard.create!(
317
+ payment_method: self,
318
+ user: setup_session.customer,
319
+ gateway_payment_profile_id: result.payment_method_id,
320
+ cc_type: result.card_brand,
321
+ last_digits: result.card_last4,
322
+ month: result.card_exp_month,
323
+ year: result.card_exp_year,
324
+ name: result.cardholder_name
325
+ )
326
+
327
+ setup_session.update!(
328
+ payment_source: credit_card
329
+ )
330
+ setup_session.complete!
331
+ else
332
+ setup_session.fail!
333
+ end
334
+
335
+ setup_session
336
+ end
337
+ end
338
+ ```
339
+
340
+ And the STI subclass:
341
+
342
+ ```ruby app/models/spree/payment_setup_sessions/my_gateway.rb
343
+ module Spree
344
+ module PaymentSetupSessions
345
+ class MyGateway < Spree::PaymentSetupSession
346
+ end
347
+ end
348
+ end
349
+ ```
350
+
351
+ ## Gateway Options Reference
352
+
353
+ For every gateway action (authorize, purchase, capture, void, credit), Spree passes a hash of gateway options:
354
+
355
+ | Option | Description |
356
+ |--------------------|-----------------------------------------------------------------------------------------------|
357
+ | `email` and `customer` | The email address related to the order |
358
+ | `ip` | The last IP address for the order |
359
+ | `order_id` | The Order's `number` attribute, plus the `identifier` for each payment |
360
+ | `shipping` | The total shipping cost for the order, in cents |
361
+ | `tax` | The total tax cost for the order, in cents |
362
+ | `subtotal` | The item total for the order, in cents |
363
+ | `currency` | The 3-character currency code for the order |
364
+ | `discount` | The promotional discount applied to the order |
365
+ | `billing_address` | A hash containing billing address information |
366
+ | `shipping_address` | A hash containing shipping address information |
367
+
368
+ ## Related Documentation
369
+
370
+ - [Payments](/developer/core-concepts/payments) - Payment architecture and core concepts
371
+ - [Checkout Customization](/developer/customization/checkout) - Customizing the checkout flow
372
+ - [Events](/developer/core-concepts/events) - Subscribe to payment events
373
+ - [Stripe Integration](/integrations/payments/stripe) - Reference implementation using Stripe
374
+ - [Adyen Integration](/integrations/payments/adyen) - Reference implementation using Adyen