Dedicated to the Hydrogen framework, headless commerce, and building custom storefronts using the Storefront API.
I'm developing a proof-of-concept iOS app to help my company decide whether to use Shopify as a back-end for product sales. I've followed the iOS SDK guides, and have created a working application that does nearly everything it needs:
1. Access store info
2. Access collections and product catalog
3. Build a shopping cart, update shipping address, use the cardVaultUrl and CardCiient to obtain a token (I'm in test mode, so using a test credit card number)
On the next step I use checkoutCompleteWithCreditCard to process the order, and receive back "access denied".
I see on the uinversity forum that this issue comes up a lot (see links below), with no responses from Shopify whether this opertion shoudl work or not from a private app via iOS SDK.
Is this feature not supported? The documentation makes no mention of it being restricted, so it appears to be a bug.
https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/storefront-api-process-checkout-438429
Could you please provide a little more information on the problem to help diagnose this case? It would be helpful to see what your payload to "checkoutCompleteWithCreditCard" looks like, as well as the payload to the "vaultURL" used for vaulting the card.
Keep in mind the the vaulting service doesn't perform any validation. This happens during the checkout process instead, which might lead to falsely believing that the vaulted token is valid and can be used for payment. Seeing your payloads will help us better understand where the problem might be.
To learn more visit the Shopify Help Center or the Community Blog.
Hello Ma'am
I am facing same issue,
My Store is "RandomSellStore", please help me with this
HI Dima, thanks for your reply and assistance!
The actual payload going over the wire is difficult for me to fetch since it's being sent by the shopify API, but here's the swift code makign the api call.
The proof-of-concept app is a series of view controllers (browse catalog, add to cart, apply shipping method, submit payment). This is the last one--payment.
Yes, I realize the token returned by the vault may be invalid, but if it was I'd expect an error more along the lines of "payment declined" instead of "access denied" from the checkoutCompleteWithCreditCard method (?)
I'm happy to zip up the entire project and send if it would be helpful...this is a simple proof-of-concept against development store and test merchant account..so no confidentiality issues at all.
============ PaymentTableViewController.swift ==============
import UIKit
import MobileBuySDK
class PaymentTableViewController: UITableViewController {
@IBOutlet weak var firstName: UITextField!
@IBOutlet weak var lastName: UITextField!
@IBOutlet weak var creditCardNumber: UITextField!
@IBOutlet weak var expiresMonth: UITextField!
@IBOutlet weak var expiresYear: UITextField!
@IBOutlet weak var verificationCode: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
firstName.text = "John"
lastName.text = "Smith"
creditCardNumber.text = "4242424242424242"
expiresMonth.text = "12"
expiresYear.text = "2019"
verificationCode.text = "555"
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6
}
func fetchPaymentToken() {
guard let cardClient = ShoppingData.shopifyCard else {
displayError("nil card client in \(#function)")
return
}
guard let cardVaultUrl = ShoppingData.cardVaultUrl else {
displayError("nil cardVaultUrl in \(#function)")
return
}
let creditCard = Card.CreditCard(
firstName: firstName.text ?? "",
middleName: "A",
lastName: lastName.text ?? "",
number: creditCardNumber.text ?? "",
expiryMonth: expiresMonth.text ?? "",
expiryYear: expiresYear.text ?? "",
verificationCode: verificationCode.text ?? ""
)
let task = cardClient.vault(creditCard, to: cardVaultUrl) { token, error in
if let token = token {
print("Token received is: \(token)")
self.processOrder(paymentToken: token)
} else {
self.displayError(error?.localizedDescription ?? "Unknown error obtaining token")
}
}
task.resume()
}
@IBAction func submitOrderTapped(_ sender: UIBarButtonItem) {
fetchPaymentToken()
}
func processOrder(paymentToken: String) {
guard let checkoutId = ShoppingData.checkout?.id else {
displayError("nil checkoutId in \(#function)")
return
}
guard let client = ShoppingData.shopifyClient else {
displayError("Invalid client in \(#function)")
return
}
guard let billToAddress = ShoppingData.billToAddress else {
displayError("nil billToAddress in \(#function)")
return
}
guard let paymentDue = ShoppingData.checkout?.paymentDue else {
displayError("nil paymentDue in \(#function)")
return
}
let idempotencyKey = UUID().uuidString
let payment = Storefront.CreditCardPaymentInput.create(
amount: paymentDue,
idempotencyKey: idempotencyKey,
billingAddress: billToAddress,
vaultId: paymentToken
)
let mutation = Storefront.buildMutation { $0
.checkoutCompleteWithCreditCard(checkoutId: checkoutId, payment: payment) { $0
.payment { $0
.id()
.ready()
}
.checkout { $0
.id()
.ready()
}
.userErrors { $0
.field()
.message()
}
}
}
let task = client.mutateGraphWith(mutation) { result, error in
if let err = error {
self.displayError(ShoppingData.shopifyErrorMessage(err: err))
return
}
if let userError = result?.checkoutCreate?.userErrors, userError.count > 0 {
for err in userError {
self.displayError(err.message)
}
return
}
let checkoutReady = result?.checkoutCompleteWithCreditCard?.checkout.ready ?? false
let paymentReady = result?.checkoutCompleteWithCreditCard?.payment?.ready ?? false
print("Checkout completed: \(checkoutReady)")
print("Payment completed: \(paymentReady)")
}
task.resume()
}
}
============ ShoppingData.swift =================
class ShoppingData {
static var shopifyClient: Graph.Client? // endpoint to shopify store
static var shopifyCard: Card.Client? // endpoint to card processing
static var itemCollections : [CatalogCollection] = [] // all items in the catalog
static var cartItems : [CatalogItem] = [] // all items in the shopping cart
static var checkout: Storefront.Checkout? // the checkout object (from which the checkoutId is pulled from)
static var billToAddress: Storefront.MailingAddressInput? // save the address to re-use in the payment submission (in real life the bill-to may be different though)
static var cardVaultUrl: URL? // the URL used to obtain credit card tokens
static func shopifyErrorMessage(err: Graph.QueryError) -> String {
switch err {
case .request(let error):
return error?.localizedDescription ?? "Error has nil local description"
case .http(let statusCode):
return HTTPURLResponse.localizedString(forStatusCode: statusCode)
case .noData:
return err.localizedDescription
case .jsonDeserializationFailed:
return "json deserialization failed"
case .invalidJson:
return "invalid json"
case .invalidQuery(let reasons):
return reasons[0].message
case .schemaViolation(let schemaError):
return "schema error: \(schemaError.localizedDescription)"
}
}
}
It's possible the gateway doesn't like your test card number, verification number, etc. Have you tried a different test card?
To learn more visit the Shopify Help Center or the Community Blog.
Yes, I'm using the numbers pasted from your site (see below). I've tried the visa and mastercard for sure, and have the same error either way.
https://help.shopify.com/manual/payments/shopify-payments/testing-shopify-payments
just to reiterate...if the payment info was invalid, the error should be "payment declined" not "access denied", right?
See post below
Reposting with shopify shop connected account: I'm seeing the same "access denied" error when calling checkoutCompleteWithCreditCard. Using Mobile-Buy-SDK 3.1.2 on iOS with Shopify private app storefront access token. Our test payload looks very similar to powerleydev's. Our shopify payment is also in test mode, and the credit card info is the same test credit card number(4242424242424242). Please let me know what additional info I need to provide to figure out what's wrong.
Request payload for checkoutCompleteWithCreditCard:
mutation{checkoutCompleteWithCreditCard(checkoutId:"Z2lkOi8vc2hvcGlmeS9DaGVja291dC9jYTdiYTk5YTFjNTY0MmU1M2I0NTFjNjBlNWU5YzlhMj9rZXk9MjAwNDk4ZWRiYTM3NDQ2MmFjMzBiNjQyMGVmNjAxNzM=",payment:{amount:"12.15",idempotencyKey:"56D2826C-B45A-4F19-8182-EC6B06F3DC9C",billingAddress:{address1:"1 Gary",address2:"",city:"San Francisco",company:null,country:"United States",firstName:"Joe",lastName:"Black",phone:"5101231234",province:"California",zip:"94110"},vaultId:"west-8c88cce51c8695bcaea71480f140ebbc",test:true}){checkout{id,ready,requiresShipping,taxesIncluded,email,shippingAddress{firstName,lastName,phone,address1,address2,city,country,countryCode,province,provinceCode,zip},shippingLine{handle,title,price},note,lineItems(first:250){edges{cursor,node{variant{id,price},title,quantity}}},webUrl,currencyCode,subtotalPrice,totalTax,totalPrice,paymentDue,order{id,orderNumber,customerUrl,email}},userErrors{field,message}}}
Response:
{
"data": {
"checkoutCompleteWithCreditCard": null
},
"errors": [{
"message": "CheckoutCompleteWithCreditCard access denied",
"locations": [{
"line": 1,
"column": 10
}],
"path": ["checkoutCompleteWithCreditCard"]
}]
}
Aready treid with real credit card info and turning off payment test mode, got same error.
Is there a permission that needs to added to the private app that's not avaiable to be set in the admin UI? If so, how do I get that set or whom should I contact? Already tried customer support, but they can't resolve API related issues and directed me to this forum.
Please advice on next step.
Further investigation revealed that it was a misconfiguration of permissions. It has been fixed and the checkouts should be running smoothly now. Please verify that it's working as you expect.
To learn more visit the Shopify Help Center or the Community Blog.
I'm still getting the same error. Could you fix the private app permission on spongerevolution.myshopify.com account too?
Mira, the permissions on your store have been updated.
To learn more visit the Shopify Help Center or the Community Blog.
Works now, thank you. Will newly created private app have the correct permission now?
@dima, thanks for taking care of this issue. Works great now!
I'm also getting the same error. Could you please fix the permissions for worm-app.myshopify.com account too?
@gurhan Permissions adjusted. Please take look.
To learn more visit the Shopify Help Center or the Community Blog.
Hi @Dima, I'm also facing this same error in my android proof-of-concept app. I've created a new thread some time ago describing all the steps I took to proceed with the checkout but I've got no answer. Can you please help me to figure out what I'm missing in the checkout process please? I've attached all the logs (requests and responses) for every single step.
As far as I understand from this thread the "Access denied" error is related to a misconfiguration of permissions in the store, is it right? If so, is there any way to set those missing permissions in the admin UI?
Please provide your shop domain that you're using for checkout.
To learn more visit the Shopify Help Center or the Community Blog.
Hello ma'am i am facing same issue,
My Domain Name : randomsellstore.com
My Private App Name : RandomSellStore
Hi Dima, thank you very much for your quick response. I've already successfully completed the checkout with credit card. I had a live chat with a colleague of yours who set the proper permissions to my private app already.
It would be very useful if the process to request permission for private app was better detailed in the documentation. Is there any way to set these permissions without having to ask a Shopify Employee? I mean is there any way I could set them myself in the Admin UI (or any other interface available to me)?.
I agree that the current process is not intuitive. We are working on improving it moving forward. Unfortunately, I don't have a timeline to share at the moment
To learn more visit the Shopify Help Center or the Community Blog.
I'm also getting the same error. I tried with Shopify Payments in test mode and with Bogus Gateway. Could you please check? Shop domain is 'al1234-test-store.myshopify.com'
Michael, I've fixed permissions for your shop. Please verify it works.
To learn more visit the Shopify Help Center or the Community Blog.
Sorry, I cannot, because it returns 404. In the Shopify Partners dashboard it moved to the tab 'Transferred stores' and now it have 'Shopify Plan' - 'Fraudulent'. Please return it back.
Michael, your shop status is unrelated to permission changes. If you have any questions regarding shop status, please contact support directly.
To learn more visit the Shopify Help Center or the Community Blog.
Okay, thanks. You said you have fixed permissions. But this is newly created store, I created it just a day ago. We have another development store, and our client will create real store later. Should we ask here about every shop we create? Can we change permissions ourselves in Shopify Dashboard or admin panel?
Michael - if you have a store marked as fraudulent you'll need to talk to the Shopify Support team directly. It's not something that can be helped with on the public forum.
Dima, please make same changes also for 'alacard-test-store.myshopify.com'.
Michael, what is the name of the private app that needs these permissions?
To learn more visit the Shopify Help Center or the Community Blog.
Dima, name of private app is `Alacard private app (test)`
Permissions have been adjusted. Please verify.
To learn more visit the Shopify Help Center or the Community Blog.
It works. Thank you very much.
Hi, same error here.
gofindit.myshopify.com
Could you fix the permissions?
GOTeam, your "Mobile App" app already has the correct checkout permissions.
To learn more visit the Shopify Help Center or the Community Blog.
@Dima_Bart sir, please can you fix checkout permission for us also ? Storename : https://proj-jules-james.myshopify.com/ and app name : App
Thanks
Hello Dima,
I also work with gofindit.myshopify.com (GOTeam user) and we are still having the access denied error, we tested on both Android and iOS and we get the same error. Any other way to fix this issue?
What's the name of your private app that you're using?
To learn more visit the Shopify Help Center or the Community Blog.
Go Find It Store
We are using "Storefront access token" when we configure the GraphClient. Is that right, or should we use the API key that is in the Mobile App section? It's a little confusing...
Yep, that's correct. Permissions have been updated for the "Go Find It Store" client, you should be all set.
To learn more visit the Shopify Help Center or the Community Blog.
Thanks! It works now. We will be creating new stores soon, is there any way to fix this issue from our end, so that we don't have to bother you again? 🙂
No problem! Unfortunetly, not yet. We'll keep you posted here if anything changes.
To learn more visit the Shopify Help Center or the Community Blog.
Hi Dima,I'm still getting the same error. Could you fix the private app permission on http://mobilecommerce.myshopify.com domain and my private app name is SmartCommerce
Hey Mahesh, SmartCommerce is now enabled with the correct permissions. Please verify.
To learn more visit the Shopify Help Center or the Community Blog.
@Dima_Bart I am having same bug, can you please do some stuff with my permissions https://www.kingofsheba.com/ and App Name "King of Sheba".
Hey dima,now it is working fine thank you but i am getting an error like this
{
"data" : {
"checkoutCompleteWithCreditCard" : {
"userErrors" : [
{
"field" : [
"payment",
"test"
],
"message" : "Test is not supported"
}
],
"checkout" : {
"id" : "Z2lkOi8vc2hvcGlmeS9DaGVja291dC84NGE4MTFjYzM3OWExZThkZWRkNzhjMDBlNmFjNWNmZD9rZXk9ZDU0YWQ4OGY1ZGYzYzJmYmQ0YzhmMDU1OWM2ZDY1Y2Q="
}
}
}
The error is telling you that "test" mode is not supported. Try removing the "test" parameter or setting it to "false" in your query.
To learn more visit the Shopify Help Center or the Community Blog.
Thank you Dima,now it is working fine
Hey, @Dima - do you mind giving me permissions for graupel-test.myshopify.com?
Thanks!!