Skip to main content
Glama

manage-webhook

Subscribe to, find, or unsubscribe from Shopify order update webhooks to receive real-time notifications when orders change.

Instructions

Subscribe, find, or unsubscribe webhooks

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform with webhook
callbackUrlYesWebhook callback URL
topicYesWebhook topic to subscribe to
webhookIdNoWebhook ID (required for unsubscribe)

Implementation Reference

  • src/index.ts:574-636 (registration)
    Registers the 'manage-webhook' MCP tool with description, Zod input schema, and async handler function that switches on 'action' to call ShopifyClient subscribe/find/unsubscribe methods.
    server.tool( "manage-webhook", "Subscribe, find, or unsubscribe webhooks", { action: z .enum(["subscribe", "find", "unsubscribe"]) .describe("Action to perform with webhook"), callbackUrl: z.string().url().describe("Webhook callback URL"), topic: z .nativeEnum(ShopifyWebhookTopic) .describe("Webhook topic to subscribe to"), webhookId: z .string() .optional() .describe("Webhook ID (required for unsubscribe)"), }, async ({ action, callbackUrl, topic, webhookId }) => { const client = new ShopifyClient(); try { switch (action) { case "subscribe": { const webhook = await client.subscribeWebhook( SHOPIFY_ACCESS_TOKEN, MYSHOPIFY_DOMAIN, callbackUrl, topic ); return { content: [{ type: "text", text: JSON.stringify(webhook, null, 2) }], }; } case "find": { const webhook = await client.findWebhookByTopicAndCallbackUrl( SHOPIFY_ACCESS_TOKEN, MYSHOPIFY_DOMAIN, callbackUrl, topic ); return { content: [{ type: "text", text: JSON.stringify(webhook, null, 2) }], }; } case "unsubscribe": { if (!webhookId) { throw new Error("webhookId is required for unsubscribe action"); } await client.unsubscribeWebhook( SHOPIFY_ACCESS_TOKEN, MYSHOPIFY_DOMAIN, webhookId ); return { content: [ { type: "text", text: "Webhook unsubscribed successfully" }, ], }; } } } catch (error) { return handleError("Failed to manage webhook", error); } } );
  • Zod schema for tool inputs: action enum, callbackUrl (URL), topic (ShopifyWebhookTopic enum), optional webhookId.
    { action: z .enum(["subscribe", "find", "unsubscribe"]) .describe("Action to perform with webhook"), callbackUrl: z.string().url().describe("Webhook callback URL"), topic: z .nativeEnum(ShopifyWebhookTopic) .describe("Webhook topic to subscribe to"), webhookId: z .string() .optional() .describe("Webhook ID (required for unsubscribe)"), },
  • Implements webhook subscription creation via GraphQL mutation 'webhookSubscriptionCreate', maps REST topic to GraphQL topic, handles user errors.
    async subscribeWebhook( accessToken: string, shop: string, callbackUrl: string, topic: ShopifyWebhookTopic ): Promise<ShopifyWebhook> { const myshopifyDomain = await this.getMyShopifyDomain(accessToken, shop); const graphqlQuery = gql` mutation webhookSubscriptionCreate( $topic: WebhookSubscriptionTopic! $webhookSubscription: WebhookSubscriptionInput! ) { webhookSubscriptionCreate( topic: $topic webhookSubscription: $webhookSubscription ) { webhookSubscription { id topic endpoint { __typename ... on WebhookHttpEndpoint { callbackUrl } } } userErrors { field message } } } `; const res = await this.shopifyGraphqlRequest<{ data: { webhookSubscriptionCreate: { webhookSubscription: { id: string; topic: ShopifyWebhookTopicGraphql; endpoint: { callbackUrl: string; }; }; userErrors: Array<{ field: string[]; message: string; }>; }; }; }>({ url: `https://${myshopifyDomain}/admin/api/${this.SHOPIFY_API_VERSION}/graphql.json`, accessToken, query: graphqlQuery, variables: { topic: this.mapTopicToGraphqlTopic(topic), webhookSubscription: { callbackUrl, }, }, }); const webhookSubscription = res.data.data.webhookSubscriptionCreate.webhookSubscription; const userErrors = res.data.data.webhookSubscriptionCreate.userErrors; if (userErrors.length > 0) { throw getGraphqlShopifyUserError(userErrors, { shop, topic, callbackUrl: callbackUrl, }); } return { id: webhookSubscription.id, topic: this.mapGraphqlTopicToTopic(webhookSubscription.topic), callbackUrl: webhookSubscription.endpoint.callbackUrl, }; }
  • Queries existing webhooks by topic and callbackUrl using GraphQL 'webhookSubscriptions' query, returns matching webhook or null.
    async findWebhookByTopicAndCallbackUrl( accessToken: string, shop: string, callbackUrl: string, topic: ShopifyWebhookTopic ): Promise<ShopifyWebhook | null> { const myshopifyDomain = await this.getMyShopifyDomain(accessToken, shop); const graphqlQuery = gql` query webhookSubscriptions( $topics: [WebhookSubscriptionTopic!] $callbackUrl: URL! ) { webhookSubscriptions( first: 10 topics: $topics callbackUrl: $callbackUrl ) { edges { node { id topic endpoint { __typename ... on WebhookHttpEndpoint { callbackUrl } } } } } } `; const res = await this.shopifyGraphqlRequest<{ data: { webhookSubscriptions: { edges: { node: { id: string; topic: ShopifyWebhookTopicGraphql; endpoint: { callbackUrl: string; }; }; }[]; }; }; }>({ url: `https://${myshopifyDomain}/admin/api/${this.SHOPIFY_API_VERSION}/graphql.json`, accessToken, query: graphqlQuery, variables: { topics: [this.mapTopicToGraphqlTopic(topic)], callbackUrl, }, }); const webhookSubscriptions = res.data.data.webhookSubscriptions.edges; if (webhookSubscriptions.length === 0) { return null; } const webhookSubscription = webhookSubscriptions[0].node; return { id: webhookSubscription.id, topic: this.mapGraphqlTopicToTopic(webhookSubscription.topic), callbackUrl: webhookSubscription.endpoint.callbackUrl, }; }
  • Deletes webhook subscription by ID using GraphQL mutation 'webhookSubscriptionDelete', throws on user errors.
    async unsubscribeWebhook( accessToken: string, shop: string, webhookId: string ): Promise<void> { const myshopifyDomain = await this.getMyShopifyDomain(accessToken, shop); const graphqlQuery = gql` mutation webhookSubscriptionDelete($id: ID!) { webhookSubscriptionDelete(id: $id) { userErrors { field message } deletedWebhookSubscriptionId } } `; const res = await this.shopifyGraphqlRequest<{ data: { webhookSubscriptionDelete: { deletedWebhookSubscriptionId: string; userErrors: Array<{ field: string[]; message: string; }>; }; }; }>({ url: `https://${myshopifyDomain}/admin/api/${this.SHOPIFY_API_VERSION}/graphql.json`, accessToken, query: graphqlQuery, variables: { id: webhookId, }, }); const userErrors = res.data.data.webhookSubscriptionDelete.userErrors; if (userErrors.length > 0) { throw getGraphqlShopifyUserError(userErrors, { shop, webhookId, }); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/smithery-ai/shopify-mcp-server-main-1'

If you have feedback or need assistance with the MCP directory API, please join our Discord server