question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

PayPal Subscriptions incorrect start_time and next_billing_time dates on Live and Sandbox

See original GitHub issue

In short: Subscription webhooks (like BILLING.SUBSCRIPTION.ACTIVATED) and subscription details API endpoint return incorrect start_time which is always previous date at 23:00 and incorrect next_billing_time close to create_time which is in the past, regardless of subscription duration period on both Live and Sandbox.

In details: We are using PayPal JS SDK (paypal.com/sdk/js) to create a subscription payment button, webhooks for notifications and subscriptions REST API V1 to retrieve details. We’ve setup monthly recurring plan with 7 days trial with following billing details:

billing cycle: Every 1 month (pays at beginning of each billing cycle) Number of billing cycles: As long as plan is offered Trial period price: $0.00 USD for 7 days (no tax) Stop collecting payments after: 1 missed billing cycles

When subscription is created using payment button the app receives subscriptionID and we immediately retrieve its details using API V1 (https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_get) which returns a response with incorrect both start_time (the previous day) and next_billing_time (in the past, but should be in 7 days) (irrelevant details are omitted for shorter output)

{
    "status": "ACTIVE",
    "status_update_time": "2020-06-12T09:47:21Z",
    "id": "I-VG4D3KBL67JT",
    "plan_id": "P-2EC848750R2281112L3QLJPI",
    "start_time": "2020-06-11T23:00:00Z",
    "quantity": "1",
    "shipping_amount":{},
    "subscriber":{},
    "billing_info":
    {
        "outstanding_balance":{},
        "cycle_executions": [],
        "next_billing_time": "2020-06-12T09:47:21Z",
        "failed_payments_count": 0
    },
    "create_time": "2020-06-12T09:46:49Z",
    "update_time": "2020-06-12T09:47:21Z",
    "transactions": null
}

Then comes in the BILLING.SUBSCRIPTION.ACTIVATED webhook with the same incorrect dates

{
	"id": "WH-8H756832S2001654V-1X369026W1516043G",
	"event_version": "1.0",
	"create_time": "2020-06-12T09:47:37.837Z",
	"resource_type": "subscription",
	"resource_version": "2.0",
	"event_type": "BILLING.SUBSCRIPTION.ACTIVATED",
	"summary": "Subscription activated",
	"resource":
	{
		"shipping_amount":{},
		"start_time": "2020-06-11T23:00:00Z",
		"update_time": "2020-06-12T09:47:21Z",
		"quantity": "1",
		"subscriber":{},
		"billing_info":
		{
			"outstanding_balance":{},
			"cycle_executions": [],
			"next_billing_time": "2020-06-12T09:47:21Z",
			"failed_payments_count": 0
		},
		"create_time": "2020-06-12T09:46:49Z",
		"links": [],
		"id": "I-VG4D3KBL67JT",
		"plan_id": "P-2EC848750R2281112L3QLJPI",
		"status": "ACTIVE",
		"status_update_time": "2020-06-12T09:47:21Z"
	},
	"links": []
}

BUT! If I manually request subscription details using API V1 later on using the same endpoint it returns correct next_billing_time (in 7 days from start time)

{
    "status": "ACTIVE",
    "status_update_time": "2020-06-12T09:50:26Z",
    "id": "I-VG4D3KBL67JT",
    "plan_id": "P-2EC848750R2281112L3QLJPI",
    "start_time": "2020-06-11T23:00:00Z",
    "quantity": "1",
    "shipping_amount": {},
    "subscriber": {},
    "billing_info": {
        "outstanding_balance": {},
        "cycle_executions": [],
        "next_billing_time": "2020-06-19T10:00:00Z",
        "failed_payments_count": 0
    },
    "create_time": "2020-06-12T09:46:49Z",
    "update_time": "2020-06-12T09:50:26Z",
}

This behaviour is the same on Sandbox and Live even for plans that don’t have free trial period like 6 months plan and subscription details api response has the same incorrect dates

{
    "status": "ACTIVE",
    "status_update_time": "2020-06-12T09:50:39Z",
    "id": "I-VAETFF0V9BAP",
    "plan_id": "P-8FP363974T0998009L3QLJ6Q",
    "start_time": "2020-06-11T23:00:00Z",
    "quantity": "1",
    "shipping_amount":{},
    "subscriber":{},
    "billing_info":
    {
        "outstanding_balance":{},
        "cycle_executions": [],
        "next_billing_time": "2020-06-12T09:50:37Z",
        "failed_payments_count": 0
    },
    "create_time": "2020-06-12T09:49:57Z",
    "update_time": "2020-06-12T09:50:39Z",
    "transactions": null
}

The same dates are in BILLING.SUBSCRIPTION.ACTIVATED webhook event.

But later on the same request returns correct next_billing_time

