PayPal Subscriptions incorrect start_time and next_billing_time dates on Live and Sandbox
See original GitHub issueIn 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:
- Created 3 years ago
- Reactions:10
- Comments:41 (1 by maintainers)
We are working on the fix. The fix will be available by 8/31. Will update the thread once changes are rolled out.
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.
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