Newer Version Available

This content describes an older version of this product. View Latest

Building a Synchronous Gateway Adapter

In synchronous payment configurations, the Salesforce payment platform sends transaction information to the gateway, and then waits for a gateway response that contains the final transaction status. Salesforce creates a transaction only if the transaction is successful in the gateway.

A synchronous gateway adapter implements the PaymentGatewayAdapter Interface. In this topic, we examine a sample synchronous adapter by looking at PaymentGatewayAdapter, and then the processRequest method, which drives most of the communication between the payment platform and the payment gateway.

Payment gateway adapters can’t make future calls, external callouts using System.Http, asynchronous calls, queueable calls, or execute DMLs using SOQL.

Note

PaymentGatewayAdapter

All synchronous gateways must implement the PaymentGatewayAdapter interface. All PaymentGatewayAdapters are required to implement the processRequest method.
1global with sharing class SampleAdapter implements commercepayments.PaymentGatewayAdapter {
2    global SampleAdapter() {}
3    
4    global commercepayments.GatewayResponse processRequest(commercepayments.paymentGatewayContext gatewayContext) {
5    }
6}

Processing an Initial Payment Request

When the payments platform receives a payments API request, it passes the request to your gateway adapter for further evaluation. The adapter begins the request evaluation process by calling the processRequest method, which represents the first step in a synchronous payment flow. We can break the processRequest implementation into three parts.

First, it builds a payment request object that the gateway can understand.

1commercepayments.RequestType requestType = gatewayContext.getPaymentRequestType();
2if (requestType == commercepayments.RequestType.Capture) {
3   req.setEndpoint('/pal/servlet/Payment/v52/capture');
4    body = buildCaptureRequest((commercepayments.CaptureRequest)gatewayContext.getPaymentRequest());
5} else if (requestType == commercepayments.RequestType.ReferencedRefund) {
6    req.setEndpoint('/pal/servlet/Payment/v52/refund');
7    body = buildRefundRequest((commercepayments.ReferencedRefundRequest)gatewayContext.getPaymentRequest());
8}

We don't recommend encoding the request body, which contains the merge fields, including the card number and CVV. This can cause the request to fail to read the encoded request body and to fail to replace the merge field values.

Note

Then, the adapter sends the request to the payment gateway.

1req.setBody(body);
2req.setMethod('POST');
3commercepayments.PaymentsHttp http = new commercepayments.PaymentsHttp();
4HttpResponse res = null;
5try {
6    res = http.send(req);
7} catch(CalloutException ce) {
8    commercepayments.GatewayErrorResponse error = new commercepayments.GatewayErrorResponse('500', ce.getMessage());
9    return error;
10}
Finally, the adapter creates a response object to store data from the gateway’s response. The type of response object varies based on whether you originally made a payment capture request or a refund request.
1if ( requestType == commercepayments.RequestType.Capture) {
2   // Refer to the end of this doc for sample createCaptureResponse implementation
3    response =  createCaptureResponse(res);
4} else if ( requestType == commercepayments.RequestType.ReferencedRefund) {
5    response =  createRefundResponse(res);
6}
7return response;

Using Custom Data

To transfer additional, custom data from the frontend to your payment gateway adapter, use the Checkout Payments Connect API. Sending custom data to the adapter supports use cases like implementing conditional logic based on specific data or mapping asynchronous webhook events to a cart by passing an identifier.

To send custom data to your payment gateway adapter, use the paymentsData parameter in the Checkout Payments Connect API input payload. This parameter is a serialized map of type <String, String> that supports up to four key-value pairs. Each key and each value can contain up to 255 characters. paymentsData is only applicable to Auth and PostAuth payment requests. Simple purchase orders don’t support paymentsData.

Similarly, the Post Authorization input payload has an additionalData property, which is also a map of type<String, String>. The paymentsData property is accepted for Auth and PostAuth requests and is transferred to the Payment APIs through the additionalData property.