Setup webhook notifications

I am trying to setup an OAuth process and then setup webhooks to make this an incredibly easy process for store owners ideally never having to create their own App or find their API credentials manually in any way.

This is for a WordPress plugin so each person who goes through the OAuth process has their own website - this is very important. I do not want in any way to receive any of the webhook notifications myself and they should all go to the individual sites.

I have read many of the other threads but they all are building SaaS where all endpoints should get received at the same URL - that is not the case for me here.

When I try to create a webhook subscription using the Access Token for a store owner I get the following error:

The merchant has not given your application sufficient permissions to do that. The merchant must authorize your application for the following scopes: DEVELOPER_APPLICATION_WEBHOOKS /write MERCHANT

I am currently lost as to how to make a request to /v2/webhooks/subscriptions from the respective site in order to subscribe to specific webhook events and set the URL for the site to receive them at.

I am coding this in PHP and here is my code so far:

		$url = 'RECEIVE WEBHOOKS HERE';

		$events = [
			"payment.created",
			"payment.succeeded",
			"payment.failed",
			"subscription.created",
			"subscription.updated",
			"subscription.canceled",
		];
		$data = [
			"url" => $url,
			"event_types" => $events,
		];

		$args = array(
			'method'    => 'POST',
			'headers'   => array(
				'Authorization' => 'Bearer ' . $access_token,
				'Content-Type'  => 'application/json'
			),
			'body'      => json_encode( $data ),
			'timeout'   => 45,
		);
		$response = wp_remote_post( $api_url . '/v2/webhooks/subscriptions', $args );

:wave: I’m Square Dev AI, here to help answer your question!
Based on the information you’ve provided, the following documentation will help answer your question:

Additional Documentation

Handle Bookings Webhook Events
Use Customer Webhooks
Payments API Webhooks

If this documentation helped you find a solution, please check the box indicating that this reply solves the problem.
Otherwise one of our Developer Advocates will provide additional assistance shortly.

Square webhooks are scoped to the application. That means that any seller that OAuth’s to your application we will start to send webhook events to you based on the subscription of your application. The error your getting is because your using an OAuth access token to try and subscribe to events. You don’t need to subscribe every seller. Once a seller authorizes your app they are automatically subscribed to webhooks because the subscription is at the application level. :slightly_smiling_face:

As I mentioned, I do not want to get a single webhook myself - every individual site has a unique URL where webhooks for their orders need to go.

How can I set that up?

That isn’t currently possible with the Square webhook structure. You would need to consume all the webhooks within your database then filter accordingly and send the orders to the sellers site. :slightly_smiling_face:

So what you’re saying is likely every single WordPress plugin that has a Square integration likely has a server somewhere which is redirecting webhook notifications on to their customer sites? That is bonkers to me.

1 Like

What are you looking to send to the site? You mentioned an order. The for order object isn’t in the payload of webhooks. If they’re showing orders it would be there server calling the APIs server side and then serving it up to the client. :slightly_smiling_face:

I am looking to do standard payments and subscriptions. I am first starting my integration by sending people to the hosted payment page. After a person pays, the site needs to get confirmation of payments via a webhook. If they signed up for a subscription the site also needs to receive webhooks for events like the subscription payment failing and other common subscription related webhooks.

Okay, every OAuth access token is returned with a merchant_id and all webhook events have the merchant_id in the payload. You can set it up so that the filtering is based on merchant_id and do any additional filtering by location if needed. :slightly_smiling_face:

I don’t understand how that helps me get the webhooks sent to the individual sites. Are you still confirming that is not possible and I will have to redirect every single webhook from my server to theirs?

You keep mentioning “filtering” but I don’t fully understand what you mean by this.

It sounds like I will need to keep a database of merchant_id and a respective URL to forward the webook events on to?

Yes, if your using OAuth you have to keep a database of merchants because you’ll have to refresh the access tokens with the refresh_token. :slightly_smiling_face:

Let’s try this from another point of view:

How can a merchant give DEVELOPER_APPLICATION_WEBHOOKS /write MERCHANT scope to an app as outlined in the original error message?

That error happened because you used an OAuth access token. There isn’t a way to get DEVELOPER_APPLICATION_WEBHOOKS /write MERCHANT permissions because the webhook subscription is scoped to the application. Only your personal access token can update the webhook subscription. Any updates to that subscription in the Developer Dashboard will effect any OAuth’d seller connected to the application. :slightly_smiling_face:

Basically you’ll need to proxy the webhook hit to the client WordPress site.

With the current API version, as I understand it, only the root app can create subscriptions; there’s no way for an oAuth client to create subscriptions. While needing to proxy is somewhat of a pain, it’s relatively simple in terms of code. You’d need to grab the post, decrypt it and re-encrypt with a different key, then push it onto the client site and return the exit code from the client site.

Thanks for the clarification.

Having each site get their webhooks directly is far more important to me right now.

I am getting confused on which keys I need to have users provide. When they create an app, they get an App ID and Access Token. However, when I use those, it keeps returning data from a different store that I have in my test account.

I am so lost right now on which keys are used for what.

I need a store owner to get whatever keys they need so that my WordPress plugin can get locations, do payments, create subscriptions, create webhooks and set a custom URL to receive webhooks.

What are the steps needed to do this?

Ideally you shouldn’t be asking sellers to create an app in there account. We recommend using OAuth to connect to sellers accounts. :slightly_smiling_face:

Our team has decided we absolutely do not want to do any webhook forwarding and keep a database of merchant_id to store_url. We want webhooks going directly to the store owners site. According to this discussion, the only way to have that happen is to have store owners create their own app.

Is there another way to make that happen?

Okay, in that case you will need to have each seller create an application and configure a webhook subscription. You’ll need them to configure their production credentials. :slightly_smiling_face:

Which API key/secret/whatever is needed in order for code to add webhooks to an app? No combination of things has worked thus far.

I always get the error: This request could not be authorized

If you have the sellers access token then you can call CreateWebhookSubscription with something like this:

{
    "idempotency_key": "{{$guid}}",
    "subscription": {
      "name": "Example Webhook Subscription",
      "event_types": [
        "payment.created",
        "payment.updated"
      ],
      "notification_url": "https://example-webhook-url.com",
      "api_version": "2024-11-20"
    }
  }

That will create the subscription for the sellers account and webhooks will be sent to the notification_url. :slightly_smiling_face: