In-App Payments SDK: Cookbook

Connect to a Backend Service

Connect a mobile app using the In-App Payments SDK to a server backend.

Android
iOS
Backend
In-App Payments SDK
Payments API
Java (Android)

Step 1: Set up a connection to a payment processing backend
Permalink Get a link to this section

To validate and process the nonce returned by the SDK CardEntry object, you must send it to a backend service that uses Connect payment APIs to capture payment.

To set up the backend connection, build a Retrofit object and configure it with the base URL for your backend service:

public class ConfigHelper {

  private static final String CHARGE_SERVER_HOST = "REPLACE_ME";
  private static final String CHARGE_SERVER_URL = "https://" + CHARGE_SERVER_HOST + "/";

  public static boolean serverHostSet() {
    return !CHARGE_SERVER_HOST.equals("REPLACE_ME");
  }

  public static Retrofit createRetrofitInstance() {
    return new Retrofit
        .Builder()
        .baseUrl(ConfigHelper.CHARGE_SERVER_URL)
        .addConverterFactory(MoshiConverterFactory.create())
        .build();
  }
}

Step 2: Define a REST interface for POST requests
Permalink Get a link to this section

public interface ChargeService {
  @POST("/chargePaymentCard")
  Call<Void> charge(@Body ChargeRequest request);

  class ChargeErrorResponse {
    String errorMessage;
  }

  class ChargeRequest {
    final String nonce;

    ChargeRequest(String nonce) {
      this.nonce = nonce;
    }
  }
}

Step 3: Make calls with the REST interface
Permalink Get a link to this section

To use your REST interface, create a Call<ChargeResult> implementation that will package and send requests to the payment processing backend:

public class ChargeCall implements Call<ChargeResult> {

  public static class Factory {
    private final ChargeService service;
    private final Converter<ResponseBody, ChargeService.ChargeErrorResponse> errorConverter;

    public Factory(Retrofit retrofit) {
      service = retrofit.create(ChargeService.class);
      Annotation[] noAnnotations = {};
      Type errorResponseType = ChargeService.ChargeErrorResponse.class;
      errorConverter = retrofit.responseBodyConverter(errorResponseType, noAnnotations);
    }

    public Call<ChargeResult> create(String nonce) {
      return new ChargeCall(this, nonce);
    }
  }

  private final ChargeCall.Factory factory;
  private final String nonce;
  private final retrofit2.Call<Void> call;

  private ChargeCall(ChargeCall.Factory factory,
      String nonce) {
    this.factory = factory;
    this.nonce = nonce;
    call = factory.service.charge(new ChargeService.ChargeRequest(nonce));
  }

  @Override
  public ChargeResult execute() {
    Response<Void> response;
    try {
      response = call.execute();
    } catch (IOException e) {
      return ChargeResult.networkError();
    }
    return responseToResult(response);
  }

  @Override
  public void enqueue(sqip.Callback<ChargeResult> callback) {
    call.enqueue(new Callback<Void>() {
      @Override
      public void onResponse(@NonNull retrofit2.Call<Void> call, @NonNull Response<Void> response) {
        callback.onResult(responseToResult(response));
      }

      @Override
      public void onFailure(@NonNull retrofit2.Call<Void> call, Throwable throwable) {
        if (throwable instanceof IOException) {
          callback.onResult(ChargeResult.networkError());
        } else {
          throw new RuntimeException("Unexpected exception", throwable);
        }
      }
    });
  }

  //TODO: Define the ChargeResult method in step 4.//additional required Call<ChargeResult> methods
}

Step 4: Handle the backend results
Permalink Get a link to this section

Define a ChargeResult object and act on the results:

private ChargeResult responseToResult(Response<Void> response) {
  if (response.isSuccessful()) {
    return ChargeResult.success();
  }
  try {
    //noinspection ConstantConditions
    ResponseBody errorBody = response.errorBody();
    ChargeService.ChargeErrorResponse errorResponse = factory.errorConverter.convert(errorBody);
    return ChargeResult.error(errorResponse.errorMessage);
  } catch (IOException exception) {
    return ChargeResult.networkError();
  }
}