Re: VCPE Enrollment Error 9501 Invalid input found, please correct the input data

kevinotto
New Contributor

VCPE Enrollment Error 9501 Invalid input found, please correct the input data

I'm trying to reach https://sandbox.api.visa.com/vcpe/v2/pan/enrollment but I'm getting a 400 error with the message "Invalid input found, please correct the input data". I'm able to reach the helloworld endpoint so my certs should be correct. I'm also using MLE for my payload.

 

Request Header:

Array
(
    [0] => HTTP/1.1 400
    [Server] => nginx
    [Date] => Sun, 10 Mar 2024 20:25:16 GMT
    [Content-Type] => application/json
    [Content-Length] => 141
    [Connection] => keep-alive
    [X-SERVED-BY] => -5b54b9f6-8z9
    [X-CORRELATION-ID] => 1710102316_720_1021519755_-5b54b9f6-8z9_VDP_WS
    [x-vdp-normalized-url] => /vcpe/v2/pan/enrollment
    [X-Frame-Options] => SAMEORIGIN
    [X-XSS-Protection] => 0
    [X-Content-Type-Options] => nosniff
    [Strict-Transport-Security] => max-age=31536000;includeSubdomains
    [Cache-Control] => no-cache, no-store, must-revalidate
    [Pragma] => no-cache
    [Expires] => -1
    [X-APP-STATUS] => 400
)

Response Body:

{
  "responseStatus": {
    "code": "9501",
    "severity": "ERROR",
    "message": "Invalid input found, please correct the input data",
    "info": "",
    "status": "400"
  }
}

 

This is my php code:

<?php

include_once __DIR__ . '/../vendor/autoload.php';

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128GCM;
use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP256;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEBuilder;
use Jose\Component\Encryption\JWEDecrypter;
use Jose\Component\Encryption\JWELoader;
use Jose\Component\Encryption\Serializer\CompactSerializer;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Component\KeyManagement\JWKFactory;

$username = '<MY USERNAME>';
$password = '<MY PASSWORD>';
$client_cert = '../private/client-certificate.cer';
$private_key = '../private/dune-private-key.cer';

$mleClientPrivateKeyPath        = '../private/mle-private.cer';
$mleClientPublicCertificatePath = '../private/mle-client_cert_e95167294fec.cer';
$mleServerPublicCertificatePath = '../private/mle-server_cert_e95167294fec.cer';
$keyId                          = '<MY MLE KEY ID>';


/**
 * This method will encrypt the payload and create a JWE token
 *
 * @param $payload
 * @param $keyId
 * @param $mleServerPublicCertificatePath
 * @return false|string
 */
function encryptPayload($payload, $keyId, $mleServerPublicCertificatePath)
{

    // The key encryption algorithm manager with the RSA-OAEP-256 algorithm.
    $keyEncryptionAlgorithmManager = new AlgorithmManager([new RSAOAEP256(),]);

    // The content encryption algorithm manager with the A128GCM algorithm.
    $contentEncryptionAlgorithmManager = new AlgorithmManager([new A128GCM(),]);

    // The compression method manager with the DEF (Deflate) method.
    $compressionMethodManager = new CompressionMethodManager([new Deflate(),]);

    // We instantiate our JWE Builder.
    $jweBuilder = new JWEBuilder($keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager, $compressionMethodManager);

    // Our key.
    $jwk = JWKFactory::createFromCertificateFile($mleServerPublicCertificatePath);

    $milliseconds = round(microtime(true) * 1000);

    $jwe = $jweBuilder
        ->create()              // We want to create a new JWE
        ->withPayload($payload) // We set the payload
        ->withSharedProtectedHeader([
            'alg' => 'RSA-OAEP-256',  // Key Encryption Algorithm
            'enc' => 'A128GCM',       // Content Encryption Algorithm
            'iat' => $milliseconds,   // Current Time Stamp in milliseconds
            'kid' => $keyId
        ])
        ->addRecipient($jwk)    // We add a recipient (a shared key or public key).
        ->build();              // We build it

    $serializer = new CompactSerializer();
    $token = $serializer->serialize($jwe, 0);
    return json_encode(['encData' => $token], JSON_PRETTY_PRINT);
}

/**
 * This method will decrypt the given JWE token.
 *
 * @param $encryptedPayload - JWE Token
 * @param $mleClientPrivateKeyPath
 * @return string|null
 */
function decryptJwe($encryptedPayload, $mleClientPrivateKeyPath)
{
    // The key encryption algorithm manager with the RSA-OAEP-256 algorithm.
    $keyEncryptionAlgorithmManager = new AlgorithmManager([new RSAOAEP256(),]);

    // The content encryption algorithm manager with the A128GCM algorithm.
    $contentEncryptionAlgorithmManager = new AlgorithmManager([new A128GCM(),]);

    // The compression method manager with the DEF (Deflate) method.
    $compressionMethodManager = new CompressionMethodManager([new Deflate(),]);

    // We instantiate our JWE Decrypter.
    $jweDecrypter = new JWEDecrypter($keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager, $compressionMethodManager);

    // Our key.
    $jwk = JWKFactory::createFromKeyFile($mleClientPrivateKeyPath);
    $encryptedPayload = json_decode($encryptedPayload, true);

    $token = $encryptedPayload['encData'];

    $serializerManager = new JWESerializerManager([new CompactSerializer(),]);

    $jwe = $serializerManager->unserialize($token);

    $success = $jweDecrypter->decryptUsingKey($jwe, $jwk, 0);
    if ($success) {
        $jweLoader = new JWELoader(
            $serializerManager,
            $jweDecrypter,
            null
        );
        $jwe = $jweLoader->loadAndDecryptWithKey($token, $jwk, $recipient);
        return $jwe->getPayload();
    } else {
        throw new \RuntimeException('Error Decrypting JWE');
    }
}

function invokeAPI($url, $method, $username, $password, $keyId, $clientCertPath, $clientPrivateKey, $mleClientPrivateKeyPath, $payload = '')
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 2);

    if ($method == 'POST') {
        curl_setopt($curl, CURLOPT_POST, 1);
    }

    if ($payload != '') {
        curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
    }

    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Accept: application/json',
        'keyId: ' . $keyId
    ));

    curl_setopt($curl, CURLOPT_PORT, 443);
    curl_setopt($curl, CURLOPT_VERBOSE, 0);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 2);
    curl_setopt($curl, CURLOPT_SSLVERSION, 1);
    curl_setopt($curl, CURLOPT_SSLCERT, $clientCertPath);
    curl_setopt($curl, CURLOPT_SSLKEY, $clientPrivateKey);

    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_setopt($curl, CURLOPT_USERPWD, $username . ":" . $password);

    //enable headers
    curl_setopt($curl, CURLOPT_HEADER, 1);

    curl_setopt($curl, CURLOPT_URL, $url);

    $response = curl_exec($curl);
    $response_info = curl_getinfo($curl);

    // close curl resource to free up system resources
    $http_header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
    curl_close($curl);

    $http_header = httpParseHeaders(substr($response, 0, $http_header_size));

    // Print all headers as array
    echo "<pre>";
    print_r($http_header);
    echo "</pre>";

    if ($response_info['http_code'] === 0) {
        $curl_error_message = curl_error($curl);
        // curl_exec can sometimes fail but still return a blank message from curl_error().
        if (!empty($curl_error_message)) {
            $error_message = "<br/><br/>API call to $url failed: $curl_error_message";
        } else {
            $error_message = "<br/><br/>API call to $url failed, but for an unknown reason. " .
                "This could happen if you are disconnected from the network.";
        }
        echo $error_message;
    } elseif ($response_info['http_code'] >= 200 && $response_info['http_code'] <= 299) {
        echo "<br/><br/>Your call returned with a success code - " . $response_info['http_code'] . "";
    } else {
        echo "<br/><br/>[HTTP Status: " . $response_info['http_code'] . "]\n[" . $response . "]";
        echo "<br/><br/>Error connecting to the API ($url)";
    }
    return substr($response, $http_header_size);
}

function httpParseHeaders($raw_headers)
{
    $headers = [];
    $key = '';

    foreach (explode("\n", $raw_headers) as $h) {
        $h = explode(':', $h, 2);

        if (isset($h[1])) {
            if (!isset($headers[$h[0]])) {
                $headers[$h[0]] = trim($h[1]);
            } elseif (is_array($headers[$h[0]])) {
                $headers[$h[0]] = array_merge($headers[$h[0]], [trim($h[1])]);
            } else {
                $headers[$h[0]] = array_merge([$headers[$h[0]]], [trim($h[1])]);
            }

            $key = $h[0];
        } else {
            if (substr($h[0], 0, 1) === "\t") {
                $headers[$key] .= "\r\n\t" . trim($h[0]);
            } elseif (!$key) {
                $headers[0] = trim($h[0]);
            }
            trim($h[0]);
        }
    }

    return $headers;
}

$payload = '{
    "operationType": "UPDATE",
    "enrollmentInfo": {
      "cardholderInfo": {
        "primaryAccountNumber": "9132"
      },
      "accountLevelInfo": {
        "customerContactInfo": {
            "email": "user@example.com",
          "action": "ADD",
          "address": {
            "zip": "04009",
            "city": "Buffalo",
            "line1": "389 North Mango Avenue",
            "state": "OR"
          },
          "lastName": "Cody",
          "firstName": "Payne",
          "prefMethodOfContact": "E"
        }
      }
    },
    "updateReferenceID": "0000001"
  }
';

$encryptedData = encryptPayload($payload, $keyId, $mleServerPublicCertificatePath);

$body = invokeAPI('https://sandbox.api.visa.com/vcpe/v2/pan/enrollment', 'POST', $username, $password, $keyId, $client_cert, $private_key, $mleClientPrivateKeyPath, $encryptedData);
$responsePayload = decryptJwe($body, $mleClientPrivateKeyPath);

echo 'Response Payload:' . "<br>";
$enrollResponse = json_decode($responsePayload, 1);
print_r($enrollResponse);

 

X-CORRELATION-ID: 1710102316_720_1021519755_-5b54b9f6-8z9_VDP_WS

3 REPLIES 3
SyedSa
Community Moderator

Re: VCPE Enrollment Error 9501 Invalid input found, please correct the input data

Hi @kevinottoThank you for reaching out. One of our agents will look into this and get back to you soon. Until then, if any community members know a solution, please feel free to reply to this thread.

kevinotto
New Contributor

Re: VCPE Enrollment Error 9501 Invalid input found, please correct the input data

Still waiting for your agents.
API_Managers
Visa Developer Support Specialist

Re: VCPE Enrollment Error 9501 Invalid input found, please correct the input data

Hi @kevinotto,

 

This API is not supported in SBX. Please email Visa Developer Support at developer@visa.com to inquire about the next step for testing.




Thanks,

Tee



Was your question answered? Don't forget to click on "Accept as Solution" to help other devs find the answer to the same question.