Sandbox.payex-checkout-v1 - PayEx Checkout v1 
Page of - last modified by Trieu Tran on 2019/12/04 14:11 
PayEx Checkout v1 

Trieu Tran

2019/12/04 14:11
Table of Contents
Introduction
What you need before you get started
What you should do, step by step
Step 1: Create payment session
Step 2: Configure your frontend
Step 3: Payment window (facilitated by PayEx)
Step 4: Get payment status
Step 5: Capture the payment

Introduction
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.
What you need before you get started
�	HTTPS enabled web server
�	Agreement that includes PayEx Checkout
�	Obtained credentials (access token) from PayEx
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.
Failed to execute the [groovy] macro. Cause: [The execution of the [groovy] script macro is not allowed. Check the rights of its last author or the parameters if it's rendered from another script.]. Click on this message for details.
org.xwiki.rendering.macro.MacroExecutionException: The execution of the [groovy] script macro is not allowed. Check the rights of its last author or the parameters if it's rendered from another script.
 at org.xwiki.rendering.macro.script.AbstractScriptMacro.execute(AbstractScriptMacro.java:178)
 at org.xwiki.rendering.macro.script.AbstractScriptMacro.execute(AbstractScriptMacro.java:58)
 at org.xwiki.rendering.internal.transformation.macro.MacroTransformation.transform(MacroTransformation.java:272)
 at org.xwiki.rendering.internal.transformation.DefaultRenderingContext.transformInContext(DefaultRenderingContext.java:183)
 at org.xwiki.rendering.internal.macro.wikibridge.DefaultWikiMacro.execute(DefaultWikiMacro.java:257)
 at org.xwiki.rendering.internal.macro.wikibridge.DefaultWikiMacro.execute(DefaultWikiMacro.java:62)
 at org.xwiki.rendering.internal.transformation.macro.MacroTransformation.transform(MacroTransformation.java:272)
 at org.xwiki.rendering.internal.transformation.DefaultRenderingContext.transformInContext(DefaultRenderingContext.java:183)
 at org.xwiki.rendering.internal.transformation.DefaultTransformationManager.performTransformations(DefaultTransformationManager.java:95)
 at org.xwiki.display.internal.DocumentContentDisplayer.display(DocumentContentDisplayer.java:263)
 at org.xwiki.display.internal.DocumentContentDisplayer.display(DocumentContentDisplayer.java:133)
 at org.xwiki.display.internal.DocumentContentDisplayer.display(DocumentContentDisplayer.java:58)
 at org.xwiki.display.internal.DefaultDocumentDisplayer.display(DefaultDocumentDisplayer.java:96)
 at org.xwiki.display.internal.DefaultDocumentDisplayer.display(DefaultDocumentDisplayer.java:39)
 at org.xwiki.sheet.internal.SheetDocumentDisplayer.display(SheetDocumentDisplayer.java:123)
 at org.xwiki.sheet.internal.SheetDocumentDisplayer.display(SheetDocumentDisplayer.java:52)
 at org.xwiki.display.internal.ConfiguredDocumentDisplayer.display(ConfiguredDocumentDisplayer.java:68)
 at org.xwiki.display.internal.ConfiguredDocumentDisplayer.display(ConfiguredDocumentDisplayer.java:42)
 at com.xpn.xwiki.doc.XWikiDocument.display(XWikiDocument.java:1146)
 at com.xpn.xwiki.doc.XWikiDocument.getRenderedContent(XWikiDocument.java:1187)
 at com.xpn.xwiki.doc.XWikiDocument.getRenderedContent(XWikiDocument.java:1164)
 at com.xpn.xwiki.doc.XWikiDocument.getRenderedContent(XWikiDocument.java:1195)
 at com.xpn.xwiki.api.Document.getRenderedContent(Document.java:701)
 at sun.reflect.GeneratedMethodAccessor508.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:395)
 at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:384)
 at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:173)
 at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:280)
 at org.apache.velocity.runtime.parser.node.ASTReference.render(ASTReference.java:369)
 at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:72)
 at org.apache.velocity.runtime.directive.Foreach.render(Foreach.java:420)
 at org.apache.velocity.runtime.parser.node.ASTDirective.render(ASTDirective.java:207)
 at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:342)
 at org.xwiki.velocity.internal.DefaultVelocityEngine.evaluateInternal(DefaultVelocityEngine.java:259)
 at org.xwiki.velocity.internal.DefaultVelocityEngine.evaluate(DefaultVelocityEngine.java:222)
 at com.xpn.xwiki.render.DefaultVelocityManager.evaluate(DefaultVelocityManager.java:361)
 at com.xpn.xwiki.internal.template.InternalTemplateManager.evaluateContent(InternalTemplateManager.java:810)
 at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:686)
 at com.xpn.xwiki.internal.template.InternalTemplateManager.lambda$renderFromSkin$0(InternalTemplateManager.java:661)
 at com.xpn.xwiki.internal.security.authorization.DefaultAuthorExecutor.call(DefaultAuthorExecutor.java:85)
 at com.xpn.xwiki.internal.template.InternalTemplateManager.renderFromSkin(InternalTemplateManager.java:660)
 at com.xpn.xwiki.internal.template.InternalTemplateManager.renderFromSkin(InternalTemplateManager.java:639)
 at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:625)
 at com.xpn.xwiki.internal.template.DefaultTemplateManager.render(DefaultTemplateManager.java:82)
 at com.xpn.xwiki.XWiki.evaluateTemplate(XWiki.java:2120)
 at com.xpn.xwiki.XWiki.parseTemplate(XWiki.java:2098)
 at com.xpn.xwiki.pdf.impl.PdfExportImpl.export(PdfExportImpl.java:261)
 at com.xpn.xwiki.web.ExportAction.export(ExportAction.java:255)
 at com.xpn.xwiki.web.ExportAction.render(ExportAction.java:87)
 at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:447)
 at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:210)
 at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:425)
 at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:228)
 at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
 at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at com.xpn.xwiki.web.ActionFilter.doFilter(ActionFilter.java:112)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.xwiki.wysiwyg.filter.ConversionFilter.doFilter(ConversionFilter.java:127)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.xwiki.container.servlet.filters.internal.SetHTTPHeaderFilter.doFilter(SetHTTPHeaderFilter.java:63)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.xwiki.container.servlet.filters.internal.SavedRequestRestorerFilter.doFilter(SavedRequestRestorerFilter.java:208)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.xwiki.container.servlet.filters.internal.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:111)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.xwiki.resource.servlet.RoutingFilter.doFilter(RoutingFilter.java:134)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
 at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
 at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
 at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
 at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
 at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
 at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
 at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 at java.lang.Thread.run(Unknown Source)
What you should do, step by step
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.
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.
Test data is located in the Test Data section. If you encounter any problem with the implementation, please visit the troubleshooting section or send us an e-mail.
Step 1: Create payment session
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.
�	HTTP 
�	C# 

Retrieve the Home resource and locate the Payment Session base URL

GET https://api.payex.com/psp/checkout/ HTTP/1.1
Accept: application/json
Authorization: Bearer merchantToken==

HTTP/1.1 200 OK
Content-Type: application/json

{
      "paymentSession": "<payment_session_url>"
}
Perform the POST request to the Payment Session base URL to create a Payment Session

POST https://api.payex.com/psp/checkout/payment-sessions/ HTTP/1.1
Content-Type: application/json
Authorization: Bearer merchantToken==

{
      "amount": 199.50,
      "vatAmount": 39.90,
      "currency": "NOK",
      "callbackUrl": "https://merchant.api/callback",
      "reference": "merchant-order-123",
      "acquire": ["email", "mobilePhoneNumber", "shippingAddress"],
      "culture": "nb-NO",
      "hosts": ["https://merchant.com/"],
      "payer": {
              "email": "payer@example.com",
              "mobilePhoneNumber": "+4712345678"
        },
      "fees" : {
              "invoice": {
                      "amount": 19.50,
                      "vatAmount": 3.90,
                      "description": "Invoice fee"
                }
        }
}

HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.payex.com/psp/checkout/payment-sessions/123-456-789

{
      "id": "https://api.payex.com/psp/checkout/payment-sessions/123-456-789",
      "amount": 199.50,
      "vatAmount": 39.90,
      "currency": "NOK",
      "callbackUrl": "https://merchant.api/callback",
      "reference": "merchant-order-123",
      "acquire": ["email", "mobilePhoneNumber", "shippingAddress"],
      "culture": "nb-NO",
      "hosts": ["https://merchant.com/"],
      "payer": {
              "email": "payer@example.com",
              "mobilePhoneNumber": "+4712345678"
        },
      "fees" : {
              "invoice": {
                      "amount": 19.50,
                      "vatAmount": 3.90,
                      "description": "Invoice fee"
                }
        }
}
Find the URL of the created Payment Session in the HTTP 'Location' header and store it alongside the order, shopping cart, or similar

