Apple Pay for the Web Merchant Validation

Has anyone found documentation on actually performing the Merchant Validation step? A signed request to the validationURL in the onvalidatemerchant event gives me an error message requesting a valid JSON object. Passing a valid JSON object responds with

{
  "statusMessage": "Payment Services Exception Invalid session request -- missing merchant identifier",
  "statusCode": "400"
}

Unfortunately, all of the obvious key names for merchant identifier are failing me(id, merchant, merchant_id, merchant_identifier). As far as I can tell there, isn't any documentation surrounding this step.

Tried

merchantIdentifier

?

Hi I also work on this , I didn't find any doc or info for performValidation method. Can you please give us some sample code of this method.Thx.

Accepted Answer

Finally figured it out!

"merchantIdentifier" is the correct field name, and there are 2 more required, "domainName" and "displayName". The trick here is that "merchantIdentifier" is actually OID 1.2.840.113635.100.6.32 in the identity certificate(View the certificate in Keychain for an easy way to find this), and "displayName" is your plaintext name.

{
    "merchantIdentifier":"F3[...]4B",
    "domainName":"[verified domain]",
    "displayName":"merchant.[...]"
}

IE:

curl --data '{"merchantIdentifier":"F3[...]4B", "domainName":"[verified domain]", "displayName":"merchant.[...]"}' --cert ./<certFile>:<certPassword>  <validationURL>


And a session token is yours!

Hi, could you please share somethin about how your "performValidation" functions looks like?

try this to get you started


function performValidation(valURL) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
          var data = JSON.parse(this.responseText);
          resolve(data);
    };
    xhr.onerror = reject;
    xhr.open('GET', 'apple_pay_do.php?u=' + valURL);
    xhr.send();
  });
}


and in apple_pay_do.php


$validation_url = $_GET['u'];


// create a new cURL resource
$ch = curl_init();


$data = '{"merchantIdentifier":"97....B0", "domainName":"your domain name", "displayName":"your display name"}';


curl_setopt($ch, CURLOPT_URL, $validation_url);
curl_setopt($ch, CURLOPT_SSLCERT, PRODUCTION_CERTIFICATE_PATH);
curl_setopt($ch, CURLOPT_SSLKEY, PRODUCTION_CERTIFICATE_KEY);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);


if(curl_exec($ch) === false)
{
    echo 'Curl error: ' . curl_error($ch);
}


// close cURL resource, and free up system resources
curl_close($ch);


This has got me as far as getting the merchant session identifier and nonce back from apple, and a successful "Pay with touch id" section in the applepay sheet in mobile safari.

Hi,

Calling the validationURL (to start session) gives me 404 - page not found. How did you manage to get this nice error message 😀

the merchant validation service seems to be offline at the moment, since around Friday (was working fine for me before then). Currently getting Http/1.1 Service Unavailable

Can I ask roughly what certificate you provided in that curl command, e.g. which stage in setup did it come from. I've exported various certs and tested a similar command from my webserver but to no avail:


$ cat fish.post
{"merchantIdentifier":"B7...D8","domainName:"www.xxx","displayName":"merchant.com.xxxxxxxxx"}
$ curl -k -X POST -d @fish.post --cert ~/applepaycerts/my.pem https://apple-pay-gateway-cert.apple.com/paymentservices/startSession


My current error is:


curl: (35) error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca


Thanks,


Paul

Scratch that it was the key/cert combination I thought it was but I noticed in keychain that my copy was marked as "invalid" and I had to regenerate.

It looks like it is still offline... I am currently getting HTTP/1.1 500 Internal Server Error

It's working ok for me today (and yesterday)

SIlly question but,

the value of your merchantIdentifier, you said you can view this in keychain, is it the value of the data field under the extention 1.2.840.113635.100.6.32?

Extention (1.2.840.113635.100.6.32)

Critical: NO

Data: 06...8F

The merchantIdentifier format shown in the online guide is working OK now, no need to hunt for the ID in the certificate any more


{ "merchantIdentifier":"merchant.com.example.mystore", "domainName":"mystore.example.com", "displayName":"MyStore" }

thanks! That works great.


I was also incorrectly adding in my https:// to my domain name.

Hi ,


I am trying to do merchant validation and getting beow error.

Please help .

If any one have standlone file to connect apple server using https post.

Pease share ...


javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure


1. Create a 2048 bit Private Key and .csr (rename the extension to .certSigningRequest) using OpenSSL tool,

2. Upload it to the Merchant ID using Create Certificate in apple developer portal

3. Get the merchant_id.cer from developer portal and convert it to .pem using open ssl

3. Added public key of your private key to the .pem file

4. Using .pem and private key, create .p12 (again using openssl).

5. Import .p12 to keystore


Note: the openssl should be replaced with commercial certificate tools as openssl is prone to hacks or security vulnerabilities.


Verify using curl --data '{"merchantIdentifier":"F3[...]4B", "domainName":"[verified domain]", "displayName":"merchant.[...]"}' --cert ./<certFile>:<certPassword> <validationURL>

Thanks raghuram for detail information.

I am able to make a curl request with the merchant certificate in .p12 format, but I am receiving the following JSON response from https://apple-pay-gateway.apple.com



{

"statusMessage": "Payment Services Exception merchantId=C4450CDAB91279A7CB97F5EF9.....0836BB76FCCC7B70BBC9F897 not registered for service",

"statusCode": "417"

}

Your merchant identifier should be as per the human readable one you registered with apple, probably starting with "merchant." I've put an end to end working implementation here https://github.com/norfolkmustard/ApplePayJS

The JSON payload I am sending is:


curl --data '{"merchantIdentifier":"merchant.com.skymode", "domainName":"www.skymode.com", "displayName":"SkyModeMe"}' --cert /Users/ericv/workspaces/skymodefrontend/src/SkyModeFrontEnd/Resources/apple-pay-skymode-merchant-certificate.p12:thepassword https://apple-pay-gateway.apple.com/paymentservices/startSession -v


The responsed back JSON payload that contains a alphanumeric ID string is being extracted from Apple via the .p12 certificate. Turns out, it doesn't matter what value I use for the "merchantIdentifier" json property, I always get back the same HTTP 417 Expectation Failed.

we need some listing of these apple statusCode


I tried removing the MerchantDomain associated with my MerchantID, and got exactly the same " .... not registered for service" text description as you, but got a statusCode of 400 instead of your 417. Knowing what 417 means in detail would seem to be the key.


You're testing this all from the same server you verified with apple?

A list of status codes would be helpful.


I am actually executing the curl request from my development machine, which is from an IP address (not accessible via any domain name) for testing/development purposes. I realize that Apple documentated to make the merchant validation request from the production webserver, but why and how would they enforce that? It seems that all the security checks is in the fact that the SSL certificate passed with every HTTP POST request will be validated and that is all Apple should be relying on (this isn't an oAuth 2.0 callback architecture). The certificate is valid, because if it wasn't I would even get back a HTTP response at all.

You have the possible issue that your dev server isn't using the same approved TLS version or cipher suits as the prod server/site you got accepted by apple, although curl could be using a different cipher compared to apache anyway.


perhaps try some verbose loging for the curl connection, see what headers/cipher etc it's using

Maybe the issue is that I have not signed up for Apple Pay with a credit card gateway. I was assuming I could get a merchant session id in the sandbox environment, which I swore I tried out earlier by making a HTTP POST request to (notice the -cert in the subdomain): https://apple-pay-gateway-cert.apple.com/paymentservices/startSession


and it didn't work. But viola, it works today. I just got back a JSON payload from the Apple Pay sandbox server of:


{"epochTimestamp":1470959853352,"merchantSessionIdentifier":"cd1c24566bbd44bbb531042748b6ec...e5a943f0f94927c24","nonce":"27d89549","merchantIdentifier":"C4450CDAB91279A7CB97F5EF91F0...36BB76FCCC7B70BBC9F897","domainName":"www.skymode.com","displayName":"SkyModeMe","signature":"308006092a864886f70d010702a0803080020101310f300d06096086480165030402010500308006092a864886f70d0107010000a0...9317765c3000000000000"}


I believe the Apple Pay for Web production web servers are returning the status code of 417 because I don't have a "real" credit card gateway for Apple Pay established for my Apple Developer account.

I did try out your php solution in github on my Mac OS X (El Capitan) using the default apache server and the php modules that shipped with Mac OS X. I couldn't get it to work because of the following:


executing apple_pay_comm.php with &u=https://apple-pay-gateway-cert.apple.com/paymentservices/startSession{"curlError":"SSL: Can't load the certificate "/Library/WebServer/Documents/applepay/applepay_includes/ApplePay.crt.pem" and its private key: OSStatus -61"}


I looked up the curl issue of "OSStatus -61" and it led me to https://coderwall.com/p/h3zzrw/using-client-ssl-certificates-for-php-curl-requests-on-osx


In the end, I couldn't get your php server code to make a HTTP post request to apple's web servers (production or sandbox).

Apple Pay for the Web Merchant Validation
 
 
Q