I am implementing apple pay onto our website. I do not have a macOS device and am using windows visual studios / mvcnet. I have done all the merchantID and certification stuff and configured it on the windows machine. I am using Apple Pay JS and on the step where the payment sheet is opened with session.begin(). I use an ajax call to retrieve a merchantSession, which I believe it does successfully because the object consumed by session.completeMerchantValidation(merchantSession) contains an epochnumber, expiration time and the site name. However, immediately after completeMerchantValidation, the oncancel event is fired, and I get a red alert saying "Payment not completed".
I need help with how to proceed from here, I read somewhere online that the domain on where I am testing needs to be a registered merchant domain. For example, when I test the functionality of the button, I need to be on www.mySite.com, where I have mySite.com registered as a domain. Can someone confirm if this is true.. because I am accessing the site from my iOS devices through local IP address. If that is not true, any help proceeding from where I am would be helpful.
function StartPaySession() {
var lineItems = [
{
label: 'Shipping',
amount: '0.00',
}
];
var shippingMethods = [
{
label: 'Free Shipping',
amount: '0.00',
identifier: 'free',
detail: 'Delivers in five business days',
},
{
label: 'Express Shipping',
amount: '5.00',
identifier: 'express',
detail: 'Delivers in two business days',
}
];
var total = {
label: 'Apple Pay Example',
amount: '8.99',
};
var paymentData = {
countryCode: 'US',
currencyCode: 'USD',
shippingMethods: shippingMethods,
lineItems: lineItems,
total: total,
supportedNetworks: ['amex', 'discover', 'masterCard', 'visa'],
merchantCapabilities: ['supports3DS'],
requiredShippingContactFields: ['postalAddress', 'email'],
};
var paySession = new ApplePaySession(2, paymentData);
paySession.onvalidatemerchant = function (event) {
var validationData = { ValidationUrl: event.validationURL };
$.ajax({
url: '/orders/cart/startapplepaysession',
method: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(validationData)
}).then(function (merchantSession) {
paySession.completeMerchantValidation(merchantSession);
alert("end = " + window.location.host);
}, function (error) {
alert("merchant validation unsuccessful: " + JSON.stringify(error));
paySession.abort();
});
};
paySession.onpaymentmethodselected = function (event) {
alert("1");
paySession.completePaymentMethodSelection(total, lineItems);
};
paySession.onshippingcontactselected = function (event) {
alert("2");
paySession.completeShippingContactSelection(ApplePaySession.STATUS_SUCCESS, shippingMethods, total, lineItems);
};
paySession.onshippingmethodselected = function (event) {
alert("3");
paySession.completeShippingMethodSelection(ApplePaySession.STATUS_SUCCESS, total, lineItems);
}
paySession.onpaymentauthorized = function (event) {
var token = event.payment.token;
alert("payment authorization | token = " + token);
paySession.completePayment(ApplePaySession.STATUS_SUCCESS);
}
paySession.oncancel = function (event) {
alert("payment cancel error " + event);
}
paySession.begin();
};
You are creating the Apple pay session at the wrong place.You need to create it from server side not on the client side.
These links might help requesting apple pay payment session, complete merchant validation
Steps are discussed here:on validate merchant
This is an old question, but thought I'd post my experience in case it's relevant. I was seeing the same behavior as described by original poster when testing on my local server, but was able to get payment sheet interactions to work.
What worked for me
Log in to AppleID as a Sandbox Test User
Specify "localhost" as the domain when performing merchant validation, e.g.:
{
"merchantIdentifier": "<your merchant ID>",
"displayName": "<your merchant display name>",
"initiative": "web",
"initiativeContext": "localhost"
}
Related
Since yesterday when I use the gapi.auth2 to do a Google Sign-in on an installed PWA app on Android, the App opens the browser window to select the user, but it remains blank.
The same page on the Chrome browser on Android open the user selection as usual. The code is the same, from the same server. The code was not modified in more than 15 days. I presume the problem is some change in the gapi JS client code from Google servers.
Inspecting the PWA Google Sign-in tab on chrome shows the following error:
Uncaught Failed to get parent origin from URL hash!
The origins on Google Developer Console are ok.
Anyone has any clue how to solve this?
Edit1: Code chunk
initGoogle() {
this.ngRedux.dispatch({ type: SN_INIT_GOOGLE });
Observable.create((observer: Observer<any>) => {
let head = document.getElementsByTagName('head');
(<any>window).__ongload = () => {
gapi.load('auth2', () => {
gapi.auth2.init({
client_id: `${AppConfig.google.clientID}`
}).then(() => {
this.auth2 = gapi.auth2.getAuthInstance();
this.googleInitiated();
observer.complete();
}, (err) => {
this.log.error(err);
observer.error(err);
});
});
};
let script: HTMLScriptElement = document.createElement('script');
script.src = 'https://apis.google.com/js/platform.js?onload=__ongload';
script.type = 'text/javascript';
head[ 0 ].appendChild(script);
}).pipe(
timeout(AppConfig.google.timeout),
retry(AppConfig.google.retries),
catchError(error => {
this.googleInitError();
return observableEmpty();
}),
take(1)
).subscribe();
}
async googleLogin(scope: string = 'profile email', rerequest: boolean = false, type: string = SN_GOOGLE_LOGIN): Promise<GoogleUser> {
let goopts = {
scope: this.ngRedux.getState().socialNetworks.getIn([ 'google', 'grantedScopes' ]),
prompt: rerequest ? 'consent' : undefined
};
try {
const user: GoogleUser = await this.auth2.signIn(<any>goopts);
...
return user;
} catch (error) {
...
return error;
}
}
Edit 2: Error screenshot
Screenshot
I had the similar issue as mentioned here. I had not registered my domain under Credential -> My OAuth Client ID -> Authorized JavaScript origins. By adding, it started working. Check the similar case for your app. It may help.
This bug should be fixed. Cannot reproduce it any more.
Following the developer docs, I have attempted numerous variations trying to achieve this.
I would like to extract the label from the token payload, if not I can build it from the /me response body.
This is my latest attempt:
var jwtDecode = require('jwt-decode');
const getTokenFields = (z, bundle) => {
var sub = jwtDecode(bundle.authData.token)['sub']
console.log(sub)
return sub;
};
const getLabelField = (z, bundle) => {
var sub = jwtDecode(bundle.authData.token)['sub']['label']
console.log(sub)
return sub;
};
const authentication = {
type: 'session',
test: {
url: '{{process.env.AP_HOST}}/me'
},
fields: [
{
key: 'token',
type: 'string',
required: true,
helpText: 'See settings to get your token'
}
],
sessionConfig: {
perform: getTokenFields
},
connectionLabel: {
perform: getLabelField
}
};
module.exports = authentication;
the only thing that I can get to work is:
connectionLabel: "{{bundle.authData.token}}", but it looks terrible!
connectionLabel: "{{bundle.authData.responsefield}}" feels like it should be something that should work but it doesn't either
David here, from the Zapier Platform team.
Instead of connectionLabel: {perform: getLabelField}, it should just be connectionLabel: getLabelField. You can also use a string that pulls from the bundle (like you're seeing) or any data that comes back from the designated test endpoint (see here).
There should be validation that prevents what you have (that'll error when you run zapier validate) but if that comes back clean then definitely let us know.
Having gone through an endless amount of materials on the topic, would appreciate help here please:
I am setting up OAuth 2.0 account linking from an Amazon Alexa "skill" to an external service. The skill successfully identifies the lack of an access token and displays a LinkAccount card to the user. Problem is: the card contains no link to the authorization page.
Respective Authorization URI definitely is provided in the skill's account linking settings.
Intent's code:
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const accessToken = handlerInput.requestEnvelope.context.System.user.accessToken;
if (accessToken == undefined){
const speechText = "Please use the Alexa app to link your Amazon account to the external account"
return handlerInput.responseBuilder
.speak(speechText)
.withLinkAccountCard()
.getResponse();
} else {
const speechText = 'Welcome to the Alexa Skills Kit, you can say hello!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Hello World', speechText)
.getResponse();
}
},
};
JSON Output:
{
"body": {
"version": "1.0",
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>Please use the Alexa app to link your Amazon account to the external account</speak>"
},
"card": {
"type": "LinkAccount"
}
},
"sessionAttributes": {},
"userAgent": "ask-node/2.0.7 Node/v6.10.3"
}
}
I am using Amazon developer console simulator and an iOS Alexa app for testing (no physical device).
Thank you.
I've created an html file with embedded Watson Virtual Agent chat bot, code similar below, with WVA strictly using the building core capabilities:
IBMChat.init({
el: 'ibm_chat_root',
baseURL: 'https://api.ibm.com/virtualagent/run/api/v1',
botID: '',
XIBMClientID: '',
XIBMClientSecret: ''
});
What I noticed is if I run the WVA in Preview mode, and have input "pay bill", the WVA can come back with two piece response, with first:
Accessing your account information...
and second the make payment:
Your account balance is $42.01 due on 5/17/2017. What would you like to do? (More options coming soon!)
However, if I enter the same in my HTML chatbot, the response only comes back with the first part:
Accessing your account information...
and second part never comes out.
Does anyone else experience the same problem?
The version in the "Preview" mode has some mock "action" handlers setup. Obviously, not every one of you users would owe $42! In the sample code on the github, the mock action handlers are not setup. There are examples on how to subscribe to those action events with handlers here: https://github.com/watson-virtual-agents/chat-widget/tree/master/examples/basic-actions-example
As of 5/31/17 you can cover all the built in actions using the code snippet below...
const config = { instance: null };
const getUserProfileVariablesMap = {
'bill_amount': '42.01',
'payment_due_date': (() => {
const currentDate = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
return `${currentDate.getMonth() + 1}/${currentDate.getDate()}/${currentDate.getFullYear()}`;
})(),
'authorized_users': 'Bob Everyman and Jane Doe'
};
const getUserProfileVariables = (data) => {
const variables = data.message.action.args.variables;
variables.forEach(v => {
const value = getUserProfileVariablesMap[v];
(value) ? config.instance.profile.set(v, value) : config.instance.profile.set(v, '[sample data]');
});
config.instance.sendSilently('success');
};
const success = () => config.instance.sendSilently('success');
const agent = () => config.instance.receive('On your own site you would run code to connect to an agent now.');
const accountSettings = () => config.instance.receive('On your own site you would run code to open the Account Settings page now.');
function registerActions(instance) {
config.instance = instance;
instance.subscribe('action:getUserProfileVariables', getUserProfileVariables);
instance.subscribe('action:updateAddress', success);
instance.subscribe('action:updateUserName', success);
instance.subscribe('action:updatePhoneNumber', success);
instance.subscribe('action:updateEmail', success);
instance.subscribe('action:payBill', success);
instance.subscribe('action:sendPaymentReceipt', success);
instance.subscribe('action:agent', agent);
instance.subscribe('action:openAccountSettingsPage', accountSettings);
};
window.IBMChatActions = {
registerActions: registerActions
};
// window.IBMChatActions.registerActions(window.IBMChat);
On the Administrative Preview, you are getting fake code stubs that handle action requests from the agent.
When one of these actions are invoked, the widget will print the "Processing..." message and then invoke all registered subscribers for that action. It is up to these registered subscribers to continue the conversation flow by silently sending "success", "failure", or "cancel" back to the server.
For example, the agent might pass down the "payBill" action. You would want to call your payment gateway, determine if it was successful, and then notify the agent of the result:
IBMChat.init(/* Settings */);
IBMChat.subscribe('action:payBill', function() {
var data = {
amount: IBMChat.profile.get('amount'),
card: {
number: IBMChat.profile.get('cc_number'),
// ... other private card data
}
};
$.post('https://www.myserver.com/payment-gateway', data)
.done( function() {
IBMChat.sendSilently('success');
})
.fail( function() {
IBMChat.sendSilently('failure');
});
});
Actions Documentation
https://github.com/watson-virtual-agents/chat-widget/blob/master/docs/DOCS.md#actions
I am trying to send a push notification using a user's id. I have already tested sending with installationId, querying the _Installation class, but i would like to query the session class of the user pointer, to then turn around and query the installation class.
My problem is lying in the restrictions of querying the session class. I have successfully used createWithoutData() found here, and I know it is working because i can output that user. However, even after using the master key found here, the results are always empty.
The general practise for sending Push Notification to specific user is that you will store pointer to User in Installation class... for example when user register do this
Swift
if let installation = PFInstallation.current() {
installation["user_id"] = PFUser.current()!
installation.saveInBackground()
}
Cloudcode
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('user_id', tarUser);
pushQuery.exists("deviceToken");
pushQuery.limit(1); // in case there are more Installation with the user ID, use only the latest
pushQuery.descending("createdAt");
Parse.Push.send({
where: pushQuery, // Set our Installation query
data: {
alert: "Some push text"
}
}, {
success: function() {
// Push was successful
response.success();
},
error: function(error) {
console.error("Got an error " + error.code + " : " + error);
response.error(error);
},
useMasterKey: true
});
if I remember correctly you have to query the pointer in Cloud code with pointer structure, like this
var tarUser = {
__type: 'Pointer',
className: '_User',
objectId: 'insertObjectIDHere'
};