Prerequisites

As a prerequisite, you should understand:

Process Details

You need to register a merchant ID using an Apple developer account. Additionally you need to assign a key pair to this merchant ID, and sign its accompanying certificate signing request (CSR) there. The key pair and CSR is received from us. With merchant ID and key pair you can integrate an Apple Pay button into your checkout solution.

The payment process itself works similar to other payment methods. When one operates the Apple Pay button, the payment instrument is chosen and the necessary security checks are performed. The Apple API returns a security token, that must be handed over to authorise the payment against the secuconnect API.

The secuconnect API methods to authorise and capture the payment are the same like for credit card payment, except there are no callback URLs for there is no second interactive 3-D Secure check, and there is a special Payment Container for Apple Pay. This Payment Container has a very short lifetime and cannot be reused.

Domain Validation and Registration

If Apple Pay is only to be integrated into a website (or if it is a web app), then no Apple Developer account is required.

The integration in native apps has not been tested yet; issues may occur due to the different Apple Team IDs. A hybrid app (like React Native or Flutter) should not be a problem.

Domain Validation File

The domain where the Apple Pay button is displayed must first be validated with Apple. The shop must offer a file /.well-known/apple-developer-merchantid-domain-association having exactly the following content:

7B227073704964223A2234413632343942424633384330353830314536383844343938364139333933423032354642303544423944393638323244413732303633363731453836444133222C2276657273696F6E223A312C22637265617465644F6E223A313638393832353536323630392C227369676E6174757265223A223330383030363039326138363438383666373064303130373032613038303330383030323031303133313064333030623036303936303836343830313635303330343032303133303830303630393261383634383836663730643031303730313030303061303830333038323033653333303832303338386130303330323031303230323038346333303431343935313964353433363330306130363038326138363438636533643034303330323330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333031653137306433313339333033353331333833303331333333323335333735613137306433323334333033353331333633303331333333323335333735613330356633313235333032333036303335353034303330633163363536333633326437333664373032643632373236663662363537323264373336393637366535663535343333343264353035323466343433313134333031323036303335353034306230633062363934663533323035333739373337343635366437333331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333035393330313330363037326138363438636533643032303130363038326138363438636533643033303130373033343230303034633231353737656465626436633762323231386636386464373039306131323138646337623062643666326332383364383436303935643934616634613534313162383334323065643831316633343037653833333331663163353463336637656233323230643662616435643465666634393238393839336537633066313361333832303231313330383230323064333030633036303335353164313330313031666630343032333030303330316630363033353531643233303431383330313638303134323366323439633434663933653465663237653663346636323836633366613262626664326534623330343530363038326230363031303530353037303130313034333933303337333033353036303832623036303130353035303733303031383632393638373437343730336132663266366636333733373032653631373037303663363532653633366636643266366636333733373033303334326436313730373036633635363136393633363133333330333233303832303131643036303335353164323030343832303131343330383230313130333038323031306330363039326138363438383666373633363430353031333038316665333038316333303630383262303630313035303530373032303233303831623630633831623335323635366336393631366536333635323036663665323037343638363937333230363336353732373436393636363936333631373436353230363237393230363136653739323037303631373237343739323036313733373337353664363537333230363136333633363537303734363136653633363532303666363632303734363836353230373436383635366532303631373037303663363936333631363236633635323037333734363136653634363137323634323037343635373236643733323036313665363432303633366636653634363937343639366636653733323036663636323037353733363532633230363336353732373436393636363936333631373436353230373036663663363936333739323036313665363432303633363537323734363936363639363336313734363936663665323037303732363136333734363936333635323037333734363137343635366436353665373437333265333033363036303832623036303130353035303730323031313632613638373437343730336132663266373737373737326536313730373036633635326536333666366432663633363537323734363936363639363336313734363536313735373436383666373236393734373932663330333430363033353531643166303432643330326233303239613032376130323538363233363837343734373033613266326636333732366332653631373037303663363532653633366636643266363137303730366336353631363936333631333332653633373236633330316430363033353531643065303431363034313439343537646236666435373438313836383938393736326637653537383530376537396235383234333030653036303335353164306630313031666630343034303330323037383033303066303630393261383634383836663736333634303631643034303230353030333030613036303832613836343863653364303430333032303334393030333034363032323130306265303935373166653731653165373335623535653561666163623463373266656234343566333031383532323263373235313030326236316562643666353530323231303064313862333530613564643664643665623137343630333562313165623263653837636661336536616636636264383338303839306463383263646461613633333038323032656533303832303237356130303330323031303230323038343936643266626633613938646139373330306130363038326138363438636533643034303330323330363733313162333031393036303335353034303330633132343137303730366336353230353236663666373432303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330316531373064333133343330333533303336333233333334333633333330356131373064333233393330333533303336333233333334333633333330356133303761333132653330326330363033353530343033306332353431373037303663363532303431373037303663363936333631373436393666366532303439366537343635363737323631373436393666366532303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330353933303133303630373261383634386365336430323031303630383261383634386365336430333031303730333432303030346630313731313834313964373634383564353161356532353831303737366538383061326566646537626165346465303864666334623933653133333536643536363562333561653232643039373736306432323465376262613038666437363137636538386362373662623636373062656338653832393834666635343435613338316637333038316634333034363036303832623036303130353035303730313031303433613330333833303336303630383262303630313035303530373330303138363261363837343734373033613266326636663633373337303265363137303730366336353265363336663664326636663633373337303330333432643631373037303663363537323666366637343633363136373333333031643036303335353164306530343136303431343233663234396334346639336534656632376536633466363238366333666132626266643265346233303066303630333535316431333031303166663034303533303033303130316666333031663036303335353164323330343138333031363830313462626230646561313538333338383961613438613939646562656264656261666461636232346162333033373036303335353164316630343330333032653330326361303261613032383836323636383734373437303361326632663633373236633265363137303730366336353265363336663664326636313730373036633635373236663666373436333631363733333265363337323663333030653036303335353164306630313031666630343034303330323031303633303130303630613261383634383836663736333634303630323065303430323035303033303061303630383261383634386365336430343033303230333637303033303634303233303361636637323833353131363939623138366662333563333536636136326266663431376564643930663735346461323865626566313963383135653432623738396638393866373962353939663938643534313064386639646539633266653032333033323264643534343231623061333035373736633564663333383362393036376664313737633263323136643936346663363732363938323132366635346638376137643162393963623962303938393231363130363939306630393932316430303030333138323031383833303832303138343032303130313330383138363330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533303230383463333034313439353139643534333633303062303630393630383634383031363530333034303230316130383139333330313830363039326138363438383666373064303130393033333130623036303932613836343838366637306430313037303133303163303630393261383634383836663730643031303930353331306631373064333233333330333733323330333033333335333933323332356133303238303630393261383634383836663730643031303933343331316233303139333030623036303936303836343830313635303330343032303161313061303630383261383634386365336430343033303233303266303630393261383634383836663730643031303930343331323230343230653065366539313863363161363938666630656134386538316564616631366435653863363432346363363033396633646139613635623638343132343463303330306130363038326138363438636533643034303330323034343733303435303232313030633434386336393963353735613261633836373763633437386461666463626261363761313032623038623339663536343138633164363162616665633831313032323034656436366532613931333137626464616239636535646665663937633035653236316534333231333331656430303039613934666336376338326339316330303030303030303030303030227D

