Hi All,
Working on my open source community platform and just finished making my PayPal integration work. It was fairly straightforward once I went through the PayPal API docs. I didn’t care to make the button look like the ‘real’ button so I just used a regular Anvil button.
The API works like so:
- User needs to call the Subscriptions API with a Plan ID to create a URL to the plan’s checkout page. That API returns the URL as well as a new subscription ID.
- You need to point it to an API endpoint as the return_url and cancel_url to capture whether the payment was successful or if the user canceled the checkout.
- You now have the subscription ID in the Users table which you can use to manage or check up on a user’s subscription status.
Anyway, here’s some client code for a button:
def btn_pay_new_click(self, **event_args):
"""This method is called when the button is clicked"""
from anvil.js import window
self.user['paypal_sub_id'], self.payment_url = anvil.server.call(
'create_sub', self.user['fee']
)
self.btn_save_click()
window.open(self.payment_url)
self.refresh_data_bindings()
And server code:
@anvil.server.callable(require_user=True)
def create_sub(plan_amt):
import requests
access_token = get_paypal_auth()
print(anvil.server.get_app_origin())
if plan_amt == 10:
plan_id = anvil.secrets.get_secret('pp_plan_id_10')
else:
plan_id = anvil.secrets.get_secret('pp_plan_id_50')
try:
response = anvil.http.request(
'https://api.paypal.com/v1/billing/subscriptions',
method='POST',
headers={
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
},
data={
'plan_id': plan_id,
'application_context': {
'return_url': anvil.server.get_api_origin() + '/capture-sub',
'cancel_url': anvil.server.get_api_origin() + '/cancel-sub'
}
},
json=True
)
return response['id'], response['links'][0]['href']
except anvil.http.HttpError as e:
print(f"Error {e.status} {e.content}")
@anvil.server.http_endpoint('/capture-sub')
def capture_sub(**params):
row = app_tables.users.get(paypal_sub_id=params['subscription_id'])
row['good_standing'] = True
return 'Payment success! You can close this tab.'
@anvil.server.http_endpoint('/cancel-sub')
def cancel_sub(**params):
row = app_tables.users.get(paypal_sub_id=params['subscription_id'])
row['paypal_sub_id'] = None
return 'You have cancelled enrollment. You can close this tab.'
Check out our GitHub repo: