MOTO is the common term for over-the-phone transactions—for example, speaking to a customer and entering their card details into a virtual terminal or the customer interacting with an Interactive Voice Response system. When flagged correctly, MOTO transactions are deemed as out of scope for the Strong Customer Authentication (SCA) requirements under the Revised PSD2 in Europe and the United Kingdom.
In this article, you’ll learn how to correctly flag a standard MOTO transaction that takes place with the customer present, that is, a customer-initiated transaction (CIT). This transaction does not require 3D Secure 2 authentication. However, if the intent is to store the card to process further merchant-initiated transactions (MITs) via MOTO, you need to make sure to store the brand reference and include the right Credential on File (COF) flags.
Standard MOTO transaction
In this example, we simply process a one-off MOTO transaction without storing the card. As mentioned previously, the transaction does not require a 3D Secure authentication as long as it is flagged correctly as a MOTO payment (entry_mode = "MOTO").
GpApiConfig config = new GpApiConfig();
config.setAppId("AppId");
config.setAppKey("AppKey");
config.setCountry("IE");
config.setChannel(Channel.CardNotPresent.getValue())
config.setEnableLogging(true);
ServicesContainer.configureService(config);
CreditCardData card = new CreditCardData();
card.setNumber("4263970000005262");
card.setExpMonth(DateTime.now().getMonthOfYear());
card.setExpYear(DateTime.now().getYear() + 1);
card.setCardHolderName("James Mason");
card.setCvn("852");
card.setEntryMethod(ManualEntryMethod.Moto);
Address billingAddress = new Address();
billingAddress.setStreetAddress1("Apartment 852");
billingAddress.setStreetAddress2("Complex 741");
billingAddress.setStreetAddress3("House 963");
billingAddress.setCity("Chicago");
billingAddress.setState("IL");
billingAddress.setPostalCode("50001");
billingAddress.setCountryCode("840");
String orderId = UUID.randomUUID().toString();
Transaction response =
card
.charge(1)
.withCurrency("EUR")
.withClientTransactionId(orderId)
.withAddress(billingAddress, AddressType.Billing)
.execute();
String responseCode = response.getResponseCode(); //SUCCESS
String transactionStatus = response.getResponseMessage(); //CAPTURE
String transactionId = response.getTransactionId(); //TRN_Deaf01xuzgCGyaz718x5uGyUNeD7Ck_69143711
$config = new GpApiConfig();
$config->appId = 'AppId';
$config->appKey = 'AppKey';
$config->country = 'IE';
$config->channel = Channel::CardNotPresent;
$config->requestLogger = new SampleRequestLogger(new Logger("logs"));
ServicesContainer::configureService($config);
$card = new CreditCardData();
$card->number = '4263970000005262';
$card->expMonth = '09';
$card->expYear = date('Y', strtotime('+1 year'));
$card->cardHolderName = "James Mason";
$card->cvn = '852';
$card->entryMethod = ManualEntryMethod::MOTO;
$billingAddress = new Address();
$billingAddress->streetAddress1 = "Apartment 852";
$billingAddress->streetAddress2 = "Complex 741";
$billingAddress->streetAddress3 = "House 963";
$billingAddress->city = "Chicago";
$billingAddress->state = "IL";
$billingAddress->postalCode = "50001";
$billingAddress->countryCode = "840";
$orderId = GenerationUtils::generateOrderId();
$response = $card->charge(1)
->withCurrency('EUR')
->withClientTransactionId($orderId)
->withAddress($billingAddress, AddressType::BILLING)
->execute();
$responseCode = $response->responseCode; //SUCCESS
$transactionStatus = $response->responseMessage; //CAPTURE
$transactionId = $response->transactionId; //TRN_Deaf01xuzgCGyaz718x5uGyUNeD7Ck_69143711
GpApiConfig config = new GpApiConfig();
config.AppId = "AppId";
config.AppKey = "AppKey";
config.Country = "IE";
config.Channel = Channel.CardNotPresent;
config.RequestLogger = new RequestConsoleLogger();
ServicesContainer.ConfigureService(config);
CreditCardData card = new CreditCardData();
card.Number = "4263970000005262";
card.ExpMonth = DateTime.Now.Month;
card.ExpYear = DateTime.Now.Year + 1;
card.CardHolderName = "James Mason";
card.Cvn = "852";
card.EntryMethod = ManualEntryMethod.Moto;
Address billingAddress = new Address();
billingAddress.StreetAddress1 = "Apartment 852";
billingAddress.StreetAddress2 = "Complex 741";
billingAddress.StreetAddress3 = "House 963";
billingAddress.City = "Chicago";
billingAddress.State = "IL";
billingAddress.PostalCode = "50001";
billingAddress.CountryCode = "840";
var orderId = Guid.NewGuid().ToString();
var response = card.Charge(1)
.WithCurrency("EUR")
.WithClientTransactionId(orderId)
.WithAddress(billingAddress, AddressType.Billing)
.Execute();
var responseCode = response.ResponseCode; //SUCCESS
var transactionStatus = response.ResponseMessage; //CAPTURE
var transactionId = response.TransactionId; //TRN_Deaf01xuzgCGyaz718x5uGyUNeD7Ck_69143711
curl --location --request POST 'https://apis.sandbox.globalpay.com/ucp/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer oaFwF4Y4KJADG1wfvO4x254F9NEh' \
--header 'Accept: application/json' \
--header 'X-GP-Version: 2021-03-22' \
--data-raw '{
"type": "SALE",
"account_id": "TRA_4d49f5d4e1b84ea4a28c8902a8538375",
"channel": "CNP",
"capture_mode": "AUTO",
"amount": "100",
"currency": "EUR",
"reference": "69143711",
"country": "IE",
"payment_method": {
"first_name": "James",
"last_name": "Mason",
"entry_mode": "MOTO",
"card": {
"number": "4263970000005262",
"expiry_month": "09",
"expiry_year": "22",
"cvv": "852",
"avs_address": "Flat 123",
"avs_postal_code": "50001"
}
}
}'
CIT with COF
In this example, we store the card for future transactions, regardless of whether they are customer-initiated or merchant-initiated. To do this, we include the COF data. We also need to store the brand reference that is returned in the response. For this step, you could also process a verification (Open-To-Buy, or OTB) instead of an authorization.
GpApiConfig config = new GpApiConfig();
config.setAppId("AppId");
config.setAppKey("AppKey");
config.setCountry("IE");
config.setChannel(Channel.CardNotPresent.getValue());
config.setEnableLogging(true);
ServicesContainer.configureService(config);
CreditCardData card = new CreditCardData();
card.setNumber("4263970000005262");
card.setExpMonth(DateTime.now().getMonthOfYear());
card.setExpYear(DateTime.now().getYear() + 1);
card.setCardHolderName("James Mason");
card.setCvn("852");
card.setEntryMethod(ManualEntryMethod.Moto);
Address billingAddress = new Address();
billingAddress.setStreetAddress1("Apartment 852");
billingAddress.setStreetAddress2("Complex 741");
billingAddress.setStreetAddress3("House 963");
billingAddress.setCity("Chicago");
billingAddress.setState("IL");
billingAddress.setPostalCode("50001");
billingAddress.setCountryCode("840");
String orderId = UUID.randomUUID().toString();
StoredCredential storeCredentials = new StoredCredential();
storeCredentials.setInitiator(StoredCredentialInitiator.CardHolder);
storeCredentials.setType(StoredCredentialType.Unscheduled);
storeCredentials.setSequence(StoredCredentialSequence.First);
Transaction response =
card
.charge(1)
.withCurrency("EUR")
.withClientTransactionId(orderId)
.withAddress(billingAddress, AddressType.Billing)
.withStoredCredential(storeCredentials)
.execute();
String responseCode = response.getResponseCode(); //SUCCESS
String transactionStatus = response.getResponseMessage(); //CAPTURE
String transactionId = response.getTransactionId(); //TRN_pxTDkW0duHg6sCfZ7VnJ6pWseaxPdN_99476441
$config = new GpApiConfig();
$config->appId = 'AppId';
$config->appKey = 'AppKey';
$config->country = 'IE';
$config->channel = Channel::CardNotPresent;
ServicesContainer::configureService($config);
$card = new CreditCardData();
$card->number = '4263970000005262';
$card->expMonth = '09';
$card->expYear = date('Y', strtotime('+1 year'));
$card->cardHolderName = "James Mason";
$card->cvn = '852';
$card->entryMethod = ManualEntryMethod::MOTO;
$billingAddress = new Address();
$billingAddress->streetAddress1 = "Apartment 852";
$billingAddress->streetAddress2 = "Complex 741";
$billingAddress->streetAddress3 = "House 963";
$billingAddress->city = "Chicago";
$billingAddress->state = "IL";
$billingAddress->postalCode = "50001";
$billingAddress->countryCode = "840";
$orderId = GenerationUtils::generateOrderId();
$storeCredentials = new StoredCredential();
$storeCredentials->initiator = StoredCredentialInitiator::PAYER;
$storeCredentials->type = StoredCredentialType::UNSCHEDULED;
$storeCredentials->sequence = StoredCredentialSequence::FIRST;
$response = $card->charge(1)
->withCurrency('EUR')
->withClientTransactionId($orderId)
->withAddress($billingAddress, AddressType::BILLING)
->withStoredCredential($storeCredentials)
->execute();
$responseCode = $response->responseCode; //SUCCESS
$transactionStatus = $response->responseMessage; //CAPTURE
$transactionId = $response->transactionId; //TRN_pxTDkW0duHg6sCfZ7VnJ6pWseaxPdN_99476441
GpApiConfig config = new GpApiConfig();
config.AppId = "AppId";
config.AppKey = "AppKey";
config.Country = "IE";
config.Channel = Channel.CardNotPresent;
config.RequestLogger = new RequestConsoleLogger();
ServicesContainer.ConfigureService(config);
CreditCardData card = new CreditCardData();
card.Number = "4263970000005262";
card.ExpMonth = DateTime.Now.Month;
card.ExpYear = DateTime.Now.Year + 1;
card.CardHolderName = "James Mason";
card.Cvn = "852";
card.EntryMethod = ManualEntryMethod.Moto;
Address billingAddress = new Address();
billingAddress.StreetAddress1 = "Apartment 852";
billingAddress.StreetAddress2 = "Complex 741";
billingAddress.StreetAddress3 = "House 963";
billingAddress.City = "Chicago";
billingAddress.State = "IL";
billingAddress.PostalCode = "50001";
billingAddress.CountryCode = "840";
var orderId = Guid.NewGuid().ToString();
StoredCredential storeCredentials = new StoredCredential();
storeCredentials.Initiator = StoredCredentialInitiator.CardHolder;
storeCredentials.Type = StoredCredentialType.Unscheduled;
storeCredentials.Sequence = StoredCredentialSequence.First;
var response = card.Charge(1)
.WithCurrency("EUR")
.WithClientTransactionId(orderId)
.WithAddress(billingAddress, AddressType.Billing)
.WithStoredCredential(storeCredentials)
.Execute();
var responseCode = response.ResponseCode; //SUCCESS
var transactionStatus = response.ResponseMessage; //CAPTURE
var transactionId = response.TransactionId; //TRN_pxTDkW0duHg6sCfZ7VnJ6pWseaxPdN_99476441
curl --location --request POST 'https://apis.sandbox.globalpay.com/ucp/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer oaFwF4Y4KJADG1wfvO4x254F9NEh' \
--header 'Accept: application/json' \
--header 'X-GP-Version: 2021-03-22' \
--data-raw '{
"type": "SALE",
"account_id": "TRA_4d49f5d4e1b84ea4a28c8902a8538375",
"channel": "CNP",
"capture_mode": "AUTO",
"amount": "100",
"currency": "EUR",
"reference": "99476441",
"country": "IE",
"initiator": "PAYER",
"stored_credential": {
"model": "UNSCHEDULED",
"sequence": "FIRST"
},
"payment_method": {
"first_name": "James",
"last_name": "Mason",
"entry_mode": "MOTO",
"card": {
"number": "4263970000005262",
"expiry_month": "09",
"expiry_year": "22",
"cvv": "852",
"avs_address": "Flat 123",
"avs_postal_code": "50001"
}
}
}'