var merchantToken = "<secret merchant token>";
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + merchantToken);

// 1. Retrieve the Home resource and locate the Payment Session base URL.
var homeResponse = await httpClient.GetAsync("https://api.payex.com/psp/checkout");
var homeContent = await homeResponse.Content.ReadAsStringAsync();
var home = Newtonsoft.Json.Linq.JObject.Parse(homeContent);
var paymentSessionBaseUrl = home["paymentSession"].ToString();

// 2. Perform the POST request to the Payment Session base URL to create a Payment Session
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
        amount = 100.00,
        vatAmount = 20.00,
        currency = "NOK",
        callbackUrl = "https://merchant.api/callback",
        reference = "merchant-order-123",
        acquire = new[] { "shippingAddress" },
        culture = "nb-NO"
});
var paymentSessionContent = new StringContent(json, Encoding.UTF8, "application/json");
var paymentSessionResponse = await httpClient.PostAsync(paymentSessionBaseUrl, paymentSessionContent);

// 3. Find the URL of the created Payment Session in the HTTP 'Location' header and store it alongside the order, shopping cart, or similar.
var paymentSessionUrl = paymentSessionResponse.Headers.Location;
After the above code is executed, the paymentSessionUrl 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.  related to the order, shopping cart or similar represented by the reference above.

Your can read more about the payment session object here.
Step 2: Configure your frontend
PayEx Checkout uses a script that bootstraps the payment process when your purchase button is clicked. Add the PayEx Checkout script to your page:
<script src="https://checkout.externalintegration.payex.com/js/payex-checkout.min.js"></script>
Please note that the above URL points to . For the URL to PayEx' production environment, please refer to the general API introduction.
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.
<form action="<url_to_your_server>" method="post">
  <!-- ... -->
    <button data-payex-checkout="<payment_session_url>" disabled>Pay</button>
</form>
The PayEx Checkout script will post the form when the payment process is complete.
You can read more about how to implement PayEx Checkout in your frontend here.
Step 3: Payment window (facilitated by PayEx)
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.
Login
PayEx holds all payer information for easier payment procedure. If the user submits an email address a lookup process begins.
Otherwise an anonymous payment process is used where only credit card is available as payment method.
Authentication
By specifying mobile phone number, a verification code is sent to your phone.  
Delivery
Depending on the parameters provided in the acquires property, various address information is required to continue to next step.
Payment
Depending on merchant country, merchant contract and consumer country a list of payment options is displayed.
Possible options are currently credit card and invoice.
Credit card offers the option to add a new card or pick a previous card.
Invoice is only available for consumers in same country as merchant.
Once the payment is authorized at our end - the PayEx Checkout Javascript will post the form.
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.
Step 4: Get payment status
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 paymentSessionUrl to the order, shopping cart, or similar.  
When the form is submitted, look up the paymentSesionUrl and perform a GET 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.
�	HTTP 
�	C# 

Retrieve the paymentSessionUrl related to the submitted form from storage, and then retrieve the Payment Session and find the URL of the Payment.

GET https://api.payex.com/psp/checkout/payment-sessions/123-456-789 HTTP/1.1
Accept: application/json
Authorization: Bearer merchantToken==

HTTP/1.1 200 OK
Content-Type: application/json

{
      "amount": 199.50,
      "vatAmount": 39.90,
      "currency": "NOK",
      "callbackUrl": "https://merchant.api/callback",
      "reference": "merchant-order-123",
      "acquire": ["email", "mobilePhoneNumber", "shippingAddress"],
      "culture": "nb-NO",
      "addressee": {
              "name": "Olivia Nyhuus",
              "email": "olivia.nyhuus@example.com",
              "mobilePhoneNumber": "004791234567",
              "shippingAddress": {
                      "city": "Oslo",
                      "countryCode": "NO",
                      "streetAddress": "Stålverkskroken, 4",
                      "zipCode": "0661"
                }
        },
      "payment": "https://api.payex.com/psp/payment/credit-card/984-223-836",
}
Retrieve the Payment and inspect its state.