It must be accessible at a URL like https://shop.example.com/.well-known/apple-developer-merchantid-domain-association .

Domain Registration

Now you can register your domain with the Apple Pay Merchant ID of secupay ("merchant.com.secupay.finaro"). You must register the fully qualified domain name (FQDN) like www.example.com (in contrast to just example.com).

Our secuconnect API offers the endpoint /apple-pay/register-merchant-domain for domain registration:

Request
POST /apple-pay/register-merchant-domain HTTP/1.1
Host: connect.secucard.com
Authorization: Bearer qb56tjj1bcvo9n2nj4u38k84lo
Content-Type: application/json
Accept: application/json
 
{
    "domainNames": [
        "shop.example.com"
  ],
    "encryptTo": "merchant.com.secupay.finaro",
    "partnerMerchantName": "Musterfirma GmbH"
}

(Please note the base path is not /api/v2 here.)

The parameters have a direct equivalent to Apple Pay, see https://developer.apple.com/documentation/applepaywebmerchantregistrationapi/registermerchantrequest .
The parameter partnerInternalMerchantIdentifier is generated by us and does not have to be transmitted. You can register up to 99 domains per call. The first domain in the list determines the partnerInternalMerchantIdentifier.

If everything is fine, the API responds with 200 OK and an object like this:

Response
HTTP/1.1 200 OK
Content-Type: application/json
 
{
    "domainNames": [
        "shop.example.com"
    ],
    "encryptTo": "merchant.com.secupay.finaro",
    "partnerMerchantName": "Musterfirma GmbH",
   "partnerInternalMerchantIdentifier": "merchant.com.secupay.finaro.com.example.shop"
}

The value of the partnerInternalMerchantIdentifier must be stored and used as merchantIdentifier of the Apple Pay Button.

Button Parameters

The other parameters can be requested from the secuconnect API:

Request
POST /api/v2/General/Contracts/GCR_UWOTSTRSQFMGV5PK5LF65LNNL0H84G/IframeOptions HTTP/1.1
Host: connect-testing.secuconnect.com
Authorization: Bearer qb56tjj1bcvo9n2nj4u38k84lo
Accept: application/json

If everything is fine, the API responds with 200 OK and an object like this:

Response
HTTP/1.1 200 OK
Content-Type: application/json
 
{
// ...
"payment_config": {
// ...
"Applepay": {
"label": "Musterfirma GmbH",
"supported_networks": [
               "masterCard",
"visa"
          ],
"merchant_capabilities": [
"supports3DS"
]
}
}
}

The returned parameters inside payment_config.Applepay are used as-is to create the button.

Apple Pay Button Integration

The Apple Pay button must be set up this way:

HTML
// https://developer.apple.com/documentation/apple_pay_on_the_web/displaying_apple_pay_buttons_using_javascript
<script src="https://applepay.cdn-apple.com/jsapi/v1.1.0/apple-pay-sdk.js"></script>
..
<apple-pay-button buttonstyle="black" type="buy" locale="de-DE"></apple-pay-button>


The Apple Pay session must be set up this way:

JavaScript
// Creating an Apple Pay Session
// https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/creating_an_apple_pay_session
 
// https://developer.apple.com/documentation/apple_pay_on_the_web/applepaypaymentrequest
var session = new ApplePaySession(1, {
currencyCode: 'EUR',
countryCode: 'DE',
 
// https://developer.apple.com/documentation/apple_pay_on_the_web/applepaylineitem
total: {
label: 'Musterfirma GmbH',
amount: '10.00',
type: 'final'
},
 
// https://developer.apple.com/documentation/apple_pay_on_the_web/applepayrequest/2951831-supportednetworks
supportedNetworks: ['masterCard', 'visa'],
 
// https://developer.apple.com/documentation/apple_pay_on_the_web/applepaymerchantcapability
merchantCapabilities: ['supports3DS']
});
 
// Providing Merchant Validation
// https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/providing_merchant_validation
// https://applepaydemo.apple.com/#merchantValidation
session.onvalidatemerchant = (event: any) => {
// Call your own server to request a new merchant session.
// You server will then call POST https://connect.secucard.com/apple-pay/create-payment-session with the same data.
// (Because of CORS this endpoint can not be called from the browser directly.)
fetch('/backend/apple-pay/init', {
method: 'POST',
body: JSON.stringify({
"merchantIdentifier": "merchant.com.secupay.finaro.com.example.shop",
"displayName": "TEST SHOP",
"initiative": "web",
"initiativeContext": "shop.example.com" // Must be equal to the "domainNames" value in the "Domain Registration" section.
})
})
.then(res => res.json()) // Parse response as JSON.
.then(merchantSession => {
session.completeMerchantValidation(merchantSession);
})
.catch(err => {
console.error("Error fetching merchant session", err);
});
};
 
// Sending container data to the backend, which will then do the "Authorise the Payment" step.
session.onpaymentauthorized = (event: any) => {
let form = event.payment.token.paymentData;
 
fetch('/backend/apple-pay/authorise', {
method: 'POST',
body: {
id: "STX_33PXAW2YN2NJTPM5KPGMK7QF5PBVA2",
container: {
type: "applepay",
private: form
}
}
})
.then(res => res.json()) // Parse response as JSON.
.then(merchantSession => {
session.completePayment(session.STATUS_SUCCESS);
})
.catch(err => {
console.error("Error fetching merchant session", err);
});
}
 
session.oncancel = (event) => {
}
 
session.begin();

Authorise the Payment

In order to authorise the Smart Transaction for Apple Pay payment, you need to call POST Smart/Transactions/STX_.../prepare/creditcard:

Request
POST /api/v2/Smart/Transactions/STX_33PXAW2YN2NJTPM5KPGMK7QF5PBVA2/prepare/creditcard HTTP/1.1
Host: connect-testing.secuconnect.com
Authorization: Bearer qb56tjj1bcvo9n2nj4u38k84lo
Content-Type: application/json
Accept: application/json
 
{
"customer": {
"contact": {
"forename": "Mike",
"surname": "Mustermann",
"name": "Mike Mustermann",
"address": {
"street": "Musterstr.",
"street_number": "42",
"additional_address_data": "App. 97",
"postal_code": "09999",
"city": "Dorianburgh",
"country": "DE"
},
"email": "Eunice.Spencer89@example.net",
"mobile": "+491775555555",
"phone": "+495555555555",
"dob": "1965-12-31T00:00:00+01:00"
}
},
    "container": {
"type": "applepay",
"private": {
"version": "EC_v1",
"data": "g7tzh9wOG0TkzmFdMHYvqwmQtAV9Zsr2tgIvDr92EXd8VtLL29WM2UN5rt4FtUJjusnnl8S5WOcxIjZdftzxYp7CuGEOf7cOmJotUPP5MeCyjn8d7CQA+8O9PDcobRC1R+DlgoFmW3+VffJlEo2b6XrGlv0Yw8ml6uUp8...c9x8=",
"signature": "MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCAMIID4zCCA4igAwIBAgIITDBBSVGdVDYwCgYIKoZIzj0EAwIwejEuMCwGA1UEAwwlQXBwbG.../Kft6VcCWj/aRqxEAAAAAAAA",
"header": {
"ephemeralPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcdKUayPwZ2cmGwV7TRiR9AOUs1581B8wPqWgwiJzUhaQ2cRn4hw4f93Mq+leog27OzF5nhZFxEAPKrMzW/mDyQ==",
"publicKeyHash": "9a/AmJ2u6BtDOZxusyFItlLeBaLYFMtH/McHzhqVi5Y=",
"transactionId": "6b5396203987ad350d91c3d2f8b7606384d070ef45443b2422a30598ca937327"
}
}
}
}

These are the parameters:

Parameter

Type

Meaning

container

object

Payment container data

container/type

string

Always "applepay" for this payment method

container/private

object

Data taken from the paymentData object of the decrypted Apple Pay token

customer

object

Customer. Only needed if not set before.

customer/id

string

Customer ID (PCU_xxx)

The Smart Transaction is authorised immediately.

Response (3-D Secure Not Required)
HTTP/1.1 200 OK
Content-Type: application/json
...
 
{
"object": "smart.transactions",
"id": "STX_33PXAW2YN2NJTPM5KPGMK7QF5PBVA2",
// ...
"customer": {
"object": "payment.customers",
"id": "PCU_3M55SQZR42NSPDS8GGF4N55EZCDCAZ",
"contact": {
"forename": "Mike",
"surname": "Mustermann",
"name": "Mike Mustermann",
"address": {
"street": "Musterstr.",
"street_number": "42",
"additional_address_data": "App. 97",
"postal_code": "09999",
"city": "Dorianburgh",
"country": "DE"
},
"email": "Eunice.Spencer89@example.net",
"mobile": "+491775555555",
"phone": "+495555555555",
"dob": "1965-12-31T00:00:00+01:00"
}
},
"container": {
"object": "payment.containers",
"id": "PCT_SF9XGHPVC2NSQX03V86EREAMMET7AZ"
},
// ... // ...
"transactions": [{
"object": "payment.transactions",
"id": "PCI_4YN04HZ4Z705GMRSJ5EW4J4X0ZDPNW"
}],
"created": "2020-10-29T14:13:41+01:00",
"updated": "2020-10-29T14:13:50+01:00",
"status": "approved",
// ...
"payment_method": "creditcard",
"trans_id": "30093721",
// ...
}

Status approved means the payment is authorised and you should be able to capture it. Status failed means you must repeat the payment process. You must also repeat the payment process when you update the Smart Transaction. It is then set back to created.

If the option auto_capture is true, it would already capture the Smart Transaction. Status ok, received or collection means you can deliver. Status pending means you have to wait for one of these statusses. Status failed means the payment failed, and you must repeat the payment process.

Capture the Payment

The way to capture an authorised payment is the same for all payment methods. If you have already studied this for invoice or direct debit payment, you will not find any new details.

In order to start the authorized Smart Transaction, you only need to call POST Smart/Transactions/STX_xxx/start.

Request
POST /api/v2/Smart/Transactions/STX_33PXAW2YN2NJTPM5KPGMK7QF5PBVA2/start HTTP/1.1
Host: connect-testing.secuconnect.com
Authorization: Bearer qb56tjj1bcvo9n2nj4u38k84lo
Accept: application/json

If everything is fine, the API responds with 200 OK:

Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"object": "smart.transactions",
"id": "STX_33PXAW2YN2NJTPM5KPGMK7QF5PBVA2",
// ...
"transactions": [
{
"object": "payment.transactions",
"id": "PCI_FDBREW9ZS7P6FTN4ZY2ATC6NK0QWO7"
}
],
"created": "2020-03-27T10:55:23+01:00",
"updated": "2020-03-27T10:56:41+01:00",
"status": "ok",
// ...
}

Status ok, received or collection means you can deliver. Status pending means you have to wait for one of these statusses. Status failed means the payment failed, and you must repeat the payment process.

In case of invoice payment you need to mark the actual delivery. This is to know the payment has become due, and to calculate the due date.

See Also

Further information:

Other payment methods: