How to specify callbackUrl when creating HTTP webhooks via GraphQL webhookSubscriptionCreate mutation?

I’m building a shipping platform that needs to programmatically create webhook subscriptions for multiple Shopify stores using the GraphQL Admin API. I’m running into an issue with the webhookSubscriptionCreate mutation and need help understanding the correct approach.

The Problem:

When trying to create an HTTP webhook subscription, I’m experiencing a disconnect between the working GraphQL mutation and the generated Java classes from the schema.

What Works: This mutation executes successfully against the 2025-07 API:

mutation RegisterWebhook(
  $topic: WebhookSubscriptionTopic!
  $webhookSubscription: WebhookSubscriptionInput!
) {
  webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
    webhookSubscription {
      id
      topic
      endpoint {
        __typename
        ... on WebhookHttpEndpoint { callbackUrl }
      }
    }
    userErrors { field message }
  }
}

What Doesn’t Work: However, when I generate Java classes from the schema using graphql-maven-plugin 3.0.1, the WebhookSubscriptionInput class only contains these fields:

  • format: WebhookSubscriptionFormat
  • includeFields: [String!]
  • filter: String
  • metafieldNamespaces: [String!]
  • metafields: [HasMetafieldsMetafieldIdentifierInput!

There’s no callbackUrl field or endpoint configuration in the generated input class.

My Questions:

  1. How can the mutation work successfully if the WebhookSubscriptionInput doesn’t contain endpoint/callback URL fields in the schema?

  2. Is there a discrepancy between the actual API behavior and the published schema for 2025-07?

  3. How should I properly pass the callback URL when using the generated Java classes - is there a missing input type or parameter I should be using?

Questions for the Community:

  • Has anyone successfully created HTTP webhook subscriptions using GraphQL?

  • Am I missing something obvious about the GraphQL mutation structure?

Technical Context:

  • API Version: 2025-07

  • Use Case: Multi-tenant SaaS platform managing webhooks for multiple stores

  • Framework: Spring Boot 3.5

  • GraphQL Client: graphql-maven-plugin 3.0.1 with generated client classes

  • Integration: Java with the following plugin configuration:

<plugin>
      <groupId>com.graphql-java-generator</groupId>
      <artifactId>graphql-maven-plugin</artifactId>
      <version>3.0.1</version>
      <configuration>
          <packageName>com.kuryo.core.shopify.app.client.graphql.generated</packageName>
          <typePrefix>Shopify</typePrefix>
          <separateUtilityClasses>true</separateUtilityClasses>
          <generateDeprecatedRequestResponse>true</generateDeprecatedRequestResponse>
          <!-- Custom scalars for all Shopify types (ARN, BigInt, Date, etc.) -->
      </configuration>
  </plugin>

Thanks for any help!

Hello @mantas.matuzas

I am more of a Node, Laravel guy and I have done it in my app built with laravel recently. I passed it as input variables while calling the graphql client. Please see the snippet below to know how I did it.

$input = [
  'topic' => 'APP_UNINSTALLED',
  'webhookSubscription' => [
     'callbackUrl' => 'www.example.com',
     'format' => 'JSON',
  ];
];

$mutation = 'here put the whole GQL mutation query';

$shop->api()->graph($mutation, $variables);

And it worked fine.

Now if you want in java, then I suppose it would look like something like this. (DID SOME DIGGING WITH AI :face_savoring_food: ) But I am feel confident that it might work out fine.

Here is the way to set callbackUrl

// Build the HTTP endpoint input
        WebhookHttpEndpointInput httpEndpointInput = new WebhookHttpEndpointInput();
        httpEndpointInput.setCallbackUrl(webhookUrl);

        // Build the subscription input with the endpoint
        WebhookSubscriptionInput subscriptionInput = new WebhookSubscriptionInput();
        subscriptionInput.setEndpoint(httpEndpointInput);

Since callbackUrl has been deprecated directly inside webhookSubscriptionInput and put inside Endpoint, you need the WebhookHttpEndpointInput class to wrap the callbackUrl.

Let me know if it works.

Thanks

Thank you so much for taking the time to share your Laravel implementation - that’s really helpful to see how you’ve successfully handled this!

I appreciate the Java example you provided as well. You’re absolutely right that this approach would work perfectly for manual implementation. However, I’m working on a slightly different workflow that I’d love to get your thoughts on.

My current approach involves:

  1. Exporting the complete GraphQL schema from Shopify’s 2025-07 API via introspection

  2. Converting that JSON introspection result to GraphQL Schema Definition Language (SDL)

  3. Using code generation tools to automatically create Java DTOs from the schema

This automated approach helps me avoid manually coding DTOs and ensures my classes stay in sync with Shopify’s schema changes. The challenge I’m facing is that when I introspect the 2025-07 API, the WebhookSubscriptionInput type only shows these 5 fields: format, includeFields, filter, metafieldNamespaces, and metafields.

                {
                    "kind": "INPUT_OBJECT",
                    "name": "WebhookSubscriptionInput",
                    "description": "The input fields for a webhook subscription.",
                    "fields": null,
                    "inputFields": [
                        {
                            "name": "format",
                            "description": "The format in which the webhook subscription should send the data.",
                            "type": {
                                "kind": "ENUM",
                                "name": "WebhookSubscriptionFormat",
                                "ofType": null
                            },
                            "defaultValue": null
                        },
                        {
                            "name": "includeFields",
                            "description": "The list of fields to be included in the webhook subscription. Only the fields specified will be included in the webhook payload. If null, then all fields will be included. Learn more about [modifying webhook payloads](https://shopify.dev/docs/apps/build/webhooks/customize/modify_payloads).",
                            "type": {
                                "kind": "LIST",
                                "name": null,
                                "ofType": {
                                    "kind": "NON_NULL",
                                    "name": null,
                                    "ofType": {
                                        "kind": "SCALAR",
                                        "name": "String",
                                        "ofType": null
                                    }
                                }
                            },
                            "defaultValue": null
                        },
                        {
                            "name": "filter",
                            "description": "A constraint specified using search syntax that ensures only webhooks that match the specified filter are emitted. See our [guide on filters](https://shopify.dev/docs/apps/build/webhooks/customize/filters) for more details.",
                            "type": {
                                "kind": "SCALAR",
                                "name": "String",
                                "ofType": null
                            },
                            "defaultValue": null
                        },
                        {
                            "name": "metafieldNamespaces",
                            "description": "The list of namespaces for any metafields that should be included in the webhook subscription.",
                            "type": {
                                "kind": "LIST",
                                "name": null,
                                "ofType": {
                                    "kind": "NON_NULL",
                                    "name": null,
                                    "ofType": {
                                        "kind": "SCALAR",
                                        "name": "String",
                                        "ofType": null
                                    }
                                }
                            },
                            "defaultValue": null
                        },
                        {
                            "name": "metafields",
                            "description": "A list of identifiers specifying metafields to include in the webhook payload.",
                            "type": {
                                "kind": "LIST",
                                "name": null,
                                "ofType": {
                                    "kind": "NON_NULL",
                                    "name": null,
                                    "ofType": {
                                        "kind": "INPUT_OBJECT",
                                        "name": "HasMetafieldsMetafieldIdentifierInput",
                                        "ofType": null
                                    }
                                }
                            },
                            "defaultValue": null
                        }
                    ],
                    "interfaces": null,
                    "enumValues": null,
                    "possibleTypes": null
                }

I don’t see the endpoint field you mentioned, nor the deprecated callbackUrl field. This makes me wonder if there might be some version differences between what I’m introspecting and what you’re working with in your Laravel setup.

Would you mind sharing which API version you’re using? Also, if you have any experience with GraphQL schema introspection or code generation, I’d really value your insights on how to properly capture the endpoint/callback URL structure from the schema itself.

Thanks again for your help - your practical experience with this integration is exactly what I need to figure this out!

Hello @mantas.matuzas

I have recently upgraded to 2025-07.

The problem is about the callbackUrl there is no secific doc. If you go to this link, beside callbackUrl you can see deprecated and then it says to use uri.

I am not familiar with spring boot. But I think in your plase I would just create a custom class which will inherite the webhookSubscriptionInput class and add callbakcUrl property from my child class. And then I will just call the graphql query using input fields.

I am actually busy now which is why I am not beilg able to get started with spring boot. I think I will have a look into springboot and try to fix this once I get my time.

It is quite interesting what you are trying to achieve.

Let me know how is it going.