Web Payment SDK - Recurring payment

Please I want to implement recurring payment(monthly subscription payment) on our platform, but i am not seeing any resources on your platform that explicitly shows how to do that programmatically on the web payment sdk. please any guide, documentation, github resources or suggestions on way forward will be appreciated. thanks.

The Web Payments SDK won’t actually create the recurring subscriptions. It will tokenize the card information that you’ll use to create the card on file with the Cards API.

Once you’ve created the card on file you’ll then create the recurring subscription with the Subscriptions API. :slight_smile:

I have been able to implement the subscription api but when the customer is charged I want to be able to update my table and be able to allocate new slots to the customer for the month… please which of the webhook i am subscribing to and how do I set that up… thanks in advance.

Glad to hear that you’ve been able to implement the Subscriptions API. When a customer pays for a recurring subscription you can listen to invoice.payment_made webhooks. This will notify you when a customer pays for a subscription. :slightly_smiling_face:

Thanks :pray: for your understanding and response… But I still need clarification, on something… Do we need to set up a callback url on our square developer dashboard that will trigger the script on the url to run each time a subscription payment is made like other traditional payment gateway I am familiar with… Finally I would appreciate if you can drop a resource that shows coding sample because on the invoice.payment_made webhook doc I can only see sample output… I would also want to confirm if that works for charging from saved cards on file. Thanks

Yes, you’ll configure the webhook URL in the Developer Dashboard. Please see our Webhooks documentation for implementation and examples.

Also if your going to be seperately charging cards on file using the Payments API that are outside of the subscription you’ll also what to listen to payments webhhoks. A payment webhook will trigger whenever a payments is made on the account… :slightly_smiling_face:

No not charging with payment API, here is what my team is doing, when a customer wants to subscribe to our membership plan, the customer is taken to our Web Payment SDK page where he/she will have to enter his/her card details, and accept to be charge from his card subsequently; on payment submission, the customer is debited immediately for the first month and then the payment ID is used to create a card on file which is used to create a subscription for that customer for subsequent months. Meanwhile the customer details is use to create the customer to our seller account in order to obtain the customer ID. So I don’t know if we are missing any step. Also with the above explanation, which of the web hook event are we supposed to listen to… Then finally do we need to update the subscription due date every month programmatically via the notification url or its to be done on our square dashboard. thanks.

If your charging the customer on the Web Payments SDK to get the payment_id to store the card on file then your using the Payments API for that payment. That payment will trigger payments webhooks. After that once the subscription is created and is charging the customer you can continue to listen for payment webhooks and you can listen to invoice.payment_made events.

Lastly there isn’t a need to update the subscription due date each month. The Subscriptions API will charge the customer on automatically according to the plans cadence. :slightly_smiling_face:

please I am getting this error on creat subscription payment.

and the docs states that only two params are. needed in CreateSubscriptionRequest. model

I am passing the location ID, the Customer ID so which is supposed to be the third one…

What’s the snippet of code your getting this error with? :slightly_smiling_face:

I have discovered the issue, that’s difference in API version what I was implementing is for Square API version 30.x… while we are running version 25.x…

But please is it still safe to remain on the current version we are right now or we should upgrade to the latest also owing to the fact that there are some features that are on beta release in the latest version…

Also I can see that using the version 25 docs we are required to pass the amount to be charged while creating the subscription which may require us to just save the card on file without the payment I’d from web payment SDK so which of the webhook event are we supposed to listen considering the above scenario. Thanks :pray:

Glad to hear you figured it out. Yes, it is safe to remain on the existing version. However we do recommend that you regularly update to a newer version on some cadence that fits your development schedule to stay current.

You’ll use invoice.payment_made events to be notified when a subscription is paid for. :slightly_smiling_face:

Good evening Sir… Please is it safe now to use the subscription plan variation features on square sdk version 30… Because I am seeing beta release on the docs. Thanks for your understanding

Yes, it is safe to use subscription plan variations with the SDK. Beta functionality is considered stable and closely represents what’s intended for final release, but fixes and updates might still be made. :slightly_smiling_face:

