PayPal makes it possible to accept payments via just a few pieces of HTML on your site with its Website Payments Standard service. This service includes a Subscriptions button to sell products or services with recurring payments.
The trouble is, PayPal doesn’t make it as easy to cancel a subscription on your site. The documentation on cancelling a subscription only provides instructions for manually cancelling a subscription from the PayPal administration interface.
The good news is, there is another, undocumented method to cancel subscriptions on your site.
Enter Express Checkout
Although PayPal Standard has no API for cancelling a subscription, PayPal offers another product which has a more comprehensive API – Express Checkout.
The gotcha here is that although Website Payments Standard and Express Checkout have distinct branding and documentation, some PayPal Express Checkout API operations can actually be performed with the values of a PayPal Standard transaction.
The API operation for cancelling subscriptions is ManageRecurringPaymentsProfileStatus.
ManageRecurringPaymentsProfileStatus
When a customer creates a subscription with PayPal Standard, PayPal notifies your site with an IPN request. The request contains a set of name values pairs which will look something like this:
[txn_type] => subscr_signup [subscr_id] => I-NARPL1C00000 [last_name] => User [residence_country] => US [mc_currency] => USD [item_name] => Digital Subscription [business] => seller@example.com [recurring] => 1 [verify_sign] => AFcWxV21C7fd0v3bYYYRCpSSRl31AEFeAejFlhh0AvqwNRts6zLECRVi [payer_status] => verified [test_ipn] => 1 [payer_email] => buyer@example.com [first_name] => Test [receiver_email] => seller@example.com [payer_id] => K48P3FBQAAAAA [invoice] => your_invoice_id [reattempt] => 1 [recur_times] => 4 [subscr_date] => 18:13:30 Apr 17, 2012 PDT [custom] => 25 [charset] => windows-1252 [notify_version] => 3.4 [period1] => 1 D [mc_amount1] => 11.00 [period3] => 1 D [mc_amount3] => 5.50 [ipn_track_id] => baca1234
The most important part of this request is the subscr_id. This field is actually equivalent to a PayPal Express Checkout Recurring Payment Profile ID and can be passed as the PROFILEID of a ManageRecurringPaymentsProfileStatus NVP API operation.
Example
The full documentation on the ManageRecurringPaymentsProfileStatus NVP API operation is available here. Unfortunately it lacks an example.
Here’s an example function in PHP for calling the ManageRecurringPaymentsProfileStatus API operation:
/**
* Performs an Express Checkout NVP API operation as passed in $action.
*
* Although the PayPal Standard API provides no facility for cancelling a subscription, the PayPal
* Express Checkout NVP API can be used.
*/
function change_subscription_status( $profile_id, $action ) {
$api_request = 'USER=' . urlencode( 'api_username' )
. '&PWD=' . urlencode( 'api_password' )
. '&SIGNATURE=' . urlencode( 'api_signature' )
. '&VERSION=76.0'
. '&METHOD=ManageRecurringPaymentsProfileStatus'
. '&PROFILEID=' . urlencode( $profile_id )
. '&ACTION=' . urlencode( $action )
. '&NOTE=' . urlencode( 'Profile cancelled at store' );
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, 'https://api-3t.sandbox.paypal.com/nvp' ); // For live transactions, change to 'https://api-3t.paypal.com/nvp'
curl_setopt( $ch, CURLOPT_VERBOSE, 1 );
// Uncomment these to turn off server and peer verification
// curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
// curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_POST, 1 );
// Set the API parameters for this transaction
curl_setopt( $ch, CURLOPT_POSTFIELDS, $api_request );
// Request response from PayPal
$response = curl_exec( $ch );
// If no response was received from PayPal there is no point parsing the response
if( ! $response )
die( 'Calling PayPal to change_subscription_status failed: ' . curl_error( $ch ) . '(' . curl_errno( $ch ) . ')' );
curl_close( $ch );
// An associative array is more usable than a parameter string
parse_str( $response, $parsed_response );
return $parsed_response;
}
Usage
To use this function, you will need to replace 'api_username', 'api_password' and 'api_signature' with your PayPal API credentials.
To cancel the subscription responsible for the IPN request above, we just pass in the value from the subscr_id field in the IPN request.
change_subscription_status( 'I-NARPL1C00000', 'Cancel' );
We can also use it to suspend a profile:
change_subscription_status( 'I-NARPL1C00000', 'Suspend' );
Or reactivate a suspended profile:
change_subscription_status( 'I-NARPL1C00000', 'Reactivate' );
Limitations
There are still a few limitations for which I haven’t been able to find a work around.
Shooting in the Dark
To suspend a subscription, it must be active. To reactivate a subscription, it must be suspended. Express Checkout provides an API operation to find the current state of a subscription – GetRecurringPaymentsProfileDetails (documented here).
Unfortunately, PayPal doesn’t allow this operation to use a subscr_id value as a PROFILEID. As a result, you’ll need to just shoot blind when managing a subscription and deal with any failures.
For reference, the parsed response of a failed ManageRecurringPaymentsProfileStatus request will look something like this:
[TIMESTAMP] => 2012-06-29T06:54:22Z [CORRELATIONID] => ebe0a10c134 [ACK] => Failure [VERSION] => 76.0 [BUILD] => 3067390 [L_ERRORCODE0] => 11556 [L_SHORTMESSAGE0] => Invalid profile status for cancel action; profile should be active or suspended [L_LONGMESSAGE0] => Invalid profile status for cancel action; profile should be active or suspended [L_SEVERITYCODE0] => Error
No IPN
Compounding the problem above, PayPal sends no IPN message when a profile is suspended. If a user suspends a profile with PayPal directly, the profile will fall out of sync with your site.
You should also record the subscription status as suspended when making a successful ManageRecurringPaymentsProfileStatus request, instead of waiting for an IPN request.
An Easier Way to Sell Subscriptions
If you want to sell subscriptions with PayPal, but you don’t know a server-side programming language, or you just value your sanity enough to avoid the PayPal API, then checkout my WooCommerce Subscriptions extension.
Combined with the featured-packed WooCommerce and ease-of-use of WordPress, Subscriptions makes it easy to sell products & services with recurring payments. And it uses the method described here, so even subscriptions created with PayPal Standard can be cancelled, suspended and reactivated directly from your store.
UPDATE 11 Feburary 2013
There is one caveat – the subscription must have been purchased after 2009 for this method to work.
wow.. the best explanation ive found so far to manage paypal subcription. Do you have any article how to create the subscription? Read your other article, but it seems you use URL parameter? I usually use form _xclick-subscription! And bit confuse about subscr_payment and recurring_payment. if you care to explain include tutorial would be great
Hi Tono, take a look at the HTML Variables for Subscriptions section.
These are all the options you can send along with
_xclick-subscriptions. They can be sent either through a HTML form, e.g add a one month free trial period:Or as GET parameters in a URL string, e.g. add a one month free trial period:
Hi Brent, thanks it helps a lot..
Do you know the difference ‘subscr_payment’ and ‘recurring_payment’?
And Do you know how to set Initial payment for subscription? at the moment i use trial fee as initial payment. Dont know wether its the right option to do..
I think
subscr_paymentpayment is for subscriptions created with PayPal Standard whilerecurring_paymentis for those created with Express Checkout.Regarding initial payments. There is no option to create an initial payment for subscriptions created in Website Payments Standard, so I’ve done the same thing you do (which is use the trial period to add it to the first payment only).
Good post. What I do not understand why my all subscription payments id start with S- and not with I-. When I post for example PROFILEID=S-7J596251UT364050T I get the error “The profile ID is invalid”.
A payment transaction ID is different to a subscription’s Profile ID. Make sure you are using the Profile ID for the subscription and not the transaction ID for a payment which forms part of that subscription.
I’m getting this response from PayPal. Guess they’ve shut down the ManageRecurringPaymentsProfileStatus method for express checkout? Any help would be greatly appreciated…
ACK: Failure
L_ERRORCODE0: 81002
L_SHORTMESSAGE0: Unspecified Method
L_LONGMESSAGE0: Method Specified is not Supported
L_SEVERITYCODE0: Error
Hi Alexander, I just tested it again and it’s still working for me. All I can suggest is to make sure each of your NVP variables & values are correct – PayPal has been known to provide an error message that has nothing to do with the real problem.
Hi Brent,
I have used your code to cancel the subscription using its profile ID like I-GY3M2WDV****. But, I’m getting the following Error from Paypal Sandbox.
[TIMESTAMP] => 2012-12-05T05:04:33Z
[CORRELATIONID] => b2d9399f85ff6
[ACK] => Failure
[VERSION] => 76.0
[BUILD] => 4181146
[L_ERRORCODE0] => 11552
[L_SHORTMESSAGE0] => Invalid profile ID
[L_LONGMESSAGE0] => The profile ID is invalid
[L_SEVERITYCODE0] => Error
I’m sure, I have that profile Id in my paypal sandbox. Even though, its returning error as such. Could you please tell me about the problem with me??
Thanks
Hi Mohan, all I can do is suggest checking the request and making sure the profile ID is being sent as you see it (i.e. not have any URL encoding/HTML escaping issues). If that fails, try creating a new profile and testing with that ID. I have since learned that only profiles created after 2009 will work via this method, so that might be the problem?
Pingback: [PHP]Paypal APIで月額課金を止める方法と不正利用されない方法 | 田舎暮らしフリーランスへの道
Great! This is very well explained and most important it has a code example.
Thank you very much!
Hi
I have created a recurring profile using subscribe button of Paypal on sandbox. But when i try to cancel it using the following code
$api_request = ‘USER=’ . urlencode( ‘api_username’ )
. ‘&PWD=’ . urlencode( ‘api_password’ )
. ‘&SIGNATURE=’ . urlencode( ‘api_signature’ )
. ‘&VERSION=76.0′
. ‘&METHOD=ManageRecurringPaymentsProfileStatus’
. ‘&PROFILEID=’ . urlencode( $profile_id )
. ‘&ACTION=’ . urlencode( $action )
. ‘&NOTE=’ . urlencode( ‘Profile cancelled at store’ );
it gives me the following error
Array
(
[TIMESTAMP] => 2013-02-08T10:19:58Z
[CORRELATIONID] => 66adc7d019253
[ACK] => Failure
[VERSION] => 76.0
[BUILD] => 5060305
[L_ERRORCODE0] => 11552
[L_SHORTMESSAGE0] => Invalid profile ID
[L_LONGMESSAGE0] => The profile ID is invalid
[L_SEVERITYCODE0] => Error
)
does “ManageRecurringPaymentsProfileStatus” this method not cancel the recurring created by standard paypal? if it cancels, then what to do? Please help.
Based on the error message, I’d say check the Subscription ID/Profile ID you’re using in the request. Make sure it’s not the transaction ID.
Hi Brent –
Thanks for your response. I am using the following
Profile start date Feb 7, 2013 | Profile ID No. I-XNEK7EVPSW4M
I have copied it from my paypal account.
Can we cancel the recurring created by PayPal standard by using ManageRecurringPaymentsProfileStatus
?
Please confirm.
Thanks
Yes, you should be able too. That’s what the article is about.
Hi
Can it be done on sandbox?
Yes
Hi Brent –
We created the recurring using the following code .
and the profile id that created was Profile ID No. I-XNEK7EVPSW4M.
when i used the above mentioned code i.e. ManageRecurringPaymentsProfileStatus to remove the recurring, it did not work.
Can you please tell me where I am wrong?
Thanks
I have no idea why it’s not working for you and you’ll need to figure that out for yourself now. PayPal is notoriously complicated, undocumented & inconsistent, so it could be how you’re creating the profile, the country your account is registered in or something completely different. I’d suggest contacting PayPal support and if you still can’t get it to work, use PayPal Express Checkout.
Hi Brent –
Thanks for your help. When i created a new profile in sandbox paypal and used its credentials then it started to work. Thanks you for your support.