@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,88 @@
1
+ ---
2
+ title: Authentication
3
+ description: Learn how to authenticate requests to the Storefront API.
4
+ ---
5
+
6
+ Storefront API requires authorization only for certain actions associated with user account (e.g. updating saved addresses) or manipulating cart and checkout.
7
+
8
+ ## For guest users
9
+
10
+ ### Using X-Spree-Order-Token header
11
+
12
+ [Cart](/api-reference/storefront/cart) and [Checkout](/api-reference/storefront/checkout) endpoints paths also allow interactions without the bearer token to allow creating and managing guest checkouts.
13
+
14
+ When you first create a cart via:
15
+
16
+ ```bash
17
+ curl --request POST \
18
+ --url 'https://demo.spreecommerce.org/api/v2/storefront/cart?fields%5Bcart%5D=number%2Ctoken' \
19
+ --header 'Content-Type: application/vnd.api+json'
20
+ ```
21
+
22
+ You'll receive a response containing an empty cart. This response also contains a `data.token` attribute.
23
+
24
+ ```json
25
+ {
26
+ "data": {
27
+ "id": "114",
28
+ "type": "cart",
29
+ "attributes": {
30
+ "number": "R522550303",
31
+ "token": "NswjLVjZOw4OpEm1yWqlJg1713367317414"
32
+ },
33
+ "relationships": {}
34
+ }
35
+ }
36
+ ```
37
+
38
+ You can store this token in the frontend session (eg. Session Storage or a cookie) and pass it in a `X-Spree-Order-Token: {token}` header.
39
+
40
+ ## For signed in users
41
+
42
+ For users who have an account in your store, you will need to generate oAuth tokens to authenticate requests to endpoints such as [Account](/api-reference/storefront/account), [Cart](/api-reference/storefront/cart) and [Checkout](/api-reference/storefront/checkout).
43
+
44
+ ### Generating OAuth token
45
+
46
+ To obtain a token, execute the following curl command:
47
+
48
+ ```bash
49
+ curl -X POST http://localhost:3000/spree_oauth/token \
50
+ --header "Content-Type: application/x-www-form-urlencoded" \
51
+ --data "grant_type=password&username=spree@example.com&password=spree123"
52
+ ```
53
+
54
+ You should receive a JSON response with a `access_token` and a `refresh_token`, eg.
55
+
56
+ ```json
57
+ {
58
+ "access_token": "CmVXoDp6f5Y51s2xFAAdSbdT5wcGZIuGKKr27zAkBvQ",
59
+ "token_type": "Bearer",
60
+ "expires_in": 7200,
61
+ "refresh_token": "g5xPzY51_QYyok-ZcH9f4_btBkT_RZ6pB7ugGRaMjQQ",
62
+ "created_at": 1713367848
63
+ }
64
+ ```
65
+
66
+ ### Refreshing OAuth token
67
+
68
+ OAuth tokens obtained via the previous step are valid only for a specific time (defined in `expires_in` attribute).
69
+
70
+ After that period, you can refresh the token by executing the following curl command:
71
+
72
+ ```bash
73
+ curl -X POST http://localhost:3000/spree_oauth/token \
74
+ --header "Content-Type: application/x-www-form-urlencoded" \
75
+ --data "grant_type=refresh_token&refresh_token=g5xPzY51_QYyok-ZcH9f4_btBkT_RZ6pB7ugGRaMjQQ"
76
+ ```
77
+
78
+ On a success, you'll receive a new bearer token to use when accessing the API, eg.
79
+
80
+ ```json
81
+ {
82
+ "access_token": "JVMcaoCkxV4o2xofhAwf7ReeFEWUM94ZnVSKRITd3TQ",
83
+ "token_type": "Bearer",
84
+ "expires_in": 7200,
85
+ "refresh_token": "nMlyfxfA9U6xfSDnFhoZQzL4IOkDc-EkW1y66ZTf5Oc",
86
+ "created_at": 1713367950
87
+ }
88
+ ```
@@ -0,0 +1,165 @@
1
+ ---
2
+ title: Adyen Integration Guide for Android
3
+ description: This guide provides step-by-step instructions for integrating Adyen Android Drop-in with spree_adyen using session flow and Drop-In component.
4
+ ---
5
+
6
+ > **WARNING:** This guide is aimed at advanced users who want to create adyen integration for their custom android application.
7
+ > You also need to install Spree Adyen extension before.
8
+
9
+ ## Note
10
+
11
+ The list of available library versions can be found on [Official Adyen Documentation for Android integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=Android&integration=Drop-in&version=5.13.1)
12
+ Current newest version available at the moment of writing the tutorial is 5.13.1.
13
+ This doc will be referring to the library version as YOUR_VERSION.
14
+
15
+ ## Resources
16
+
17
+ - [Official Adyen Documentation for Android integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=Android&integration=Drop-in&version=5.13.1)
18
+ - Spree Adyen API docs - [create payment_session](/api-reference/storefront/adyen/create-an-adyen-payment-session) and [get payment_session](/api-reference/storefront/adyen/get-adyen-payment-session)
19
+ - [Official Adyen example for Android integration](https://github.com/adyen-examples/adyen-android-online-payments)
20
+
21
+ ## Overview
22
+
23
+ The integration consists of two main components:
24
+
25
+ - **Spree Adyen**: Provides API for your client and receive payment result from Adyen
26
+ - **Your Android client app**: Shows the Drop-in UI and handles payment flow
27
+
28
+ ## Step 1: Import the library
29
+
30
+ Import the compatibility module:
31
+
32
+ ### Import the module with Jet Compose
33
+
34
+ ```bash
35
+ implementation "com.adyen.checkout:drop-in-compose:YOUR_VERSION"
36
+ ```
37
+
38
+ ### Import without Jet Compose
39
+
40
+ ```bash
41
+ implementation "com.adyen.checkout:drop-in:YOUR_VERSION"
42
+ ```
43
+
44
+ ## Step 2: Create a checkout session
45
+
46
+ Create session using [this endpoint](/api-reference/storefront/adyen/create-an-adyen-payment-session).
47
+
48
+ ```kotlin
49
+ val sessionModel = SessionModel.SERIALIZER.deserialize(sessionsResponseJSON)
50
+ ```
51
+
52
+ sessionsResponseJSON should contain:
53
+ - `sessionData` - available as `adyen_data` in payment_session API response
54
+ - `id` - available as `adyen_id` in payment_session API response
55
+
56
+ ```kotlin
57
+ val sessionModel = SessionModel.SERIALIZER.deserialize(sessionsResponseJSON)
58
+ ```
59
+
60
+ ## Step 3
61
+
62
+ call `CheckoutSessionProvider.createSession` passing serialized session data (`sessionModel`) and `dropInConfiguration`
63
+
64
+ dropInConfiguration example:
65
+
66
+ ```kotlin
67
+ val checkoutConfiguration = CheckoutConfiguration(
68
+ environment = environment,
69
+ clientKey = clientKey,
70
+ shopperLocale = shopperLocale, // Optional
71
+ ) {
72
+ // Optional: add Drop-in configuration.
73
+ dropIn {
74
+ setEnableRemovingStoredPaymentMethods(true)
75
+ }
76
+
77
+ // Optional: add or change default configuration for the card payment method.
78
+ card {
79
+ setHolderNameRequired(true)
80
+ setShopperReference("...")
81
+ }
82
+
83
+ // Optional: change configuration for 3D Secure 2.
84
+ adyen3DS2 {
85
+ setThreeDSRequestorAppURL("...")
86
+ }
87
+ }
88
+ ```
89
+ see also: https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=Web&integration=Drop-in&version=6.18.1#create-instance
90
+
91
+
92
+ `environment` - enum: `live` or `test`
93
+ `clientKey` - `client_key` from payment_sessions endpoint
94
+ `shopperLocale` - shopper locale in ISO format
95
+
96
+
97
+ ```kotlin
98
+ // Create an object for the checkout session.
99
+ val result = CheckoutSessionProvider.createSession(sessionModel, dropInConfiguration)
100
+
101
+ // If the payment session is successful, handle the result.
102
+ // If the payment session encounters an error, handle the error.
103
+ when (result) {
104
+ is CheckoutSessionResult.Success -> handleCheckoutSession(result.checkoutSession)
105
+ is CheckoutSessionResult.Error -> handleError(result.exception)
106
+ }
107
+ ```
108
+
109
+ ## Step 4: Launch and show Drop-in
110
+
111
+ ```kotlin
112
+ override fun onDropInResult(sessionDropInResult: SessionDropInResult?) {
113
+ when (sessionDropInResult) {
114
+ // The payment finishes with a result.
115
+ is SessionDropInResult.Finished -> handleResult(sessionDropInResult.result)
116
+ // The shopper dismisses Drop-in.
117
+ is SessionDropInResult.CancelledByUser ->
118
+ // Drop-in encounters an error.
119
+ is SessionDropInResult.Error -> handleError(sessionDropInResult.reason)
120
+ // Drop-in encounters an unexpected state.
121
+ null ->
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## Step 5: Create the Drop-in launcher
127
+
128
+ DropIn.startPayment, passing:
129
+
130
+ - `dropInLauncher` - The Drop-in launcher object
131
+ - `checkoutSession` - result of `CheckoutSessionProvider.createSession`
132
+ - `dropInConfiguration` - Your Drop-in configuration
133
+
134
+ Example:
135
+
136
+ ```kotlin
137
+ import com.adyen.checkout.dropin.compose.startPayment
138
+ import com.adyen.checkout.dropin.compose.rememberLauncherForDropInResult
139
+
140
+ @Composable
141
+ private fun ComposableDropIn() {
142
+ val dropInLauncher = rememberLauncherForDropInResult(sessionDropInCallback)
143
+
144
+ DropIn.startPayment(dropInLauncher, checkoutSession, dropInConfiguration)
145
+ }
146
+ ```
147
+
148
+ ## Get payment outcome
149
+
150
+ 1. Wait for backend to process the payment
151
+ 2. Continue shopping experience
152
+
153
+ ### 1. Wait for backend to process the payment
154
+
155
+ backend will change the state of `payment_session` to one of the following state
156
+
157
+ - `pending` - chosen payment method can take a while to complete
158
+ - `completed` - payment resulted in success, order completed
159
+ - `canceled` - payment canceled, payment is `void`
160
+ - `refused` - payment failed
161
+
162
+ ### 2. Continue shopping experience
163
+
164
+ if succeed - order is processed and completed
165
+ if failed - payment can be retried using new payment session
@@ -0,0 +1,194 @@
1
+ ---
2
+ title: Adyen Integration Guide for iOS
3
+ description: This guide provides step-by-step instructions for integrating Adyen iOS Drop-in with spree_adyen using session flow and Drop-In component.
4
+ ---
5
+
6
+ > **WARNING:** This guide is aimed at advanced users who want to create adyen integration for their custom iOS application.
7
+ > You also need to install Spree Adyen extension before.
8
+
9
+ ## Requirements
10
+
11
+ - Adyen test account
12
+ - Set up `spree_adyen` spree extension
13
+
14
+ ### return_url
15
+
16
+ spree_adyen needs to be configured with `return_url`.
17
+
18
+ Return url tells where shopper should be redirect after the payment from outside your application (for example klarna or most of others buy now pay later systems).
19
+
20
+ Use the custom URL for your app, like `my-app://adyen`. Url can contain custom query params however do not include any personally identifiable information (PII) of your customer. Maximum length of the url is 1024 characters.
21
+
22
+ ## Note
23
+
24
+ The list of available library versions can be found on [Official Adyen Documentation for iOS integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=iOS&integration=Drop-in&version=5.13.1)
25
+ Current newest version available at the moment of writing the tutorial is 5.19.2.
26
+
27
+ ## Resources
28
+
29
+ - [Official Adyen Documentation for iOS integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=iOS&integration=Drop-in&version=5.19.2)
30
+ - Spree Adyen API docs - [create payment_session](/api-reference/storefront/adyen/create-an-adyen-payment-session) and [get payment_session](/api-reference/storefront/adyen/get-adyen-payment-session)
31
+ - [Official Adyen example for iOS integration](https://github.com/Adyen/adyen-ios/tree/develop/Demo)
32
+ - Apple Developer documentation on [defining custom url scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app)
33
+
34
+ ## Overview
35
+
36
+ The integration consists of two main components:
37
+
38
+ - **Spree Adyen**: Provides API for your client and receive payment result from Adyen
39
+ - **Your iOS client app**: Shows the Drop-in UI and handles payment flow
40
+
41
+ ## Step 1: Install adyen with Swift Package Manager
42
+
43
+ repository URL:
44
+ ```
45
+ https://github.com/Adyen/adyen-ios
46
+ ```
47
+ use at least version 5.0.0
48
+
49
+ CocoaPods and Carthage instructions are available [here](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=iOS&integration=Drop-in&version=5.19.2&tab=cocoapods_1_2#1-get-adyen-ios).
50
+
51
+ ## Step 2: Create the context
52
+
53
+ Create the instance of APIContext that includes client key and environment setting.
54
+
55
+ ```swift
56
+ // Set the client key and environment in an instance of APIContext.
57
+ let apiContext = APIContext(clientKey: clientKey, environment: Environment.test) // Set the environment to a live one when going live.
58
+ // Create the amount with the value in minor units and the currency code.
59
+ let amount = Amount(value: 1000, currencyCode: "EUR")
60
+ // Create the payment object with the amount and country code.
61
+ let payment = Payment(amount: amount, countryCode: "NL")
62
+ // Create an instance of AdyenContext, passing the instance of APIContext, and payment object.
63
+ let adyenContext = AdyenContext(apiContext: apiContext, payment:payment)
64
+ ```
65
+
66
+ `environment` - Environment.test or Environment.live
67
+ `clientKey` - `client_key` from payment_sessions endpoint
68
+
69
+ ## Step 3: Create and set up session
70
+
71
+ Create a session using [payment_session endpoint](/api-reference/storefront/adyen/create-an-adyen-payment-session).
72
+ Then set a configuration using data from the response:
73
+
74
+ ```swift
75
+ let configuration = AdyenSession.Configuration(sessionIdentifier: sessionId,
76
+ initialSessionData: data)
77
+ ```
78
+
79
+ - `data` - available as `adyen_data` in payment_session API response
80
+ - `sessionId` - available as `adyen_id` in payment_session API response
81
+
82
+ With the configuration you initialize AdyenSession:
83
+
84
+ ```swift
85
+ AdyenSession.initialize(with: configuration, delegate: self, presentationDelegate: self) { [weak self] result in
86
+ switch result {
87
+ case let .success(session):
88
+ //Store the session object.
89
+ self?.session = session
90
+ case let .failure(error):
91
+ //Handle the error.
92
+ }
93
+ }
94
+ ```
95
+
96
+ ## Step 4. Configure Drop-in
97
+
98
+ ```swift
99
+ let dropInConfiguration = DropInComponent.Configuration()
100
+ // Some payment methods have additional required or optional configuration.
101
+ // For example, an optional configuration to show the cardholder name field for cards.
102
+ dropInConfiguration.card.showsHolderNameField = true
103
+ ```
104
+
105
+ ## Step 5: Initialize the DropInComponent class
106
+
107
+ ```swift
108
+ let dropInComponent = DropInComponent(paymentMethods: session.sessionContext.paymentMethods,
109
+ context: adyenContext,
110
+ configuration: dropInConfiguration)
111
+
112
+ // Keep the instance of Drop-in to so that it doesn't get destroyed after the function is executed.
113
+ self.dropInComponent = dropInComponent
114
+
115
+ // Set the session as the delegate.
116
+ dropInComponent.delegate = session
117
+ // If you support gift cards, set the session as the partial payment delegate.
118
+ dropInComponent.partialPaymentDelegate = session
119
+ ```
120
+
121
+ ## Step 6: Show Drop-in in your app
122
+
123
+ ```swift
124
+ myCheckoutViewController.present(dropInComponent.viewController, animated: true)
125
+ ```
126
+
127
+ If the `action` field is `redirect` you need to handle the redirect result.
128
+
129
+ ## Step 7. Handling the redirect result
130
+
131
+ If the `action` field returns `redirect` the shopper is completing the payment outside of your application. You need to inform the Drop-in when the shopper returns to your app.
132
+
133
+ Here an example for a Custom Url scheme:
134
+ - implement the following in your `UIApplicationDelegate`:
135
+
136
+ ```swift
137
+ func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
138
+ return RedirectComponent.applicationDidOpen(from: url)
139
+ }
140
+ ```
141
+
142
+ for Universal URL use this instead:
143
+ ```swift
144
+ func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
145
+ guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
146
+ let incomingURL = userActivity.webpageURL else { return false }
147
+ return RedirectComponent.applicationDidOpen(from: incomingURL)
148
+ }
149
+ ```
150
+
151
+ ## Step 8: Show the shopper result of the payment
152
+
153
+ When the payment flow is finished, your instance of AdyenSession calls the didComplete method.
154
+ Implement the following in your Drop-in configuration object.
155
+
156
+ ```swift
157
+ func didComplete(with result: AdyenSessionResult, // The session result.
158
+ component: Component, // The Drop-in component.
159
+ session: AdyenSession) // Your instance of AdyenSession.
160
+ ```
161
+
162
+ Use the resultCode to inform your shopper about the current payment status.
163
+ Possible resultCode values:
164
+ - `authorised` - payment authorised
165
+ - `refused` - payment refused
166
+ - `pending` - payment pending (for payments with asynchronous flow like iDEAL). When the shopper completes the payment webhook will process process the payment.
167
+ - `cancelled` - payment canceled
168
+ - `received` - some payments needs more time to be processed. When the status is available webhook will process the payment
169
+ - `error` - an error occurred when processing the payment. The response contains more details with the error code
170
+ Your instance of AdyenSession calls the didFail method containing the error.
171
+ ```swift
172
+ func didFail(with error: Error, // The error object.
173
+ from component: Component, // The Drop-in component.
174
+ session: AdyenSession) // Your instance of AdyenSession.
175
+ ```
176
+
177
+ ## Step 8: Continue shopping experience
178
+
179
+ 1. Wait for backend to process the payment
180
+ 2. Continue shopping experience
181
+
182
+ ### 1. Wait for backend to process the payment
183
+
184
+ backend after receiving webhook will change the state of `payment_session` to one of the following state:
185
+ - `pending` - chosen payment method can take a while to complete
186
+ - `completed` - payment resulted in success, order completed
187
+ - `canceled` - payment canceled, payment is `void`
188
+ - `refused` - payment failed
189
+
190
+ ### 2. Continue shopping experience
191
+
192
+ if succeed - order is processed and completed
193
+
194
+ if failed - payment can be retried using new payment session
@@ -0,0 +1,248 @@
1
+ ---
2
+ title: Quick Checkout with Stripe and Storefront API
3
+ description: This tutorial will show you how to add quick checkout to your headless/composable storefront using Stripe and Spree APIs.
4
+ ---
5
+
6
+ > **WARNING:** This guide is aimed at advanced users who have some experience with Spree API and Stripe.
7
+ > You also need to install [Spree Stripe](https://github.com/spree/spree_stripe) extension before.
8
+
9
+ > **INFO:** If you're using the standard Spree Storefront, then you can skip this tutorial as quick checkout is already built in.
10
+
11
+ ## Prerequisites
12
+
13
+ Assume that you have a cart made with line items in it already.
14
+
15
+ Quick checkout works by handling 3 different events:
16
+ - Address change
17
+ - Shipping Method/Rate change
18
+ - Confirmation
19
+
20
+ How you should handle them depends on your platform/language:
21
+
22
+ - For Web and JS, please review:
23
+ - [Express Checkout Element](https://docs.stripe.com/elements/express-checkout-element)
24
+ - We also recommend reviewing the [spree_stripe implementation in Stimulus.js](https://github.com/spree/spree_stripe/blob/main/app/javascript/spree_stripe/controllers/stripe_button_controller.js)
25
+
26
+ - For iOS, please review:
27
+ - [StripeApplePay](https://docs.stripe.com/apple-pay)
28
+ - [STPApplePayContext](https://stripe.dev/stripe-ios/stripeapplepay/documentation/stripeapplepay/stpapplepaycontext#instance-methods)
29
+
30
+ ## Checkout Flow
31
+
32
+ ### Address change
33
+
34
+ Here we need to send some basic information about the customer's shipping address, and we should move the order to the delivery step (don't forget to replace the placeholders with the customer's data):
35
+
36
+ <details>
37
+ <summary>Update the checkout</summary>
38
+
39
+ ```bash Update order [expandable]
40
+ curl -X PATCH <SHOP URL>/api/v2/storefront/checkout \
41
+ -H 'Authorization: Bearer <Token>' \
42
+ -H 'Content-Type: application/json' \
43
+ -d '{
44
+ "order": {
45
+ "ship_address_attributes": {
46
+ "quick_checkout": true,
47
+ "firstname": <First name>,
48
+ "lastname": <Last name>,
49
+ "city": <City>,
50
+ "zipcode": <Zip>,
51
+ "country_iso": <Country>,
52
+ "state_name": <State>
53
+ },
54
+ "bill_address_id": "CLEAR"
55
+ }
56
+ }'
57
+ ```
58
+
59
+ - **`quick_checkout`** (`bool`) — `true` indicating that the order is from quick checkout. It is required as the address details you will receive from Apple Pay or Google Pay are not complete and wouldn't be valid for the standard checkout.
60
+
61
+ - **`firstname`** (`string`) — Customer's first name, e.g. John
62
+
63
+ - **`lastname`** (`string`) — Customer's last name, e.g. Doe
64
+
65
+ - **`city`** (`string`) — Customer's city, e.g. Mountain View
66
+
67
+ - **`zipcode`** (`string`) — Customer's zip code, e.g. 94043
68
+
69
+ - **`country_iso`** (`string`) — Customer's country ISO, e.g. US
70
+
71
+ - **`state_name`** (`string`) — Customer's address state, e.g. CA (empty string is also accepted)
72
+
73
+ - **`bill_address_id`** (`string`) — Set it to `CLEAR` to clear the existing billing address (this prevents the order from accidentally advancing to the `payment` step).
74
+
75
+ [Full documentation](/api-reference/storefront/checkout/update-checkout)
76
+
77
+ </details>
78
+
79
+ <details>
80
+ <summary>Move the order to the delivery step</summary>
81
+
82
+ [Endpoint documentation](/api-reference/storefront/checkout-state/advance-checkout)
83
+
84
+ ```bash Advance order to the delivery step
85
+ curl -X PATCH '<SHOP URL>/api/v2/storefront/checkout/advance?state=delivery&include=shipments.shipping_rates' \
86
+ -H 'Authorization: Bearer <Token>' \
87
+ -H 'Content-Type: application/json' \
88
+ -d '{
89
+ "quick_checkout": true,
90
+ "shipping_method_id": <Shipping Method ID>
91
+ }'
92
+ ```
93
+
94
+ - **`quick_checkout`** (`bool`) — `true` indicating that the order is from quick checkout
95
+
96
+ - **`shipping_method_id`** (`string`) — You don't have to send `shipping_method_id` if you don't have it yet, but if you received `Shipping Method/Rate changed` event, and you already have the selected shipping method, then you can send it.
97
+
98
+ This will return you an order response, and you can update the payment element with a new total (you should use `total_minus_store_credits` for total) and shipping rates.
99
+
100
+ </details>
101
+
102
+
103
+ ### Shipping Method/Rate change
104
+
105
+ Here we need to send the selected shipping method to the backend and update the total in the payment element
106
+
107
+ [Endpoint documentation](/api-reference/storefront/checkout-shipments/selects-shipping-method-for-shipments)
108
+
109
+ ```bash Select shipping method
110
+ curl -X PATCH '<SHOP URL>/api/v2/storefront/checkout/select_shipping_method' \
111
+ -H 'Authorization: Bearer <Token>' \
112
+ -H 'Content-Type: application/json' \
113
+ -d '{
114
+ "shipping_method_id": <Shipping Method ID>
115
+ }'
116
+ ```
117
+
118
+ - **`shipping_method_id`** (`string`) — Shipping method ID of the selected shipping rate
119
+
120
+ Subsequently, update the payment element with a new total taken from the response's `total_minus_store_credits`
121
+
122
+ ### Confirming the payment
123
+
124
+ Now you should make several more calls to the backend
125
+
126
+ <details>
127
+ <summary>Confirm that the order is ready for the payment</summary>
128
+
129
+ ```bash Validate order for payment
130
+ curl -X POST '<SHOP URL>/api/v2/storefront/checkout/validate_order_for_payment?skip_state=true' \
131
+ -H 'Authorization: Bearer <Token>'
132
+ ```
133
+ > **INFO:** `200` response code means that the order is ready for the payment.
134
+
135
+ [Endpoint documentation](/api-reference/storefront/checkout/validate-order-payment)
136
+
137
+ </details>
138
+
139
+ <details>
140
+ <summary>Update the address with more data</summary>
141
+
142
+ You should have a lot more information about the customer (in previous events, Stripe probably will not provide you information such as customer address), so send them to the backend:
143
+
144
+ [Endpoint documentation](/api-reference/storefront/checkout/update-checkout)
145
+
146
+ ```bash Update the order [expandable]
147
+ curl -X PATCH <SHOP URL>/api/v2/storefront/checkout \
148
+ -H 'Authorization: Bearer <Token>' \
149
+ -H 'Content-Type: application/json' \
150
+ -d '{
151
+ "order": {
152
+ "email": <EMAIL>,
153
+ "ship_address_attributes": {
154
+ "quick_checkout": true,
155
+ "firstname": <First name>,
156
+ "lastname": <Last name>,
157
+ "address1": <Address>,
158
+ "address2": <Address 2>,
159
+ "city": <City>,
160
+ "zipcode": <Zip>,
161
+ "country_iso": <Country>,
162
+ "state_name": <State>,
163
+ "phone": <Phone>
164
+ }
165
+ },
166
+ "do_not_change_state": true
167
+ }'
168
+ ```
169
+ - **`email`** (`string`) — Customer's email, e.g. email@example.com
170
+
171
+ - **`quick_checkout`** (`bool`) — `true` indicating that the order is from quick checkout
172
+
173
+ - **`firstname`** (`string`) — Customer's first name, e.g. John
174
+
175
+ - **`lastname`** (`string`) — Customer's last name, e.g. Doe
176
+
177
+ - **`address1`** (`string`) — Customer's address, e.g. 123 Main St
178
+
179
+ - **`address2`** (`string`) — Customer's address 2, e.g., Apt. 1
180
+
181
+ - **`zipcode`** (`string`) — Customer's zip code, e.g. 94043
182
+
183
+ - **`country_iso`** (`string`) — Customer's country ISO, e.g. US
184
+
185
+ - **`state_name`** (`string`) — Customer's address state, e.g. CA (empty string is also accepted)
186
+
187
+ - **`phone`** (`string`) — Customer's phone number, e.g. +1234567890
188
+
189
+ - **`do_not_change_state`** (`bool`) — Set it to `true` so the order does not advance to the next state
190
+
191
+ </details>
192
+
193
+
194
+ <details>
195
+ <summary>Move the order to the payment step</summary>
196
+
197
+ [Endpoint documentation](/api-reference/storefront/checkout-state/advance-checkout)
198
+ ```bash Move the order to the payment step
199
+ curl -X PATCH '<SHOP URL>/api/v2/storefront/checkout/advance?state=payment' \
200
+ -H 'Authorization: Bearer <Token>' \
201
+ -d '{
202
+ "shipping_method_id": <Shipping Method ID>
203
+ }'
204
+ ```
205
+ - **`shipping_method_id`** (`string`) — Shipping method ID of the selected shipping rate
206
+
207
+ </details>
208
+
209
+
210
+ Thereafter, you should confirm the payment intent using the Stripe library; this depends on your platform/language.
211
+
212
+ > **WARNING:** `<PAYMENT INTENT ID>` should be Spree's internal payment intent ID, which you will receive when you create the payment intent. Do not confuse it with Stripe's payment intent ID.
213
+
214
+ If you like to redirect the user to Spree's order summary page, then set the `return_url` when confirming the payment intent to `<SHOP URL>/stripe/payment_intents/<PAYMENT INTENT ID>`. This will check if the payment intent is confirmed, move the order to the complete state, and redirect the user to the order summary.
215
+
216
+ If you like to make the order summary page by yourself, then after confirming the payment intent in Stripe, make this request:
217
+
218
+
219
+ ```bash Confirm payment intent
220
+ curl -X POST <SHOP URL>/api/v2/storefront/stripe/payment_intents/<PAYMENT INTENT ID>/confirm \
221
+ -H 'Authorization: Bearer <Token>'
222
+ ```
223
+
224
+ [Endpoint documentation](/api-reference/storefront/stripe/mark-the-payment-intent-as-confirmed-and-move-the-order-to-the-complete-state)
225
+
226
+ This will also check if the payment intent is confirmed, and it will move the order to the complete state
227
+
228
+ ### User cancels the payment
229
+
230
+ If at any point, the user cancels the payment (closes the quick checkout sheet/modal), you will need to handle this event and clear the shipping and billing address from the order as these addresses will not be valid and if someones decides to use standard checkout it could lead to errors.
231
+
232
+ ```bash Reset order addresses
233
+ curl -X PATCH <SHOP URL>/api/v2/storefront/checkout \
234
+ -H 'Authorization: Bearer <Token>' \
235
+ -H 'Content-Type: application/json' \
236
+ -d '{
237
+ "order": {
238
+ "ship_address_id": "CLEAR",
239
+ "bill_address_id": "CLEAR"
240
+ }
241
+ }'
242
+ ```
243
+
244
+ [Endpoint documentation](/api-reference/storefront/checkout/update-checkout)
245
+
246
+ ### All Done!
247
+
248
+ Congrats! Now, your users should be able to pay for orders with quick checkout! Need support or want to give some feedback? You can join our [community](https://slack.spreecommerce.org/) or drop us an email at [hello@spreecommerce.org](mailto:hello@spreecommerce.org).