Hello Sir, please I am having an issue with my webhook notification url, if I do not check for the invoice payment status my database updates as expected but if I check for the status of the invoice payment before update my database base on if the status is paid, my database fails to update. Also have use a unique url from webhook.site to listen to the webhook event it shows that the invoice was paid, so i am thinking there is a variable i am not accessing correctly, here is what i an trying to do in my code…

here is the documentation i am using

Also we noticed that before now, if a customer use a particular test card to subscriber on the sandbox account, another customer cannot use same card, again… but right now, multiple customers can use same card to subscribe, please is this normal? if yes can you enlighten us on the reasons or conditions that could warrant the above experiences. thanks… :slightly_smiling_face:

Are you able to print out what your getting for status? It may be that your not looking at the nested status in the right place.

Currently only our test values are available in sandbox. No other test values are available to be used in sandbox. :slightly_smiling_face:

From my code screen shot you can see that I am calling
$result2 = $body->getInvoicePaymentMadeEventData();
$result1 = $result2->getInvoicePaymentMadeEventObject();
$result = $result1->getInvoice();

and then using $result to get every other nested values, now I need to be sure that getInvoicePaymentMadeEventData and getInvoicePaymentMadeEventObject are the right right objects I am supposed to call, and that I am doing it the right way, i think that is where the major confusion lies… because I have checked your model in github could not find the above two model objects… From what I have seen in the test data I am actually looking for the nested status in the right place… also you did not comment anything about the multiple customer not being able to use same test card for subscription and right now they can do that …

please here is the error I an getting:
[2023-10-11 15:17:03] staging.ERROR: Call to a member function getInvoicePaymentMadeEventData() on string {“exception”:"[object] (Error(code: 0): Call to a member function getInvoicePaymentMadeEventData()

and here is my code:
if (WebhooksHelper::isValidWebhookEventSignature($body, $signature, $SIGNATURE_KEY, $NOTIFICATION_URL)) {
$result2 = $body->getInvoicePaymentMadeEventData();
}catch(ApiException $e){

$result2 = $body->getInvoicePaymentMadeEventData(); this is actually the line of code that is throwing the error… please what am i doing wrong.

I also want you to note that I have logged the data and I got the correct json response…

The error message you’re encountering, “Call to a member function getInvoicePaymentMadeEventData() on string,” indicates that you are trying to call the getInvoicePaymentMadeEventData() method on a string object. This method is likely intended to be called on an object of a specific class, but in your code, it’s being called on a string.

To solve this, you should first check the data type of the variable $body and ensure that it’s an object that has the getInvoicePaymentMadeEventData() method. Here are some steps to follow:

  1. Check Variable Type: Before calling the method, check the type of the $body variable. You can use the var_dump() or gettype() function to determine its type. Make sure it’s an object of the expected class.

    var_dump($body); // Check the type of $body
  2. Verify Object Structure: Ensure that the object you are trying to work with ($body) has the getInvoicePaymentMadeEventData() method defined within its class. The method should be part of the object’s class definition.

  3. Data Source: If $body is supposed to contain data from an external source, double-check the source to ensure that it is providing the expected data in the expected format.

  4. Exception Handling: If you anticipate that $body might not always contain the expected object, you should implement proper error handling to avoid calling the method on an invalid or unexpected object type. This can help prevent fatal errors like the one you’re encountering.

Here’s an example of how you can add more robust error handling to your code:

if (WebhooksHelper::isValidWebhookEventSignature($body, $signature, $SIGNATURE_KEY, $NOTIFICATION_URL)) {
    try {
        // Check if $body is an object before calling the method
        if (is_object($body) && method_exists($body, 'getInvoicePaymentMadeEventData')) {
            $result2 = $body->getInvoicePaymentMadeEventData();
            // Process $result2
        } else {
            // Handle the case where $body is not the expected object
            // You might log an error or take appropriate action here
    } catch (ApiException $e) {

By following these steps and verifying the type and structure of the $body object, you should be able to resolve the error and ensure that the method is only called on valid objects. :slightly_smiling_face: