Wiki source code of PayEx Checkout v1
Last modified by Trieu Tran on 2019/12/04 14:11
![]() |
34.1 | 1 | == Introduction == |
![]() |
11.1 | 2 | |
![]() |
40.1 | 3 | PayEx Checkout v1 is an easy way for customers to complete payments. We provide a two-phase payment method which means that an amount is initially reserved (authorized), then deducted (captured) and described in more detail when you are ready to send out the goods. |
![]() |
11.1 | 4 | |
![]() |
34.1 | 5 | == What you need before you get started == |
![]() |
11.1 | 6 | |
![]() |
14.1 | 7 | * HTTPS enabled web server |
8 | * Agreement that includes PayEx Checkout | ||
9 | * Obtained credentials (access token) from PayEx | ||
10 | |||
11 | To get a grasp of what we expect of your implementation when you are finished, we recommend that you take a peek at the following sequence diagram before you get started. | ||
12 | |||
13 | |||
14 | {{plantuml}} | ||
15 | @startuml | ||
16 | skinparam sequence{ | ||
17 | ArrowColor #2DA944 | ||
18 | |||
19 | ActorFontColor #333333 | ||
20 | ActorFontStyle bold | ||
21 | ActorFontSize 15 | ||
22 | ActorBackgroundColor #fefefe | ||
23 | ActorBorderColor #2DA944 | ||
24 | |||
25 | LifeLineBorderColor #999999 | ||
26 | LifeLineBackgroundColor #dddddd | ||
27 | |||
28 | ParticipantBorderColor #2DA944 | ||
29 | ParticipantBackgroundColor #ffffff | ||
30 | ParticipantFontColor #333333 | ||
31 | ParticipantFontStyle bold | ||
32 | } | ||
33 | |||
34 | skinparam Roundcorner 10 | ||
35 | skinparam Shadowing false | ||
36 | |||
37 | skinparam ActivityBorderColor #123123 | ||
38 | |||
39 | skinparam NoteBackgroundColor white | ||
40 | skinparam NoteBorderColor #999999 | ||
41 | skinparam NoteFontColor #333333 | ||
42 | |||
43 | skinparam sequenceDividerBackgroundColor white | ||
44 | skinparam sequenceDividerBorderColor #999999 | ||
45 | skinparam sequenceDividerFontStyle bold | ||
46 | skinparam sequenceDividerFontSize 15 | ||
47 | |||
48 | Actor Consumer | ||
49 | Participant "Merchant Web Page" as MerchantWebPage | ||
50 | Participant "Merchant Web Server" as MerchantWebServer | ||
51 | Participant PayEx | ||
52 | '//Sequence start//' | ||
53 | |||
54 | Consumer->MerchantWebPage: Open page with Checkout button | ||
55 | Activate MerchantWebPage | ||
56 | MerchantWebPage->MerchantWebServer: Load web page | ||
57 | Activate MerchantWebServer | ||
![]() |
18.1 | 58 | ==[[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/#HStep1:Createpaymentsession step 1: create payment session ]]== |
![]() |
19.1 | 59 | MerchantWebServer->PayEx: GET [[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/Testdata/#HUsefulURLs <checkout baseUrl>]] |
![]() |
14.1 | 60 | Activate PayEx |
61 | note left: First API request | ||
62 | MerchantWebServer<--PayEx: Response: {paymentSessionUrl} | ||
![]() |
19.1 | 63 | MerchantWebServer->PayEx: POST [[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/Introduction/Payment-session/ <checkout paymentSessionUrl> $accessToken]] |
![]() |
14.1 | 64 | note left: Second API request |
65 | PayEx-->MerchantWebServer: {paymentSessionUrl} | ||
66 | Deactivate PayEx | ||
67 | MerchantWebServer->MerchantWebServer: Save {paymentSessionUrl} to local storage | ||
68 | |||
69 | MerchantWebServer->MerchantWebPage: Page with Checkout config {paymentSessionUrl} | ||
70 | Deactivate MerchantWebServer | ||
![]() |
18.1 | 71 | ==[[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/#HStep2:Configureyourfrontend step 2: configure your frontend]]== |
![]() |
14.1 | 72 | |
73 | MerchantWebPage->PayEx: GET checkout.js | ||
74 | Activate PayEx | ||
75 | PayEx->MerchantWebPage: Serve static JavaScript | ||
76 | Deactivate PayEx | ||
77 | MerchantWebPage->Consumer: Show purchase page | ||
78 | Deactivate MerchantWebPage | ||
79 | ||| | ||
80 | hnote over MerchantWebPage: Consumer presses Checkout button | ||
81 | |||
82 | Consumer->MerchantWebPage: Checkout button clicked | ||
83 | |||
84 | |||
![]() |
18.1 | 85 | ==[[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/#HStep3:Paymentwindow step 3: payment window]]== |
![]() |
14.1 | 86 | Activate MerchantWebPage |
87 | MerchantWebPage->Consumer: Display Checkout to Consumer | ||
88 | note right: Checkout window opens. Consumer purchase dialogue | ||
89 | Consumer->MerchantWebPage: Enter payment data | ||
90 | MerchantWebPage->PayEx: Payment data is sent to PayEx for authorization | ||
91 | Activate PayEx | ||
92 | PayEx-->MerchantWebPage: Response purchase dialog | ||
93 | Deactivate PayEx | ||
94 | note left: Checkout windows closes | ||
95 | MerchantWebPage->MerchantWebServer: POST Payment <form> | ||
96 | Deactivate MerchantWebPage | ||
97 | |||
98 | Activate MerchantWebServer | ||
![]() |
18.1 | 99 | ==[[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/#HStep4:Getpaymentstatus step 4: get payment status]]== |
![]() |
14.1 | 100 | MerchantWebServer<-MerchantWebServer: Get {paymentSessionUrl} from storage |
101 | |||
![]() |
19.1 | 102 | MerchantWebServer->PayEx: GET [[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/Introduction/Payment-session/ <paymentSessionUrl> $merchantToken]] |
![]() |
14.1 | 103 | note left: Third API request |
104 | Activate PayEx | ||
105 | PayEx-->MerchantWebServer: Respons paymentSession Object | ||
106 | |||
![]() |
19.1 | 107 | MerchantWebServer->PayEx: GET [[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/Introduction/Payment/ <paymentUrl> $merchantToken]] |
![]() |
14.1 | 108 | note left: Fourth API request |
109 | MerchantWebServer<--PayEx: Response paymentStatus Object | ||
110 | Deactivate PayEx | ||
111 | |||
112 | MerchantWebServer<-MerchantWebServer: Save paymentStatusObject | ||
113 | MerchantWebServer->MerchantWebPage:Receipt page | ||
114 | Deactivate MerchantWebPage | ||
115 | Deactivate MerchantWebServer | ||
116 | |||
117 | ||| | ||
118 | hnote over MerchantWebServer: Awaiting order fullfilment | ||
119 | ||| | ||
120 | |||
![]() |
18.1 | 121 | ==[[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/#HStep5:Capturethepayment step 5: capture the payment]]== |
![]() |
14.1 | 122 | |
123 | MerchantWebServer->MerchantWebServer: Complete order | ||
124 | Activate MerchantWebServer | ||
![]() |
19.1 | 125 | MerchantWebServer->PayEx: POST [[https://wiki.payex.com/xwiki/wiki/developer/view/Main/ECommerce/PayEx%20Checkout/Introduction/Payment/#HCapture <CaptureUrl> $merchantToken]] |
![]() |
14.1 | 126 | Activate PayEx |
127 | note left: Fifth API request | ||
128 | PayEx-->MerchantWebServer: Capture response | ||
129 | Deactivate PayEx | ||
130 | MerchantWebServer->MerchantWebServer: Ship goods | ||
131 | MerchantWebServer->Consumer: Consumer recieves goods | ||
132 | Deactivate MerchantWebServer | ||
133 | '//Sequence end//' | ||
134 | @enduml | ||
135 | {{/plantuml}} | ||
136 | |||
137 | |||
138 | |||
![]() |
34.1 | 139 | == What you should do, step by step == |
![]() |
14.1 | 140 | |
![]() |
44.1 | 141 | Below is an example implementation provided in C# 6, .NET 4.5.1+ and Newtonsoft.Json for the backend code. The frontend naturally uses HTML5 and JavaScript. To view backend examples of the raw HTTP request and response messages, please have a look at the [[Backend API documentation>>doc:Sandbox.payex-checkout-v1.Introduction.WebHome]]. |
![]() |
14.1 | 142 | |
143 | Note that the examples are written for a "happy path" implementation and thus contain no error handling of any kind. The examples are therefore not production ready code to be used in an actual application, they are just provided to help understanding the API and give the implementation a head start. | ||
144 | |||
![]() |
45.1 | 145 | Test data is located in the [[Test Data section>>doc:Sandbox.payex-checkout-v1.Testdata.WebHome]]. If you encounter any problem with the implementation, please visit the troubleshooting section or [[send us an e-mail>>mailto:support.ecom@payex.com]]. |
![]() |
14.1 | 146 | |
![]() |
34.1 | 147 | === Step 1: Create payment session === |
![]() |
14.1 | 148 | |
149 | Create a payment session by doing a HTTP POST from your webserver with payment info and your merchant token. The response from the POST will contain a Payment Session URL that you will need later. Save this value for future use (frontend config and operations on the payment) related to the order/shoppingcart in your database. | ||
150 | |||
151 | {{tabs idsToLabels="HTTP=HTTP, CS=C#"/}} | ||
152 | |||
153 | (% id="HTTP" %) | ||
154 | ((( | ||
155 | Retrieve the Home resource and locate the Payment Session base URL | ||
156 | |||
157 | **Request** | ||
158 | |||
159 | {{code language="JavaScript"}} | ||
160 | GET https://api.payex.com/psp/checkout/ HTTP/1.1 | ||
161 | Accept: application/json | ||
162 | Authorization: Bearer merchantToken== | ||
163 | {{/code}} | ||
164 | |||
165 | **Response** | ||
166 | |||
167 | {{code language="JavaScript"}} | ||
168 | HTTP/1.1 200 OK | ||
169 | Content-Type: application/json | ||
170 | |||
171 | { | ||
172 | "paymentSession": "<payment_session_url>" | ||
173 | } | ||
174 | {{/code}} | ||
175 | |||
176 | Perform the POST request to the Payment Session base URL to create a Payment Session | ||
177 | |||
178 | **Request** | ||
179 | |||
180 | {{code language="JavaScript"}} | ||
181 | POST https://api.payex.com/psp/checkout/payment-sessions/ HTTP/1.1 | ||
182 | Content-Type: application/json | ||
183 | Authorization: Bearer merchantToken== | ||
184 | |||
185 | { | ||
186 | "amount": 199.50, | ||
187 | "vatAmount": 39.90, | ||
188 | "currency": "NOK", | ||
189 | "callbackUrl": "https://merchant.api/callback", | ||
190 | "reference": "merchant-order-123", | ||
191 | "acquire": ["email", "mobilePhoneNumber", "shippingAddress"], | ||
192 | "culture": "nb-NO", | ||
![]() |
31.1 | 193 | "hosts": ["https://merchant.com/"], |
![]() |
14.1 | 194 | "payer": { |
195 | "email": "payer@example.com", | ||
196 | "mobilePhoneNumber": "+4712345678" | ||
197 | }, | ||
198 | "fees" : { | ||
199 | "invoice": { | ||
200 | "amount": 19.50, | ||
201 | "vatAmount": 3.90, | ||
202 | "description": "Invoice fee" | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | |||
207 | {{/code}} | ||
208 | |||
209 | **Response** | ||
210 | |||
211 | {{code language="JavaScript"}} | ||
212 | HTTP/1.1 201 Created | ||
213 | Content-Type: application/json | ||
214 | Location: https://api.payex.com/psp/checkout/payment-sessions/123-456-789 | ||
215 | |||
216 | { | ||
217 | "id": "https://api.payex.com/psp/checkout/payment-sessions/123-456-789", | ||
![]() |
31.1 | 218 | "amount": 199.50, |
219 | "vatAmount": 39.90, | ||
220 | "currency": "NOK", | ||
221 | "callbackUrl": "https://merchant.api/callback", | ||
222 | "reference": "merchant-order-123", | ||
223 | "acquire": ["email", "mobilePhoneNumber", "shippingAddress"], | ||
224 | "culture": "nb-NO", | ||
225 | "hosts": ["https://merchant.com/"], | ||
226 | "payer": { | ||
227 | "email": "payer@example.com", | ||
228 | "mobilePhoneNumber": "+4712345678" | ||
229 | }, | ||
230 | "fees" : { | ||
231 | "invoice": { | ||
232 | "amount": 19.50, | ||
233 | "vatAmount": 3.90, | ||
234 | "description": "Invoice fee" | ||
235 | } | ||
236 | } | ||
![]() |
14.1 | 237 | } |
238 | {{/code}} | ||
239 | |||
240 | Find the URL of the created Payment Session in the HTTP 'Location' header and store it alongside the order, shopping cart, or similar | ||
241 | ))) | ||
242 | |||
243 | (% id="CS" %) | ||
244 | ((( | ||
245 | {{code language="c#"}} | ||
246 | var merchantToken = "<secret merchant token>"; | ||
247 | var httpClient = new HttpClient(); | ||
248 | httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + merchantToken); | ||
249 | |||
250 | // 1. Retrieve the Home resource and locate the Payment Session base URL. | ||
251 | var homeResponse = await httpClient.GetAsync("https://api.payex.com/psp/checkout"); | ||
252 | var homeContent = await homeResponse.Content.ReadAsStringAsync(); | ||
253 | var home = Newtonsoft.Json.Linq.JObject.Parse(homeContent); | ||
254 | var paymentSessionBaseUrl = home["paymentSession"].ToString(); | ||
255 | |||
256 | // 2. Perform the POST request to the Payment Session base URL to create a Payment Session | ||
257 | var json = Newtonsoft.Json.JsonConvert.SerializeObject(new | ||
258 | { | ||
259 | amount = 100.00, | ||
260 | vatAmount = 20.00, | ||
261 | currency = "NOK", | ||
262 | callbackUrl = "https://merchant.api/callback", | ||
263 | reference = "merchant-order-123", | ||
264 | acquire = new[] { "shippingAddress" }, | ||
265 | culture = "nb-NO" | ||
266 | }); | ||
267 | var paymentSessionContent = new StringContent(json, Encoding.UTF8, "application/json"); | ||
268 | var paymentSessionResponse = await httpClient.PostAsync(paymentSessionBaseUrl, paymentSessionContent); | ||
269 | |||
270 | // 3. Find the URL of the created Payment Session in the HTTP 'Location' header and store it alongside the order, shopping cart, or similar. | ||
271 | var paymentSessionUrl = paymentSessionResponse.Headers.Location; | ||
272 | {{/code}} | ||
273 | |||
274 | After the above code is executed, the {{code}}paymentSessionUrl{{/code}} variable will contain the URL to a Payment Session that contains the payment data used to guide the user through the PayEx Checkout user flow. **Remember to persist the {{code}}paymentSessionUrl{{/code}} to storage** related to the order, shopping cart or similar represented by the {{code}}reference{{/code}} above. | ||
275 | ))) | ||
276 | |||
277 | ---- | ||
278 | |||
![]() |
43.1 | 279 | Your can read more about the payment session object [[here>>Sandbox.payex-checkout-v1.Introduction.Payment-session.WebHome]]. |
![]() |
14.1 | 280 | |
![]() |
34.1 | 281 | === Step 2: Configure your frontend === |
![]() |
14.1 | 282 | |
283 | PayEx Checkout uses a script that bootstraps the payment process when your purchase button is clicked. Add the PayEx Checkout script to your page: | ||
284 | |||
285 | {{code language="html"}} | ||
![]() |
33.1 | 286 | <script src="https://checkout.externalintegration.payex.com/js/payex-checkout.min.js"></script> |
![]() |
14.1 | 287 | {{/code}} |
288 | |||
![]() |
33.1 | 289 | Please note that the above URL points to **PayEx Checkout's test environment**. For the URL to PayEx' production environment, [[please refer to the general API introduction>>doc:Main.ecommerce.technical-reference.card-payments.WebHome]]. |
![]() |
14.1 | 290 | |
291 | Choose the button that you want to start the checkout process with and add the attribute data-payex-checkout with the value returned from return in the initial POST. Then add the disable attribute - the PayEx Checkout JavaScript will enable it when it is properly loaded. The button should be wrapped inside a form that POST to your server. | ||
292 | |||
293 | {{code language="html"}} | ||
294 | <form action="<url_to_your_server>" method="post"> | ||
295 | <!-- ... --> | ||
296 | <button data-payex-checkout="<payment_session_url>" disabled>Pay</button> | ||
297 | </form> | ||
298 | {{/code}} | ||
299 | |||
300 | The PayEx Checkout script will post the form when the payment process is complete. | ||
301 | |||
![]() |
41.1 | 302 | You can read more about how to implement PayEx Checkout in your frontend [[here>>Sandbox.payex-checkout-v1.Frontend API.WebHome]]. |
![]() |
14.1 | 303 | |
![]() |
34.1 | 304 | === Step 3: Payment window (facilitated by PayEx) === |
![]() |
14.1 | 305 | |
![]() |
34.1 | 306 | When a consumer clicks on the Pay button the PayEx Checkout payment window appears in the web browser. This payment window includes the following steps. |
![]() |
31.1 | 307 | |
![]() |
34.1 | 308 | ==== Login ==== |
309 | |||
310 | PayEx holds all payer information for easier payment procedure. If the user submits an email address a lookup process begins. | ||
![]() |
31.1 | 311 | Otherwise an anonymous payment process is used where only credit card is available as payment method. |
![]() |
34.1 | 312 | |
313 | ==== Authentication ==== | ||
314 | |||
![]() |
31.1 | 315 | By specifying mobile phone number, a verification code is sent to your phone. |
316 | |||
![]() |
34.1 | 317 | ==== Delivery ==== |
318 | |||
![]() |
31.1 | 319 | Depending on the parameters provided in the acquires property, various address information is required to continue to next step. |
320 | |||
![]() |
34.1 | 321 | ==== Payment ==== |
![]() |
31.1 | 322 | |
323 | Depending on merchant country, merchant contract and consumer country a list of payment options is displayed. | ||
![]() |
34.1 | 324 | Possible options are currently credit card and invoice. |
![]() |
31.1 | 325 | Credit card offers the option to add a new card or pick a previous card. |
326 | Invoice is only available for consumers in same country as merchant. | ||
327 | |||
![]() |
14.1 | 328 | Once the payment is authorized at our end - the PayEx Checkout Javascript will post the form. |
![]() |
34.1 | 329 | From the payment window is opened until it closes, everything in the payment process is performed entirely by PayEx. After that we expect a receipt to be sent to the consumer. |
![]() |
14.1 | 330 | |
![]() |
34.1 | 331 | === Step 4: Get payment status === |
![]() |
14.1 | 332 | |
333 | After a successfully authorized payment, the purchase form will be submitted as earlier mentioned. It is assumed that the form contains the reference connecting the previously persisted {{code}}paymentSessionUrl{{/code}} to the order, shopping cart, or similar. | ||
334 | |||
335 | When the form is submitted, look up the {{code}}paymentSesionUrl{{/code}} and perform a {{code}}GET{{/code}} request on it to retrieve the status of the payment. The returned JSON will also contain the necessary URLs to perform actions on the payment such as capture, cancel and reversal. | ||
336 | |||
337 | {{tabs idsToLabels="HTTP_2=HTTP, C_2=C#"/}} | ||
338 | |||
339 | (% id="HTTP_2" %) | ||
340 | ((( | ||
![]() |
31.1 | 341 | Retrieve the ##paymentSessionUrl## related to the submitted form from storage, and then retrieve the Payment Session and find the URL of the Payment. |
![]() |
14.1 | 342 | |
343 | **Request** | ||
344 | |||
345 | {{code language="JavaScript"}} | ||
346 | GET https://api.payex.com/psp/checkout/payment-sessions/123-456-789 HTTP/1.1 | ||
347 | Accept: application/json | ||
348 | Authorization: Bearer merchantToken== | ||
349 | {{/code}} | ||
350 | |||
351 | **Response** | ||
352 | |||
353 | {{code language="JavaScript"}} | ||
354 | HTTP/1.1 200 OK | ||
355 | Content-Type: application/json | ||
356 | |||
357 | { | ||
358 | "amount": 199.50, | ||
359 | "vatAmount": 39.90, | ||
360 | "currency": "NOK", | ||
361 | "callbackUrl": "https://merchant.api/callback", | ||
362 | "reference": "merchant-order-123", | ||
363 | "acquire": ["email", "mobilePhoneNumber", "shippingAddress"], | ||
364 | "culture": "nb-NO", | ||
365 | "addressee": { | ||
366 | "name": "Olivia Nyhuus", | ||
367 | "email": "olivia.nyhuus@example.com", | ||
368 | "mobilePhoneNumber": "004791234567", | ||
369 | "shippingAddress": { | ||
370 | "city": "Oslo", | ||
371 | "countryCode": "NO", | ||
372 | "streetAddress": "Stålverkskroken, 4", | ||
373 | "zipCode": "0661" | ||
374 | } | ||
375 | }, | ||
376 | "payment": "https://api.payex.com/psp/payment/credit-card/984-223-836", | ||
377 | } | ||
378 | {{/code}} | ||
379 | |||
380 | Retrieve the Payment and inspect its state. | ||
381 | |||
382 | **Request** | ||
383 | |||
384 | {{code language="JavaScript"}} | ||
385 | GET <payment_url> HTTP/1.1 | ||
386 | Content-Type: application/json | ||
387 | Authorization: Bearer merchantToken== | ||
388 | {{/code}} | ||
389 | |||
390 | **Response** | ||
391 | |||
392 | {{code language="JavaScript"}} | ||
393 | { | ||
394 | "payment": { | ||
395 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c", | ||
396 | "number": 1234567890, | ||
397 | "created": "2016-09-14T13:21:29.3182115Z", | ||
398 | "updated": "2016-09-14T13:21:57.6627579Z", | ||
399 | "operation": "Purchase|Verify|Recur", | ||
![]() |
46.1 | 400 | "intent": "Authorization|AutoCapture", |
![]() |
14.1 | 401 | "state": "Ready|Pending|Failed|Aborted", |
402 | "currency": "NOK|SEK|...", | ||
403 | "amount": 1500, | ||
404 | "remainingCaptureAmount": 1500, | ||
405 | "remainingCancellationAmount": 1500, | ||
406 | "remainingReversalAmount": 0, | ||
407 | "description": "Test Purchase", | ||
408 | "initiatingSystemUserAgent": "PostmanRuntime/3.0.1", | ||
409 | "userAgent": "Mozilla/5.0...", | ||
410 | "language": "nb-NO", | ||
411 | "paymentToken": "5adc265f-f87f-4313-577e-08d3dca1a26c", | ||
412 | "prices": { | ||
413 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/prices" | ||
414 | }, | ||
415 | "transactions": { | ||
416 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/transactions" | ||
417 | }, | ||
418 | "authorizations": { | ||
419 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/authorizations" | ||
420 | }, | ||
421 | "captures": { | ||
422 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/captures" | ||
423 | }, | ||
424 | "cancellations": { | ||
425 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/cancellations" | ||
426 | }, | ||
427 | "reversals": { | ||
428 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/reversals" | ||
429 | }, | ||
430 | "payeeInfo": { | ||
431 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/payeeInfo" | ||
432 | }, | ||
433 | "urls": { | ||
434 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/urls" | ||
435 | }, | ||
436 | "settings": { | ||
437 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/settings" | ||
438 | } | ||
439 | }, | ||
440 | "operations": [ | ||
441 | { | ||
442 | "href": "<capture_operation_url>", | ||
443 | "rel": "create-checkout-capture", | ||
444 | "method": "POST" | ||
445 | }, | ||
446 | { | ||
447 | "href": "<cancellation_operation_url>", | ||
448 | "rel": "create-checkout-cancellation", | ||
449 | "method": "POST" | ||
450 | }, | ||
451 | { | ||
452 | "href": "<reversal_operation_url>", | ||
453 | "rel": "create-checkout-reversal", | ||
454 | "method": "POST" | ||
455 | } | ||
456 | ] | ||
457 | } | ||
458 | {{/code}} | ||
459 | ))) | ||
460 | |||
461 | (% id="C_2" %) | ||
462 | ((( | ||
![]() |
34.1 | 463 | ===== Implementation example ===== |
![]() |
14.1 | 464 | |
465 | {{code language="c#"}} | ||
466 | var merchantToken = "<secret merchant token>"; | ||
467 | var httpClient = new HttpClient(); | ||
468 | httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + merchantToken); | ||
469 | |||
470 | // 1. Retrieve the paymentSessionUrl related to the submitted form from storage. | ||
471 | var paymentSessionUrl = "<retrieved from storage>"; | ||
472 | |||
473 | // 2. Retrieve the Payment Session and find the URL of the Payment. | ||
474 | var paymentSessionResponse = await httpClient.GetAsync(paymentSessionUrl); | ||
475 | var paymentSessionContent = await paymentSessionResponse.Content.ReadAsStringAsync(); | ||
476 | var paymentSession = Newtonsoft.Json.Linq.JObject.Parse(paymentSessionContent); | ||
477 | var paymentUrl = paymentSession["payment"].ToString(); | ||
478 | |||
479 | // 3. Retrieve the Payment and inspect its state. | ||
480 | var paymentResponse = await httpClient.GetAsync(paymentUrl); | ||
481 | var paymentContent = await paymentResponse.Content.ReadAsStringAsync(); | ||
482 | var payment = Newtonsoft.Json.Linq.JObject.Parse(paymentContent); | ||
483 | var paymentState = payment["state"].ToString(); | ||
484 | {{/code}} | ||
485 | |||
486 | After the above code example is executed, the {{code}}paymentState{{/code}} variable will contain the value {{code}}Ready{{/code}}, {{code}}Pending{{/code}}, {{code}}Failed{{/code}} or {{code}}Aborted{{/code}}. Use it to provide a message to the user in the form of a receipt, an error message in the event of failure, etc. | ||
487 | ))) | ||
488 | |||
489 | ---- | ||
490 | |||
491 | In a normal flow the paymentState will be {{code}}Ready{{/code}} and it is now expected that an order confirmation is presented to the consumer in your webshop and that you ship the confirmation per email. | ||
492 | |||
![]() |
43.1 | 493 | Read more about the payment session [[here>>Sandbox.payex-checkout-v1.Introduction.Payment-session.WebHome||anchor="HRetrievePaymentSession"]]. |
![]() |
14.1 | 494 | |
495 | == Step 5: Capture the payment == | ||
496 | |||
497 | {{tabs idsToLabels="HTTP_3=HTTP, C_3=C#"/}} | ||
498 | |||
499 | Capture can be done at any time, depending on whether you want to physically send the purchased goods to the customer first, for instance. Just repeat the {{code}}GET{{/code}} request to the {{code}}paymentSessionUrl{{/code}}, find the {{code}}capture{{/code}} operation and execute it. We now expect an order confirmation to be sent to the consumer. | ||
500 | |||
501 | |||
502 | (% id="HTTP_3" %) | ||
503 | ((( | ||
504 | Retrieve the {{code}}paymentSessionUrl{{/code}} related to the submitted form from storage, and then retrieve the Payment Session and find the URL of the Payment. | ||
505 | |||
506 | **Request** | ||
507 | |||
508 | {{code language="JavaScript"}} | ||
509 | GET https://api.payex.com/psp/checkout/payment-sessions/123-456-789 HTTP/1.1 | ||
510 | Accept: application/json | ||
511 | Authorization: Bearer merchantToken== | ||
512 | {{/code}} | ||
513 | |||
514 | **Response** | ||
515 | |||
516 | {{code language="JavaScript"}} | ||
517 | HTTP/1.1 200 OK | ||
518 | Content-Type: application/json | ||
519 | |||
520 | { | ||
521 | "amount": 199.50, | ||
522 | "vatAmount": 39.90, | ||
523 | "currency": "NOK", | ||
524 | "callbackUrl": "https://merchant.api/callback", | ||
525 | "reference": "merchant-order-123", | ||
526 | "acquire": ["email", "mobilePhoneNumber", "shippingAddress"], | ||
527 | "culture": "nb-NO", | ||
528 | "addressee": { | ||
529 | "name": "Olivia Nyhuus", | ||
530 | "email": "olivia.nyhuus@example.com", | ||
531 | "mobilePhoneNumber": "004791234567", | ||
532 | "shippingAddress": { | ||
533 | "city": "Oslo", | ||
534 | "countryCode": "NO", | ||
535 | "streetAddress": "Stålverkskroken, 4", | ||
536 | "zipCode": "0661" | ||
537 | } | ||
538 | }, | ||
539 | "payment": "https://api.payex.com/psp/payment/credit-card/984-223-836" | ||
540 | } | ||
541 | {{/code}} | ||
542 | |||
543 | Retrieve the Payment and find its {{code}}create-checkout-capture{{/code}} operation: | ||
544 | |||
545 | **Request** | ||
546 | |||
547 | {{code language="JavaScript"}} | ||
548 | GET <payment_url> HTTP/1.1 | ||
549 | Content-Type: application/json | ||
550 | Authorization: Bearer merchantToken== | ||
551 | {{/code}} | ||
552 | |||
553 | **Response** | ||
554 | |||
555 | {{code language="JavaScript"}} | ||
556 | { | ||
557 | "payment": { | ||
558 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c", | ||
559 | "number": 1234567890, | ||
560 | "created": "2016-09-14T13:21:29.3182115Z", | ||
561 | "updated": "2016-09-14T13:21:57.6627579Z", | ||
562 | "operation": "Purchase|Verify|Recur", | ||
![]() |
47.1 | 563 | "intent": "Authorization|AutoCapture", |
![]() |
14.1 | 564 | "state": "Ready|Pending|Failed|Aborted", |
565 | "currency": "NOK|SEK|...", | ||
566 | "amount": 1500, | ||
567 | "remainingCaptureAmount": 1500, | ||
568 | "remainingCancellationAmount": 1500, | ||
569 | "remainingReversalAmount": 0, | ||
570 | "description": "Test Purchase", | ||
571 | "initiatingSystemUserAgent": "PostmanRuntime/3.0.1", | ||
572 | "userAgent": "Mozilla/5.0...", | ||
573 | "language": "nb-NO", | ||
574 | "paymentToken": "5adc265f-f87f-4313-577e-08d3dca1a26c", | ||
575 | "prices": { | ||
576 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/prices" | ||
577 | }, | ||
578 | "transactions": { | ||
579 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/transactions" | ||
580 | }, | ||
581 | "authorizations": { | ||
582 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/authorizations" | ||
583 | }, | ||
584 | "captures": { | ||
585 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/captures" | ||
586 | }, | ||
587 | "cancellations": { | ||
588 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/cancellations" | ||
589 | }, | ||
590 | "reversals": { | ||
591 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/reversals" | ||
592 | }, | ||
593 | "payeeInfo": { | ||
594 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/payeeInfo" | ||
595 | }, | ||
596 | "urls": { | ||
597 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/urls" | ||
598 | }, | ||
599 | "settings": { | ||
600 | "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/settings" | ||
601 | } | ||
602 | }, | ||
603 | "operations": [ | ||
604 | { | ||
605 | "href": "<capture_operation_url>", | ||
606 | "rel": "create-checkout-capture", | ||
607 | "method": "POST" | ||
608 | }, | ||
609 | { | ||
610 | "href": "<cancellation_operation_url>", | ||
611 | "rel": "create-checkout-cancellation", | ||
612 | "method": "POST" | ||
613 | }, | ||
614 | { | ||
615 | "href": "<reversal_operation_url>", | ||
616 | "rel": "create-checkout-reversal", | ||
617 | "method": "POST" | ||
618 | } | ||
619 | ] | ||
620 | } | ||
621 | {{/code}} | ||
622 | |||
623 | Perform the capture request: | ||
624 | |||
625 | **Request** | ||
626 | |||
627 | {{code language="JavaScript"}} | ||
628 | POST <capture_operation_href> HTTP/1.1 | ||
629 | Accept: application/json | ||
630 | Content-Type: application/json | ||
631 | Authorization: Bearer merchantToken== | ||
632 | |||
633 | { | ||
634 | "transaction": { | ||
635 | "description": "description for the transaction" | ||
636 | } | ||
637 | } | ||
638 | {{/code}} | ||
639 | |||
640 | **Response** | ||
641 | |||
642 | {{code language="JavaScript"}} | ||
643 | { | ||
644 | "payment": "<paymentUrl>", | ||
645 | "capture": { | ||
646 | "id": "<paymentCaptureUrl>", | ||
647 | "transaction": { | ||
648 | "id": "<transactionUrl>", | ||
649 | "created": "2016-09-14T01:01:01.01Z", | ||
650 | "updated": "2016-09-14T01:01:01.03Z", | ||
651 | "type": "Capture", | ||
652 | "state": "Initialized|Completed|Failed", | ||
653 | "number": 1234567890, | ||
654 | "amount": 1500, | ||
655 | "vatAmount": 300, | ||
656 | "description": "Test Capture", | ||
657 | "payeeReference": "ABC123", | ||
658 | "failedReason": "", | ||
659 | "isOperational": "TRUE|FALSE", | ||
660 | "operations": [] | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | {{/code}} | ||
665 | |||
666 | As the {{code}}state{{/code}} property in the response above will indicate, the capture operation should now be {{code}}Completed{{/code}}, indicating that the payment is captured. | ||
667 | ))) | ||
668 | |||
669 | (% id="C_3" %) | ||
670 | ((( | ||
671 | Implementation example | ||
672 | |||
673 | {{code language="c#"}} | ||
674 | var merchantToken = "<secret merchant token>"; | ||
675 | var httpClient = new HttpClient(); | ||
676 | httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + merchantToken); | ||
677 | |||
678 | // 1. Retrieve the paymentSessionUrl related to the submitted form from storage. | ||
679 | var paymentSessionUrl = "<retrieved from storage>"; | ||
680 | |||
681 | // 2. Retrieve the Payment Session and find the URL of the Payment. | ||
682 | var paymentSessionResponse = await httpClient.GetAsync(paymentSessionUrl); | ||
683 | var paymentSessionContent = await paymentSessionResponse.Content.ReadAsStringAsync(); | ||
684 | var paymentSession = Newtonsoft.Json.Linq.JObject.Parse(paymentSessionContent); | ||
685 | var paymentUrl = paymentSession["payment"].ToString(); | ||
686 | |||
687 | // 3. Retrieve the Payment and find its 'create-checkout-capture' operation. | ||
688 | var paymentResponse = await httpClient.GetAsync(paymentUrl); | ||
689 | var paymentContent = await paymentResponse.Content.ReadAsStringAsync(); | ||
690 | var payment = Newtonsoft.Json.Linq.JObject.Parse(paymentContent); | ||
691 | var captureUrl = payment["operations"] | ||
692 | .Children() | ||
693 | .First(x => x["rel"].ToString() == "create-checkout-capture")["href"] | ||
694 | .ToString(); | ||
695 | |||
696 | // 4. Perform the capture request. | ||
697 | var json = Newtonsoft.Json.JsonConvert.SerializeObject(new | ||
698 | { | ||
699 | transaction = new | ||
700 | { | ||
701 | description = "Captured the payment" | ||
702 | } | ||
703 | }); | ||
704 | var captureRequestContent = new StringContent(json, Encoding.UTF8, "application/json"); | ||
705 | var captureResponse = await httpClient.PostAsync(captureUrl, captureRequestContent); | ||
706 | var captureResponseContent = await captureResponse.Content.ReadAsStringAsync(); | ||
707 | var capture = Newtonsoft.Json.Linq.JObject.Parse(captureResponseContent); | ||
708 | {{/code}} | ||
709 | |||
710 | When the above code example is executed, the {{code}}capture{{/code}} variable will be a JSON object containing the result of the capture operation. It is now excepted that an order receipt is sent per email to the consumer. | ||
711 | |||
![]() |
42.1 | 712 | The above example performs a complete capture of the authorized amount. If you want to perform a more detailed captured, read more about the capture operation [[here.>>Sandbox.payex-checkout-v1.Introduction.Payment.WebHome||anchor="HCapture"]] |
![]() |
14.1 | 713 | ))) |