A place to discuss charging merchants for your apps and services using the billing API.
So I've created a Shopify app using the Ruby shopify-cli gem, and I am working on implementing the Billing API now. I'm using the scaffolding code created by the shopify node create command, so it's a generic GraphQL API mutation using the pre-built handlers in server/handlers/mutations.
When the client goes to install the app, they get sent to the install screen, then to the charge screen. Upon accepting the charge, the browser is then redirected to https://<myapphost>.ngrok.io/?shop=undefined. When my app gets this request, it tries to start the auth workflow for the undefined shop domain, redirecting to https://undefined/auth/etc....
Am I missing somewhere in the documentation where I'm supposed to also send the shop to Shopify? The redirect URL I'm supplying when creating the charge is just https://<myapphost>.ngrok.io, so Shopify seems to be tacking on the ?shop=undefined themselves.
I've searched through the forums and documentation to no avail, and Shopify Support said they don't have a technical team to elevate my ticket to so they just pointed me back to the forums. Any help at all would be appreciated.
Update: Created a new application using the shopify-cli and ONLY set up the Billing API. Same issue persists.
Code below:
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
const host = ctx.query.host;
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
ctx.cookies.set('shopOrigin', shop, { httpOnly: false, secure: true, sameSite: "none" })
ctx.cookies.set('accessToken', accessToken, { httpOnly: false, secure: true, sameSite: "none" });
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (topic, shop, body) =>
delete ACTIVE_SHOPIFY_SHOPS[shop],
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
/* added this section for Billing API implementation */
server.context.client = await handlers.createClient(shop, accessToken);
const hasSubscription = await handlers.getAppSubscriptionStatus(ctx);
if (hasSubscription) {
next();
ctx.redirect(`/?shop=${shop}&host=${host}`);
} else {
await handlers.getSubscriptionUrl(ctx);
}
},
})
);
getAppSubcriptionStatus:
import { gql } from "apollo-boost";
const GET_SUBSCRIPTION = gql`
query {
currentAppInstallation {
activeSubscriptions {
status
}
}
}
`;
export const getAppSubscriptionStatus = async (ctx) => {
const { client } = ctx;
const isActive = await client
.query({
query: GET_SUBSCRIPTION,
})
.then((response) => {
if (response.data.currentAppInstallation.activeSubscriptions.length) {
return (
response.data.currentAppInstallation.activeSubscriptions[0].status ===
"ACTIVE"
);
} else return false;
});
return isActive;
};
Solved! Go to the solution
This is an accepted solution.
UPDATE: I've solved this issue, in case anyone stumbles across this in the future. I set my redirectUrl in my initial appSubscriptionCreate mutation to be `https://<myapphost>.ngrok.io/?shop=${shop}&host=${host}`, and that seems to have fixed my issue.
This is an accepted solution.
UPDATE: I've solved this issue, in case anyone stumbles across this in the future. I set my redirectUrl in my initial appSubscriptionCreate mutation to be `https://<myapphost>.ngrok.io/?shop=${shop}&host=${host}`, and that seems to have fixed my issue.
Hi there!
Could you supply the getSubscriptionUrl function? It isn't clear to me, how this one works.
Thanks in advance!
Hi @GR0
Can you provide the updation that you have made in the getSubscriptionurl function
It will be great if you could update the code that is working..
Thanks 🙂
you can get the host using ctx.query.host