GET <payment_url> HTTP/1.1
Content-Type: application/json
Authorization: Bearer merchantToken==

{
      "payment": {
              "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c",
              "number": 1234567890,
              "created": "2016-09-14T13:21:29.3182115Z",
              "updated": "2016-09-14T13:21:57.6627579Z",
              "operation": "Purchase|Verify|Recur",
              "intent": "Authorization|AutoCapture",
              "state": "Ready|Pending|Failed|Aborted",
              "currency": "NOK|SEK|...",
              "amount": 1500,
              "remainingCaptureAmount": 1500,
              "remainingCancellationAmount": 1500,
              "remainingReversalAmount": 0,
              "description": "Test Purchase",
              "initiatingSystemUserAgent": "PostmanRuntime/3.0.1",
              "userAgent": "Mozilla/5.0...",
              "language": "nb-NO",
              "paymentToken": "5adc265f-f87f-4313-577e-08d3dca1a26c",
              "prices": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/prices"
                },
              "transactions": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/transactions"
                },
              "authorizations": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/authorizations"
                },
              "captures": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/captures"
                },
              "cancellations": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/cancellations"
                },
              "reversals": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/reversals"
                },
              "payeeInfo": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/payeeInfo"
                },
              "urls": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/urls"
                },
              "settings": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/settings"
                }
        },
      "operations": [
                {
                      "href": "<capture_operation_url>",
                      "rel": "create-checkout-capture",
                      "method": "POST"
                },
                {
                      "href": "<cancellation_operation_url>",
                      "rel": "create-checkout-cancellation",
                      "method": "POST"
                },
                {
                      "href": "<reversal_operation_url>",
                      "rel": "create-checkout-reversal",
                      "method": "POST"
                }
        ]
}

Implementation example
var merchantToken = "<secret merchant token>";
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + merchantToken);

// 1. Retrieve the paymentSessionUrl related to the submitted form from storage.
var paymentSessionUrl = "<retrieved from storage>";

// 2. Retrieve the Payment Session and find the URL of the Payment.
var paymentSessionResponse = await httpClient.GetAsync(paymentSessionUrl);
var paymentSessionContent = await paymentSessionResponse.Content.ReadAsStringAsync();
var paymentSession = Newtonsoft.Json.Linq.JObject.Parse(paymentSessionContent);
var paymentUrl = paymentSession["payment"].ToString();

// 3. Retrieve the Payment and inspect its state.
var paymentResponse = await httpClient.GetAsync(paymentUrl);
var paymentContent = await paymentResponse.Content.ReadAsStringAsync();
var payment = Newtonsoft.Json.Linq.JObject.Parse(paymentContent);
var paymentState = payment["state"].ToString();
After the above code example is executed, the paymentState variable will contain the value Ready, Pending, Failed or Aborted. Use it to provide a message to the user in the form of a receipt, an error message in the event of failure, etc.

In a normal flow the paymentState will be Ready 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.
Read more about the payment session here.
Step 5: Capture the payment
�	HTTP 
�	C# 
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 GET request to the paymentSessionUrl, find the capture operation and execute it. We now expect an order confirmation to be sent to the consumer.

Retrieve the paymentSessionUrl related to the submitted form from storage, and then retrieve the Payment Session and find the URL of the Payment.

GET https://api.payex.com/psp/checkout/payment-sessions/123-456-789 HTTP/1.1
Accept: application/json
Authorization: Bearer merchantToken==

HTTP/1.1 200 OK
Content-Type: application/json

{
      "amount": 199.50,
      "vatAmount": 39.90,
      "currency": "NOK",
      "callbackUrl": "https://merchant.api/callback",
      "reference": "merchant-order-123",
      "acquire": ["email", "mobilePhoneNumber", "shippingAddress"],
      "culture": "nb-NO",
      "addressee": {
              "name": "Olivia Nyhuus",
              "email": "olivia.nyhuus@example.com",
              "mobilePhoneNumber": "004791234567",
              "shippingAddress": {
                      "city": "Oslo",
                      "countryCode": "NO",
                      "streetAddress": "Stålverkskroken, 4",
                      "zipCode": "0661"
                }
        },
      "payment": "https://api.payex.com/psp/payment/credit-card/984-223-836"
}
Retrieve the Payment and find its create-checkout-capture operation:

