diff --git a/core/src/main/java/com/hyperwallet/android/Hyperwallet.java b/core/src/main/java/com/hyperwallet/android/Hyperwallet.java
index d0eecf36..156182e7 100644
--- a/core/src/main/java/com/hyperwallet/android/Hyperwallet.java
+++ b/core/src/main/java/com/hyperwallet/android/Hyperwallet.java
@@ -203,6 +203,30 @@ public void createBankCard(@NonNull final HyperwalletBankCard bankCard,
performRestTransaction(builder, listener);
}
+ /**
+ * Creates a {@link PayPalAccount} for the User associated with the authentication token returned from
+ * {@link HyperwalletAuthenticationTokenProvider#retrieveAuthenticationToken(HyperwalletAuthenticationTokenListener)}.
+ *
+ *
The {@link HyperwalletListener} that is passed in to this method invocation will receive the responses from
+ * * processing the request.
+ *
+ * This function will requests a new authentication token via {@link HyperwalletAuthenticationTokenProvider}
+ * if the current one is expired or about to expire.
+ *
+ * @param payPalAccount the {@code PayPalAccount} to be created; must not be null
+ * @param listener the callback handler of responses from the Hyperwallet platform; must not be null
+ */
+ public void createPayPalAccount(@NonNull final PayPalAccount payPalAccount,
+ @NonNull final HyperwalletListener listener) {
+ PathFormatter pathFormatter = new PathFormatter("users/{0}/paypal-accounts");
+
+ RestTransaction.Builder builder = new RestTransaction.Builder<>(POST, pathFormatter,
+ new TypeReference() {
+ }, listener).jsonModel(payPalAccount);
+
+ performRestTransaction(builder, listener);
+ }
+
/**
* Returns the {@link HyperwalletBankAccount} linked to the transfer method token specified, or null if none exists.
*
diff --git a/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java b/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java
index 27b1182e..cdb9fe55 100644
--- a/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java
+++ b/core/src/test/java/com/hyperwallet/android/HyperwalletTestSuite.java
@@ -3,6 +3,7 @@
import com.hyperwallet.android.model.meta.HyperwalletRetrieveTransferMethodConfigurationFieldsTest;
import com.hyperwallet.android.transfermethod.HyperwalletCreateBankAccountTest;
import com.hyperwallet.android.transfermethod.HyperwalletCreateBankCardTest;
+import com.hyperwallet.android.transfermethod.HyperwalletCreatePayPalAccountTest;
import com.hyperwallet.android.transfermethod.HyperwalletDeactivateBankAccountTest;
import com.hyperwallet.android.transfermethod.HyperwalletDeactivateBankCardTest;
import com.hyperwallet.android.transfermethod.HyperwalletGetBankAccountTest;
@@ -23,6 +24,7 @@
HyperwalletCreateBankAccountTest.class,
HyperwalletListBankAccountsTest.class,
HyperwalletCreateBankCardTest.class,
+ HyperwalletCreatePayPalAccountTest.class,
HyperwalletGetBankAccountTest.class,
HyperwalletGetBankCardTest.class,
HyperwalletUpdateBankAccountTest.class,
diff --git a/core/src/test/java/com/hyperwallet/android/transfermethod/HyperwalletCreatePayPalAccountTest.java b/core/src/test/java/com/hyperwallet/android/transfermethod/HyperwalletCreatePayPalAccountTest.java
new file mode 100644
index 00000000..eec9cb27
--- /dev/null
+++ b/core/src/test/java/com/hyperwallet/android/transfermethod/HyperwalletCreatePayPalAccountTest.java
@@ -0,0 +1,140 @@
+package com.hyperwallet.android.transfermethod;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import static com.hyperwallet.android.model.HyperwalletStatusTransition.StatusDefinition.ACTIVATED;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.CREATED_ON;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.EMAIL;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.STATUS;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TOKEN;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_COUNTRY;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TRANSFER_METHOD_CURRENCY;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodFields.TYPE;
+import static com.hyperwallet.android.model.HyperwalletTransferMethod.TransferMethodTypes.PAYPAL_ACCOUNT;
+
+import com.hyperwallet.android.Hyperwallet;
+import com.hyperwallet.android.exception.HyperwalletException;
+import com.hyperwallet.android.listener.HyperwalletListener;
+import com.hyperwallet.android.model.HyperwalletError;
+import com.hyperwallet.android.model.HyperwalletErrors;
+import com.hyperwallet.android.model.PayPalAccount;
+import com.hyperwallet.android.rule.HyperwalletExternalResourceManager;
+import com.hyperwallet.android.rule.HyperwalletMockWebServer;
+import com.hyperwallet.android.rule.HyperwalletSdkMock;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+import java.net.HttpURLConnection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.mockwebserver.RecordedRequest;
+
+@RunWith(RobolectricTestRunner.class)
+public class HyperwalletCreatePayPalAccountTest {
+ @Rule
+ public HyperwalletMockWebServer mServer = new HyperwalletMockWebServer();
+ @Rule
+ public HyperwalletSdkMock mSdkMock = new HyperwalletSdkMock(mServer);
+ @Rule
+ public HyperwalletExternalResourceManager mExternalResourceManager = new HyperwalletExternalResourceManager();
+ @Rule
+ public MockitoRule mMockito = MockitoJUnit.rule();
+
+ @Mock
+ private HyperwalletListener mListener;
+
+ @Captor
+ private ArgumentCaptor mPayPalAccountCaptor;
+ @Captor
+ private ArgumentCaptor mExceptionCaptor;
+
+ private final CountDownLatch mAwait = new CountDownLatch(1);
+
+ @Test
+ public void testCreatePayPalAccount_withSuccess() throws InterruptedException {
+
+ String responseBody = mExternalResourceManager.getResourceContent("paypal_account_response.json");
+ mServer.mockResponse().withHttpResponseCode(HttpURLConnection.HTTP_CREATED).withBody(responseBody).mock();
+
+ final PayPalAccount.Builder builder = new PayPalAccount
+ .Builder("US", "USD", "jsmith@paypal.com")
+ .token("trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b");
+
+ final PayPalAccount payPalAccount = builder.build();
+
+ assertThat(payPalAccount.getField(TRANSFER_METHOD_COUNTRY), is("US"));
+ assertThat(payPalAccount.getField(TRANSFER_METHOD_CURRENCY), is("USD"));
+ assertThat(payPalAccount.getField(EMAIL), is("jsmith@paypal.com"));
+ assertThat(payPalAccount.getField(TOKEN), is("trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b"));
+
+
+ Hyperwallet.getDefault().createPayPalAccount(payPalAccount, mListener);
+ mAwait.await(50, TimeUnit.MILLISECONDS);
+
+ RecordedRequest recordedRequest = mServer.getRequest();
+ verify(mListener).onSuccess(mPayPalAccountCaptor.capture());
+ verify(mListener, never()).onFailure(any(HyperwalletException.class));
+
+ PayPalAccount paypalAccountResponse = mPayPalAccountCaptor.getValue();
+ assertThat(paypalAccountResponse, is(notNullValue()));
+
+ //paypal account info
+ assertThat(recordedRequest.getPath(),
+ is("/rest/v3/users/usr-fbfd5848-60d0-43c5-8462-099c959b49c7/paypal-accounts"));
+
+ assertThat(paypalAccountResponse.getField(STATUS), is(ACTIVATED));
+ assertThat(paypalAccountResponse.getField(TOKEN), is("trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b"));
+ assertThat(paypalAccountResponse.getField(TRANSFER_METHOD_COUNTRY), is("US"));
+ assertThat(paypalAccountResponse.getField(TRANSFER_METHOD_CURRENCY), is("USD"));
+ assertThat(paypalAccountResponse.getField(TYPE), is(PAYPAL_ACCOUNT));
+ assertThat(paypalAccountResponse.getField(CREATED_ON), is(notNullValue()));
+ assertThat(paypalAccountResponse.getField(EMAIL), is("jsmith@paypal.com"));
+ }
+
+ @Test
+ public void testCreatePayPalAccount_withValidationError() throws InterruptedException {
+ String responseBody = mExternalResourceManager.getResourceContentError("transfer_method_error_response.json");
+ mServer.mockResponse().withHttpResponseCode(HttpURLConnection.HTTP_BAD_REQUEST).withBody(responseBody).mock();
+
+ final PayPalAccount payPalAccount = new PayPalAccount
+ .Builder("", "USD", "jsmith@paypal.com")
+ .token("trm-ac5727ac-8fe7-42fb-b69d-977ebdd7b48b")
+ .build();
+
+ Hyperwallet.getDefault().createPayPalAccount(payPalAccount, mListener);
+ mAwait.await(50, TimeUnit.MILLISECONDS);
+
+ RecordedRequest recordedRequest = mServer.getRequest();
+ verify(mListener, never()).onSuccess(any(PayPalAccount.class));
+ verify(mListener).onFailure(mExceptionCaptor.capture());
+
+ HyperwalletException hyperwalletException = mExceptionCaptor.getValue();
+ assertThat(hyperwalletException, is(notNullValue()));
+
+ assertThat(recordedRequest.getPath(),
+ is("/rest/v3/users/usr-fbfd5848-60d0-43c5-8462-099c959b49c7/paypal-accounts"));
+
+ HyperwalletErrors hyperwalletErrors = hyperwalletException.getHyperwalletErrors();
+ assertThat(hyperwalletErrors.getErrors(), hasSize(1));
+
+ HyperwalletError hyperwalletError = hyperwalletErrors.getErrors().get(0);
+ assertThat(hyperwalletError.getCode(), is("CONSTRAINT_VIOLATIONS"));
+ assertThat(hyperwalletError.getFieldName(), is("transferMethodCountry"));
+ assertThat(hyperwalletError.getMessage(), is("You must provide a value for this field"));
+ }
+}