{
    "status": "ACTIVE",
    "status_update_time": "2020-06-12T09:55:27Z",
    "id": "I-VAETFF0V9BAP",
    "plan_id": "P-8FP363974T0998009L3QLJ6Q",
    "start_time": "2020-06-11T23:00:00Z",
    "quantity": "1",
    "shipping_amount": {},
    "subscriber": {},
    "billing_info": {
        "outstanding_balance": {},
        "cycle_executions": [],
        "last_payment": {
            "amount": {},
            "time": "2020-06-12T09:50:38Z"
        },
        "next_billing_time": "2020-12-12T10:00:00Z",
        "failed_payments_count": 0
    },
    "create_time": "2020-06-12T09:49:57Z",
    "update_time": "2020-06-12T09:55:27Z",
    "links": []
}

This is a big issue as our system determines subscription duration based on payment provider details as it could be any period (free 7 trial or paid 6 month etc.) but PayPal API returns inconsistent and unreliable results especially critical is next_billing_time which is in the past, but after some time (not sure how long the delay is) the same endpoint returns correct next_billing_time.

P.S. All the response details are from Sandbox, but I can provide Live details as well privately.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:10
  • Comments:41 (1 by maintainers)

github_iconTop GitHub Comments

17reactions
ravishekharcommented, Aug 14, 2020

We are working on the fix. The fix will be available by 8/31. Will update the thread once changes are rolled out.

9reactions
CaptainBeOScommented, Oct 6, 2020

I read elsewhere that PayPal have no intention of changing this behaviour, which led me to understand that we all must be missing something. After much digging and experimenting I can share the solution to this problem with you all and hope nobody else wastes so much time.

It seems that when the initial BILLING.SUBSCRIPTION.ACTIVATED event is triggered it is done so BEFORE the payment has actually cleared. The fact that the subscription is marked as ACTIVE is in my opinion misleading. It should be APPROVED at this stage. The dates you see on the JSON object reflect the fact that the next payment is due now. According to the API documentation next_billing_time is always 10:00am GMT on the day payment is due, which may well be in the past as we have all observed.

It turns out that the dates get updated, not 20 minutes later, but as soon as the payment is cleared. Wait for the PAYMENT.SALE.COMPLETED webhook and then call the Get subscription details API. Yes, the only way out of this pickle is to make this API call.

curl -v -X GET https://api.sandbox.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Access-Token"

The resulting object will be correct.

This makes more sense if you start playing with delayed subscription start_times as I did. For delayed start times you will get the BILLING.SUBSCRIPTION.ACTIVATED as soon as the subscription is created and the start_time in that object will be the start of the day indicated by the start_time you passed in the API or in the Javascript SDK and next_billing_time will be 10:00am GMT on that date . Your customer is not billed until start_time passes and then when the sale completes you get PAYMENT.SALE.COMPLETED and that is your chance to activate the subscription with the condition that start_time has passed and status = ‘ACTIVE’.

This also translates to renewals. I spent an age trying to find any indication what happens when there is a successful renewal. The webhook to use for renewals is also PAYMENT.SALE.COMPLETED. Query the subscription details API again and the resulting object will contain the new next_billing_time.

I’ve not got far enough in my investigations to work out the conclusion to the following hypothisis: However I suspect that there is very little need to store next_billing_time as you all seem to be aiming for. Paypal alleges that they will send BILLING.SUBSCRIPTION.SUSPENDED webhook events if payment fails. That being the case responding to PAYMENT.SALE.COMPLETED and BILLING.SUBSCRIPTION.SUSPENDED alone (possibly also BILLING.SUBSCRIPTION.CANCELLED) by querying the subscription details API to get the “status” and “start_time”, should, when coupled with the condition that start_time has passed and status = ‘ACTIVE’, be sufficient to determine that a subscription should continue. We’ll see…

Hope this helps. TTFN

Read more comments on GitHub >

github_iconTop Results From Across the Web

Test and go live with Subscriptions - PayPal Developer
Test the transaction as a buyer. Select the PayPal button on the page. Use the sandbox personal login information from the Developer Dashboard ......
Read more >
Subscriptions API - PayPal Developer
You can use billing plans and subscriptions to create subscriptions that process recurring PayPal payments for physical or digital goods, or services.
Read more >
How subscription billing cycles work - PayPal Developer
PayPal attempts to collect recurring payments from subscribers on the day after the previous billing cycle or trial period ends.
Read more >
Recurring Billing | Advanced Settings - Braintree Support ...
If you choose to continue retrying the subscription, we will only retry it once per billing cycle, on the subscription's usual billing date....
Read more >
Subscriptions - PayPal Developer
Create a plan to represent the payment cycles for your subscription. Use the PayPal JavaScript SDK to present the PayPal button. When the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found