cancel
Showing results for 
Search instead for 
Did you mean: 

E00114 - "Invalid OTS Token." in Node, but works through the API Live Console

Hi,

 

Scenario: Using Accept.js to get opaque data which is then used on a Node server to create a subscription.

Problem: Everytime I get an "Invalid OTS Token." response, but if I try the exact same JSON request at https://developer.authorize.net/api/reference/index.html#recurring-billing-create-a-subscription, then it succeeds.

Question: What could be the problem? I assume it's not the payload, nor that it's sent multiple times as it works the second time in the API live console. But what else could it be?

 

My code:

function createSubscription(req, res) {
  const { opaqueDataDescriptor, opaqueDataValue } = req.body;

  const merchantAuthenticationType = new ApiContracts.MerchantAuthenticationType();

  merchantAuthenticationType.setName(config.authorizeNet.loginId);
  merchantAuthenticationType.setTransactionKey(config.authorizeNet.transactionKey);

  const interval = new ApiContracts.PaymentScheduleType.Interval();

  interval.setLength(3);
  interval.setUnit(ApiContracts.ARBSubscriptionUnitEnum.MONTHS);

  const paymentScheduleType = new ApiContracts.PaymentScheduleType();

  paymentScheduleType.setInterval(interval);
  paymentScheduleType.setStartDate((new Date()).toISOString().substring(0, 10));
  paymentScheduleType.setTotalOccurrences(9999);
  paymentScheduleType.setTrialOccurrences(1);

  const opaqueDataType = new ApiContracts.OpaqueDataType();

  opaqueDataType.setDataDescriptor(opaqueDataDescriptor);
  opaqueDataType.setDataValue(opaqueDataValue);

  const paymentType = new ApiContracts.PaymentType();

  paymentType.setOpaqueData(opaqueDataType);

  const customer = new ApiContracts.CustomerType();

  customer.setType(ApiContracts.CustomerTypeEnum.BUSINESS);
  customer.setEmail('testUser@example.com');

  const nameAndAddressType = new ApiContracts.NameAndAddressType();

  nameAndAddressType.setFirstName('Test');
  nameAndAddressType.setLastName('User');

  const arbSubscriptionType = new ApiContracts.ARBSubscriptionType();

  arbSubscriptionType.setName('fullQuarterly');
  arbSubscriptionType.setPaymentSchedule(paymentScheduleType);
  arbSubscriptionType.setAmount(225);
  arbSubscriptionType.setTrialAmount(150);
  arbSubscriptionType.setPayment(paymentType);
  arbSubscriptionType.setCustomer(customer);
  arbSubscriptionType.setBillTo(nameAndAddressType);

  const createRequest = new ApiContracts.ARBCreateSubscriptionRequest();

  createRequest.setMerchantAuthentication(merchantAuthenticationType);
  createRequest.setSubscription(arbSubscriptionType);

  console.log(JSON.stringify(createRequest.getJSON(), null, 2));
  const ctrl = new ApiControllers.ARBCreateSubscriptionController(createRequest.getJSON());

  ctrl.execute(() => {
    const apiResponse = ctrl.getResponse(),
          response = new ApiContracts.ARBCreateSubscriptionResponse(apiResponse);

    logger.info('[authorize.net] Create Subscription Response:\n', JSON.stringify(response));
  });
}

And the logs (first the request that is to be sent, which I then grabbed and tried in the API console. Second is the response I got in Node):

{
  "ARBCreateSubscriptionRequest": {
    "merchantAuthentication": {
      "name": "mySandboxName",
      "transactionKey": "mySandboxKey"
    },
    "clientId": null,
    "subscription": {
      "name": "fullQuarterly",
      "paymentSchedule": {
        "interval": {
          "length": 3,
          "unit": "months"
        },
        "startDate": "2019-11-26",
        "totalOccurrences": 9999,
        "trialOccurrences": 1
      },
      "amount": 225,
      "trialAmount": 150,
      "payment": {
        "opaqueData": {
          "dataDescriptor": "COMMON.ACCEPT.INAPP.PAYMENT",
          "dataValue": "eyJjb2RlIjoiNTBfMl8wNjAwMDUzQTk5NkZEMjNCQTUwQjIwMUZDQzRFNTU0ODJFM0U5QTNBQ0I4RDNCNTJCMkVGQUVEMjFDRTY3RDlBODg2QUMyRTlDM0EyNzE0Njk4QjFENjA2NDc2NDM0RUFGMDkyREE1IiwidG9rZW4iOiI5NTc0NzQyOTM0NDA3Njc1MDAzNjAyIiwidiI6IjEuMSJ9"
        }
      },
      "customer": {
        "type": "business",
        "email": "testUser@example.com"
      },
      "billTo": {
        "firstName": "Test",
        "lastName": "User"
      }
    }
  }
}

info: [authorize.net] Create Subscription Response: {"messages":{"resultCode":"Error","message":[{"code":"E00114","text":"Invalid OTS Token."}]}}

Live console response:

													
{
    "subscriptionId": "6165150",
    "profile": {
        "customerProfileId": "1921875673",
        "customerPaymentProfileId": "1834822332"
    },
    "messages": {
        "resultCode": "Ok",
        "message": [
            {
                "code": "I00001",
                "text": "Successful."
            }
        ]
    }
}
Chee7ah
Member
2 REPLIES 2

Still have no idea what's wrong here, but a different approach worked.

1. Created a customer profile with a customer paypment profile first with the opaque data

2. Created a subscription with the new customer profile and customer payment profile ids.

 

One catch I ran into: Apparently it takes like 10 seconds for the payment profile to be available for subscriptions. After creation I could immediately make a request to validate it and it succeeds. But creating a subscription fails with E00040 - The record cannot be found. As a workaround added some retry logic to keep trying and after about 10 sec it succeeds...

Chee7ah
Member

Hi Chee7ah

 

Creating a subscription automatically creates a Customer Profile. Unless there is a particular reason that you want to do both separately, my recommendation would be to simply create the subscription and log the profile created when it is returned in the ARBCreateSubscriptionResponse. 

 

Regards,

Elaine