shopify-billing
Originally fromtoilahuongg/shopify-agents-kit
SKILL.md
Shopify Billing Skill
The Billing API allows you to charge merchants for your app using recurring subscriptions or one-time purchases.
[!IMPORTANT] GraphQL Only: The REST Billing API is deprecated. Always use the GraphQL Admin API for billing operations.
1. Recurring Subscriptions (appSubscriptionCreate)
Use this mutation to create a recurring charge (e.g., monthly plan).
Example (Remix / Shopify App Template)
/* app/routes/app.upgrade.tsx */
import { authenticate } from "../shopify.server";
export const action = async ({ request }) => {
const { admin } = await authenticate.admin(request);
const shop = await admin.graphql(`
mutation AppSubscriptionCreate($name: String!, $lineItems: [AppSubscriptionLineItemInput!]!, $returnUrl: URL!) {
appSubscriptionCreate(name: $name, returnUrl: $returnUrl, lineItems: $lineItems) {
userErrors {
field
message
}
appSubscription {
id
}
confirmationUrl
}
}
`,
{
variables: {
name: "Pro Plan",
returnUrl: "https://myapp.com/app",
lineItems: [{
plan: {
appRecurringPricingDetails: {
price: { amount: 10.00, currencyCode: "USD" },
interval: "EVERY_30_DAYS"
}
}
}]
}
});
const response = await shop.json();
const confirmationUrl = response.data.appSubscriptionCreate.confirmationUrl;
// Redirect merchant to approve charge
return redirect(confirmationUrl);
};
2. One-Time Purchases (appPurchaseOneTimeCreate)
Use this mutation for non-recurring charges (e.g., specific service, lifetime access).
const response = await admin.graphql(`
mutation AppPurchaseOneTimeCreate($name: String!, $price: MoneyInput!, $returnUrl: URL!) {
appPurchaseOneTimeCreate(name: $name, returnUrl: $returnUrl, price: $price) {
userErrors { field message }
confirmationUrl
}
}
`, {
variables: {
name: "Concierge Setup",
returnUrl: "https://myapp.com/app",
price: { amount: 50.00, currencyCode: "USD" }
}
});
3. Checking Active Subscriptions
To gate features, check the currentAppInstallation for active subscriptions.
/* app/shopify.server.ts (billing config) */
export const billing = {
"Pro Plan": {
amount: 10.00,
currencyCode: "USD",
interval: "EVERY_30_DAYS",
},
};
/* Checking in loader */
const { billing } = await authenticate.admin(request);
const billingCheck = await billing.require({
plans: ["Pro Plan"],
isTest: true, // Use true for development stores
onFailure: async () => billing.request({ plan: "Pro Plan", isTest: true }),
});
const subscription = billingCheck.appSubscriptions[0];
Manual Query (if not using billing helper)
query {
currentAppInstallation {
activeSubscriptions {
id
name
status
lineItems {
plan {
pricingDetails {
... on AppRecurringPricing {
price { amount currencyCode }
}
}
}
}
}
}
}
4. Best Practices
- Test Mode: Always set
test: true(orisTest) when developing. Test charges do not bill the merchant. - Confirmation URL: You MUST redirect the user to the
confirmationUrlreturned by the mutation. The charge is not active until they approve it. - Webhooks: Listen for
app_subscriptions/updateto handle cancellations or status changes in real-time.
Weekly Installs
4
Repository
toilahuongg/goo…vity-kitFirst Seen
Jan 25, 2026
Security Audits
Installed on
gemini-cli4
claude-code4
codex4
opencode4
antigravity3
github-copilot3