cancel
Showing results for 
Search instead for 
Did you mean: 

The element 'subscription' has invalid child element 'customer'

Error E00003 The element 'subscription' in namespace 'AnetApi/sml/v1/schema/AnetApiSchema.xsd' has invalid child element 'cusotmer' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. List of possible elements expected: 'shipTo', profile' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'.

 

Getting this error when trying to add an ARB subscription. We're not using profiles, but according to the API docs, "customer" should be a valid sub element of "subscription".

 

https://developer.authorize.net/api/reference/#recurring-billing-create-a-subscription

 

Full code:

<?php
  ...
  public function create_subscription($transaction) {
    global $custom_options;

    if(isset($transaction) and $transaction instanceof Transaction) {
      $usr = $transaction->user();
      $prd = $transaction->product();
      $sub = $transaction->subscription();
    }
    else {
      throw new CustomGatewayException( 'Payment was unsuccessful, please check your payment details and try again.' );
    }

    $invoice = $this->create_new_order_invoice($sub);

    // Default to 9999 for infinite occurrences
    $total_occurrences = $sub->limit_cycles ? $sub->limit_cycles_num : 9999;

    $args = array( "refId" => $invoice,
                   "subscription" => array(
                     "name" => $prd->post_title,
                     "paymentSchedule" => array(
                       "interval" => $this->arb_subscription_interval($sub),
                       "startDate" => Utils::get_date_from_ts((time() + (($sub->trial)?Utils::days($sub->trial_days):0)), 'Y-m-d'),
                       "totalOccurrences" => $total_occurrences,
                     ),
                     "amount" => Utils::format_float($sub->total),
                     "payment" => array(
                       "creditCard" => array(
                         "cardNumber" => sanitize_text_field($_POST['custom_cc_num']),
                         "expirationDate" => sanitize_text_field($_POST['custom_cc_exp_month']) . '-' . sanitize_text_field($_POST['custom_cc_exp_year']),
                         "cardCode" => sanitize_text_field($_POST['custom_cvv_code'])
                       )
                     ),
                     "order" => array(
                       "invoiceNumber" => $invoice,
                       "description" => $prd->post_title
                     ),
                     "billTo" => array(
                       "firstName" => $usr->first_name,
                       "lastName" => $usr->last_name
                     ),
                     "customer" => array(
                       "email" => $usr->user_email
                     )
                   )
                 );

    if($custom_options->show_address_fields && $custom_options->require_address_fields) {
      $args['subscription']['billTo'] =
        array_merge($args['subscription']['billTo'],
                    array("address" => str_replace('&', '&amp;', get_user_meta($usr->ID, 'custom-address-one', true)),
                          "city"    => get_user_meta($usr->ID, 'custom-address-city', true),
                          "state"   => get_user_meta($usr->ID, 'custom-address-state', true),
                          "zip"     => get_user_meta($usr->ID, 'custom-address-zip', true),
                          "country" => get_user_meta($usr->ID, 'custom-address-country', true)));
    }

    $res = $this->send_arb_request('ARBCreateSubscriptionRequest', $args);
    ...
  
  protected function send_arb_request($method, $args, $http_method = 'post') {
    $args = array_merge(
      array(
        "merchantAuthentication" => array(
          "name" => $this->settings->login_name,
          "transactionKey" => $this->settings->transaction_key
        )
      ),
      $args
    );

    $content = $this->arb_array_to_xml($method, $args);

    $remote_array = array('method' => strtoupper($http_method),
                          'timeout' => 30,
                          'redirection' => 5,
                          'httpversion' => '1.0',
                          'blocking' => true,
                          'headers' => array('content-type' => 'application/xml'),
                          'body' => $content,
                          'cookies' => array());

    $response = wp_remote_post('https://api2.authorize.net/xml/v1/request.api', $remote_array);
    ...

Is the (https://api2.authorize.net/xml/v1/request.api) endpoint the problem?

 

Thanks for any help!

cartpauj
Contributor
20 REPLIES 20

Are you using the API endpoints? Or do you do this through SIM?

@Renaissance we do not create a customer object. We're creating a subscription via ARB and trying to send the customer email address is all.

cartpauj
Contributor

@cartpaujthat is your problem.

The customer property of the request only accepts customer type objects. This is through SIM/DPM or through the modern API?

We use ARBCreateSubscriptionRequest

 

The code from the OP is exactly how we're doing it.  It works fine if we remove the customer -> email from the data.

@cartpauj 

 

That can't be the whole picture. All of those properties have to be assigned to objects.  Your function where you pass your arguments may not have a place for the customer object. I am not good with XML but if you are using php code through the API with that function, they have to be passed as objects.  Copy and paste the function definition that is doing the ARBCreateSubscriptionRequest. The one that you pass the $args array to. 

It's the second function in the OP code that sends the request (using WordPress Request API).

 

This was written probably back in 2013 using the XML api, so it is definitely old.

 

It works fine except in the rare case where we need to send an email address along with the subscription data.

 

The $args get converted to XML in this function:

 

  protected function arb_array_to_xml($method, $array, $level=0) {
    if($level==0) {
      $xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
      $xml .= "<{$method} xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">\n";
    }
    else
      $xml = '';

    foreach($array as $key => $value ) {
      // Print indentions
      for($i=0; $i < $level+1; $i++) { $xml .= "  "; }

      // Print open tag (looks like we don't need
      // to worry about attributes with this schema)
      $xml .= "<{$key}>";

      // Print value or recursively render sub arrays
      if(is_array($value)) {
        $xml .= "\n";
        $xml .= $this->arb_array_to_xml($method,$value,$level+1);
        // Print indentions for end tag
        for($i=0; $i < $level+1; $i++) { $xml .= "  "; }
      }
      else
        $xml .= $value;

      // Print End tag
      $xml .= "</{$key}>\n";
    }

    if($level==0)
      $xml .= "</{$method}>\n";

    return $xml;
  }

 

 

@cartpauj 

 

So you are creating XML with that. In your code below, I think it is the customer and billTo properties being out of order.  

 

 

 $args = array( "refId" => $invoice,
                   "subscription" => array(
                     "name" => $prd->post_title,
                     "paymentSchedule" => array(
                       "interval" => $this->arb_subscription_interval($sub),
                       "startDate" => Utils::get_date_from_ts((time() + (($sub->trial)?Utils::days($sub->trial_days):0)), 'Y-m-d'),
                       "totalOccurrences" => $total_occurrences,
                     ),
                     "amount" => Utils::format_float($sub->total),
                     "payment" => array(
                       "creditCard" => array(
                         "cardNumber" => sanitize_text_field($_POST['custom_cc_num']),
                         "expirationDate" => sanitize_text_field($_POST['custom_cc_exp_month']) . '-' . sanitize_text_field($_POST['custom_cc_exp_year']),
                         "cardCode" => sanitize_text_field($_POST['custom_cvv_code'])
                       )
                     ),
                     "order" => array(
                       "invoiceNumber" => $invoice,
                       "description" => $prd->post_title
                     ),
                     "billTo" => array(
                       "firstName" => $usr->first_name,
                       "lastName" => $usr->last_name
                     ),
                     "customer" => array(
                       "email" => $usr->user_email
                     )
                   )
                 );

 

 you are getting this error:

 

 error E00003 The element 'subscription' in namespace 'AnetApi/sml/v1/schema/AnetApiSchema.xsd' has invalid child element 'customer' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. List of possible elements expected: 'shipTo', profile' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'.

 

Because the next child element following billTo is shipTo, but your request gives customer. Put customer after order and billTo after customer and it should work. 

If that does it, please kindly mark this thread as solved. Just an FYI, if you use the sample code and php SDK package, you never run into this issue.  Your request is aligned with the schema for you no matter what you do. You should try it. 

I will test that now and update this if that resolves it. I was not aware the order would matter either.

 

Yes, we are in need of a complete rewrite at this point :)

 

Hopefully this isn't against forum rules, but @Renaissance are you available off-forums anywhere for consulting/development work?

 

I'll follow up soon.

@cartpauj 

 

I will be in the auth.net certified developer program soon.  Feel free to IM me on this website if you need additional help. Click my name then click send this user a private message.