CheckoutAPI Subscription Plan Correct Usage

I really hope someone at Square can help me to understand the correct process for creating a subscription plan using the Checkout API. So far, I have had nothing but troubles.

First, I will describe what I need to do, which should seem obvious given that we are creating a subscription:

  1. I need to send the user to a Square-hosted page to sign up/pay
  2. I need to then be able to somehow track that the user has paid and is up to date

Following the guide here, I expect that Square will create both a customer object and a subscription object. However, the webhooks that are sent during this checkout process contain no information whatsoever about the customer or subscription, and there does not seem to be anyway to obtain that information afterwards. I cannot retrieve the customer or subscription based on any of the pieces of information sent in the webhooks.

The order objects sent with the webhooks do not contain the customer or subscription information. I would expect that they would, or maybe they do, but only if you specify an existing customer in the inital request? But this is difficult to determine as the sandbox environment behaves strangely, and also because I cannot figure out the correct way to specify both an existing subscription plan in the ‘create payment link’ request in addition to providing a customer id.

Square suggests that I can look up the customer by phone number, which would be great, since our database has their phone number already stored. But the customer could enter any phone number during signup, so this is actually not helpful.

As far as I can see, the only alternative is to create a customer using the customer API and then use that customer ID when sending the ‘create payment link’ request. However, in order to do that, I am required to create an order. So I settled on this code, after creating a customer via the customersAPI:

const checkoutResponse = await checkoutApi.createPaymentLink({
            idempotencyKey: randomUUID(),
            checkoutOptions: {
                subscriptionPlanId: plan.id,
                redirectUrl: 'https://our.website',
            },
            order: {
                locationId: locationId,
                customerId: customer.id,
                lineItems: [
                    {
                        quantity: '1',
                        basePriceMoney: {
                            amount: costInfo.recurringPriceMoney.amount,
                            currency: costInfo.recurringPriceMoney.currency
                        },
                        catalogObjectId: plan.id
                    }
                ],
                pricingOptions: {
                    autoApplyTaxes: true
                }
            }
        });

where plan refers to a CatalogObject which is a subscription type. However, when I make this request, I receive an error response:

INVALID_REQUEST_ERROR
NOT_FOUND
Item variation with catalog object ID `SWWHQL7GVINH2BSBJ76X2Z4P` not found.

However, this subscription plan does exist, as I can confirm in the API Explorer retrieve catalog object endpoint. It’s not clear to me what other order information is required.

So, my question is:
What is the correct way to create a payment link for a subscription plan, using the Checkout API and an existing customer, OR is there some other way that I can retrieve the subscription and customer information after they have successfully subscribed?

I would love some clear explanation as I find the guide that I linked to be lacking in specifics and the API Explorer explanations of what fields are required/mutually exclusive seem to me to be confusing and/or non-existent. Maybe there is something I have overlooked somewhere, I’m not sure. I also have some suggestions:

  • The checkout API should allow creation of a subscription payment link using nothing more than this, if an order is created anyway:
const checkoutResponse = await checkoutApi.createPaymentLink({
            idempotencyKey: randomUUID(),
            checkoutOptions: {
                subscriptionPlanId: plan.id,
                redirectUrl: 'https://our.website/',
            }
}
  • I should also be able to add an existing customer id, and/or there should be a webhook that relates the information that was created behind the scenes, like the customer and the subscription

I appreciate any help with this issue! Thanks in advance!

:wave: With Subscriptions create with Checkout API you’ll want to listen to invoice webhooks. With the invoice events your get the subscription_id for the newly generated subscription as well as the customer_id. Here is an example invoice webhook event:

{
    "merchant_id": "0F5SS1WQBNTGG",
    "location_id": "3Z4V4WHQK64X9",
    "type": "invoice.payment_made",
    "event_id": "102bcfc0-08f6-5356-9b99-6c615af857e0",
    "created_at": "2022-08-19T21:18:50Z",
    "data": {
        "type": "invoice",
        "id": "inv:0-ChDOu8PMr2qLKqx9V9rQq4j5EOcN",
        "object": {
            "invoice": {
                "accepted_payment_methods": {
                    "bank_account": false,
                    "card": true,
                    "square_gift_card": false
                },
                "created_at": "2022-08-19T21:18:47Z",
                "delivery_method": "EMAIL",
                "description": "Daily • August 19 - August 20, 2022",
                "id": "inv:0-ChDOu8PMr2qLKqx9V9rQq4j5EOcN",
                "invoice_number": "10011",
                "location_id": "3Z4V4WHQK64X9",
                "order_id": "fIZfjLp1VUPMEUVCQHcf8CqWM8MZY",
                "payment_requests": [
                    {
                        "automatic_payment_source": "CARD_ON_FILE",
                        "card_id": "ccof:w6rl3taGx6RoK8iU3GA",
                        "computed_amount_money": {
                            "amount": 100,
                            "currency": "USD"
                        },
                        "due_date": "2022-08-19",
                        "request_type": "BALANCE",
                        "tipping_enabled": false,
                        "total_completed_amount_money": {
                            "amount": 100,
                            "currency": "USD"
                        },
                        "uid": "08eda10c-a2f5-4385-b7ba-be7e610124d7"
                    }
                ],
                "primary_recipient": {
                    "address": {
                        "address_line_1": "500 Electric Ave",
                        "address_line_2": "Suite 600",
                        "address_line_3": "",
                        "administrative_district_level_1": "NY",
                        "country": "US",
                        "locality": "New York",
                        "postal_code": "10003",
                        "sublocality": ""
                    },
                    "company_name": "Square",
                    "customer_id": "W1Z6ER5M88TJ1EEW32FJJ5PX84",
                    "email_address": "[email protected]",
                    "family_name": "Square",
                    "given_name": "Bryan",
                    "phone_number": "1-916-555-4240"
                },
                "public_url": "https://squareup.com/pay-invoice/inv:0-ChDOu8PMr2qLKqx9V9rQq4j5EOcN",
                "status": "PAID",
                "subscription_id": "ff780f8b-225b-4ff0-bd2b-269d3925a3b4",
                "timezone": "America/Los_Angeles",
                "title": "One-phase subscription plan for testing checkout  link. Subscription",
                "updated_at": "2022-08-19T21:18:49Z",
                "version": 3
            }
        }
    }
}

:slightly_smiling_face:

Thanks for the quick response! I have a follow-up question: will that invoice webhook trigger in sandbox mode? I think I only saw order and payment webhook events before when I used the dummy checkout page, but I will double-check. If not, how could I test it? Thanks for you advice.

Nate

Hmm, doesn’t look like they’re being triggered in Sandbox. I’m checking with the team as to why. I tested in production so it works as expected in production. :slightly_smiling_face:

I am trying to test in production mode by creating a subscription plan that costs $0.00/month, but I can’t receive any webhooks because I am stuck on the payment page with the error ‘We are unable to complete your request at this time. Please try again.’ But I am using a valid card, so maybe it just doesn’t allow a subscription that is $0/month? Either way, I am blocked from being able to test out this API due to limitations of both the sandbox and production mode.

:wave: Currently the minimum amount for a subscription needs to be $1.00. :slightly_smiling_face: