I have an app customer who wants the orders which my app creates in their store to automatically bill a payment method to pay for that order. I’m trying to use the orderCreateMandatePayment mutation, but I’m having a hard time finding a valid mandateId that would work for charging a credit card automatically for future orders.
I was able to create a Subscription in my testing store, which stored a customer.paymentMethod on my customer record in that store, but the paymentMethod.mandates records have a mandateId of null. I’m using the bogus payment gateway since this is a test store…
How can I get a customer record in my store that has a valid paymentMethod.mandate that can be used with the orderCreateMandatePayment mutation?
https://shopify.dev/docs/api/admin-graphql/latest/objects/PaymentMandateResource
https://shopify.dev/docs/api/admin-graphql/latest/mutations/orderCreateMandatePayment
Hey @Eric_Froese, good question. I have a couple of things that should help narrow this down.
First, the mandateId that orderCreateMandatePayment expects is the id from a PaymentMandate object, not a CustomerPaymentMethod ID. You retrieve those by querying paymentCollectionDetails.vaultedPaymentMethods on the Order object, which returns PaymentMandate nodes with an id field. That id (format gid://shopify/PaymentMandate/{id}) is what you pass as mandateId.
The CustomerPaymentMethod.mandates connection you’re looking at returns PaymentMandateResource objects, which is a different type. Those have resourceId and resourceType fields, but that’s not the ID the mutation needs.
Before I can give you more targeted advice, it would help to understand your flow a bit better:
-
How is your app creating these orders? Via the orderCreate mutation, draft orders, or is the customer going through the online store checkout?
-
When you say you “created a Subscription,” do you mean a subscription contract, or a selling plan with deferred payment terms (pre-order / try-before-you-buy)?
The reason I ask is that orderCreateMandatePayment is designed for collecting payment on orders where the customer’s card was vaulted during checkout (the deferred purchase options flow covers this). If your app is creating orders directly via API, those orders may not have vaulted payment methods attached, which would explain the null values you’re seeing.
Also worth noting that write_payment_mandate is a restricted access scope that requires approval through the Partner Dashboard, so make sure you’ve requested that if you haven’t already. Let me know a bit more and I can take a closer look for you!
Hi @Donal-Shopify, thank you so much for your assistance! I wasn’t sure where to go by reading the Shopify Graphql docs by themselves, so I was pointed in the PaymentMandateResource by docs AI assistant.
My use case is this:
My app is used to route orders from Store A to Store B via API directly (using draftOrderCreate, then draftOrderComplete, not online store checkout). When creating the routed order in Store B, the customer would like to settle the payment for that routed order by automatically charging a vaulted payment method which is associated with a Customer record within their store. If it matters, this customer is on Shopify Plus.
In order for my testing store to have a “customer with a vaulted payment method”, I installed the Shopify Subscription app in that store and subscribed to a contract using the Bogus payment method:
query GetCustomer($id: ID!) {
customer(id: $id) {
id
paymentMethods(first: 10) {
nodes {
id
instrument {
__typename
...on CustomerCreditCard {
brand
}
}
mandates(first: 10) {
nodes {
resourceId
resourceType
}
}
}
}
}
}
{
"data": {
"customer": {
"id": "gid://shopify/Customer/9735541522625",
"paymentMethods": {
"nodes": [
{
"id": "gid://shopify/CustomerPaymentMethod/8f0be1f8df27240f0ca0767575bb7399",
"instrument": {
"__typename": "CustomerCreditCard",
"brand": "bogus"
},
"mandates": {
"nodes": [
{
"resourceId": null,
"resourceType": "SUBSCRIPTIONS"
}
]
}
}
]
}
}
}
}
My hope is that I can use one of these stored payment methods tied to a customer in order to pay for orders which are created via API later on.
I feel like subscription apps are basically doing this, so I wonder which are the correct APIs to pull this off?
Thank you so much for your help,
Eric
Thanks for the detailed breakdown, Eric. That clears up a lot.
The main problem is that orderCreateMandatePayment only works when the order already has vaulted payment methods attached to it (via order.paymentCollectionDetails.vaultedPaymentMethods). That attachment happens during checkout, not when an order is created through draftOrderCreate + draftOrderComplete. So even if the customer has a vaulted card on their CustomerPaymentMethod record, a draft-order-originated order won’t have that card available in paymentCollectionDetails, and the mutation won’t have a mandate to charge.
Subscription apps handle this differently in that they don’t create an order and then charge a stored card. Instead, subscriptionBillingAttemptCreate creates the order and charges the payment method in a single step (the order is a side effect of a successful billing attempt). That’s why it works for them, but it requires a subscription contract with a linked payment method, which doesn’t fit your order-routing use case.
The most promising path given you’re on Plus would be the B2B vaulted cards flow. If the customer in Store B is set up as a B2B company with a vaulted card on their company location, you could create the draft order with a purchasingEntity pointing to that company location, complete it as payment pending, and then try orderCreateMandatePayment against the resulting order. I haven’t confirmed whether mandates propagate to draft-order-originated B2B orders specifically, so that would need testing on your end.
The simpler fallback is to complete the draft order as payment pending and use the additionalPaymentCollectionUrl on the order’s paymentCollectionDetails to send the customer a payment link.
Hi @Donal-Shopify,
Thank you for your help! Your suggestions were bang on, and I was able to assign the customer with a saved payment method to the order (even an order created with the REST API) and then capture payment with the orderCreateMandatePaymentAPI. Everything worked perfectly in my testing environment.
Unfortunately, upon requesting access to the Payment Mandate API from Shopify, I was ultimately rejected:
At this time, we are only granting this to apps which are using a selling strategy that permits deferred payments such as pre-orders and Try Before You Buy. Since your App doesn’t seem to be doing this the request is denied.
Hopefully this changes in the future.
Best regards,
Eric
Glad the B2B vaulted card approach worked in testing, and sorry to hear the scope request was denied. That restriction isn’t something I can change from my end, but I’ve raised this use case internally as product feedback so the relevant team has visibility on it.
For now, the additionalPaymentCollectionUrl on order.paymentCollectionDetails is still the most viable path for collecting payment on API-created orders without the mandate scope. It does require the customer to complete payment through that link, which I know isn’t the hands-off experience you’re after but it’s the closest thing to it right now.