GET <payment_url> HTTP/1.1
Content-Type: application/json
Authorization: Bearer merchantToken==

{
      "payment": {
              "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c",
              "number": 1234567890,
              "created": "2016-09-14T13:21:29.3182115Z",
              "updated": "2016-09-14T13:21:57.6627579Z",
              "operation": "Purchase|Verify|Recur",
              "intent": "Authorization|AutoCapture",
              "state": "Ready|Pending|Failed|Aborted",
              "currency": "NOK|SEK|...",
              "amount": 1500,
              "remainingCaptureAmount": 1500,
              "remainingCancellationAmount": 1500,
              "remainingReversalAmount": 0,
              "description": "Test Purchase",
              "initiatingSystemUserAgent": "PostmanRuntime/3.0.1",
              "userAgent": "Mozilla/5.0...",
              "language": "nb-NO",
              "paymentToken": "5adc265f-f87f-4313-577e-08d3dca1a26c",
              "prices": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/prices"
                },
              "transactions": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/transactions"
                },
              "authorizations": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/authorizations"
                },
              "captures": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/captures"
                },
              "cancellations": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/cancellations"
                },
              "reversals": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/reversals"
                },
              "payeeInfo": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/payeeInfo"
                },
              "urls": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/urls"
                },
              "settings": {
                      "id": "/psp/creditcard/payments/5adc265f-f87f-4313-577e-08d3dca1a26c/settings"
                }
        },
      "operations": [
                {
                      "href": "<capture_operation_url>",
                      "rel": "create-checkout-capture",
                      "method": "POST"
                },
                {
                      "href": "<cancellation_operation_url>",
                      "rel": "create-checkout-cancellation",
                      "method": "POST"
                },
                {
                      "href": "<reversal_operation_url>",
                      "rel": "create-checkout-reversal",
                      "method": "POST"
                }
        ]
}
Perform the capture request:

POST <capture_operation_href> HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: Bearer merchantToken==

{
      "transaction": {
              "description": "description for the transaction"
        }
}

{
      "payment": "<paymentUrl>",
      "capture": {
              "id": "<paymentCaptureUrl>",
              "transaction": {
                      "id": "<transactionUrl>",
                      "created": "2016-09-14T01:01:01.01Z",
                      "updated": "2016-09-14T01:01:01.03Z",
                      "type": "Capture",
                      "state": "Initialized|Completed|Failed",
                      "number": 1234567890,
                      "amount": 1500,
                      "vatAmount": 300,
                      "description": "Test Capture",
                      "payeeReference": "ABC123",
                      "failedReason": "",
                      "isOperational": "TRUE|FALSE",
                      "operations": []
                }
        }
}
As the state property in the response above will indicate, the capture operation should now be Completed, indicating that the payment is captured.

Implementation example
var merchantToken = "<secret merchant token>";
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + merchantToken);

// 1. Retrieve the paymentSessionUrl related to the submitted form from storage.
var paymentSessionUrl = "<retrieved from storage>";

// 2. Retrieve the Payment Session and find the URL of the Payment.
var paymentSessionResponse = await httpClient.GetAsync(paymentSessionUrl);
var paymentSessionContent = await paymentSessionResponse.Content.ReadAsStringAsync();
var paymentSession = Newtonsoft.Json.Linq.JObject.Parse(paymentSessionContent);
var paymentUrl = paymentSession["payment"].ToString();

// 3. Retrieve the Payment and find its 'create-checkout-capture' operation.
var paymentResponse = await httpClient.GetAsync(paymentUrl);
var paymentContent = await paymentResponse.Content.ReadAsStringAsync();
var payment = Newtonsoft.Json.Linq.JObject.Parse(paymentContent);
var captureUrl = payment["operations"]
        .Children()
        .First(x => x["rel"].ToString() == "create-checkout-capture")["href"]
        .ToString();

// 4. Perform the capture request.
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
        transaction = new
        {
                description = "Captured the payment"
        }
});
var captureRequestContent = new StringContent(json, Encoding.UTF8, "application/json");
var captureResponse = await httpClient.PostAsync(captureUrl, captureRequestContent);
var captureResponseContent = await captureResponse.Content.ReadAsStringAsync();
var capture = Newtonsoft.Json.Linq.JObject.Parse(captureResponseContent);
When the above code example is executed, the capture 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.
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.