diff --git a/docs/getting-started/index.html b/docs/getting-started/index.html index 751bc3f..73346f9 100644 --- a/docs/getting-started/index.html +++ b/docs/getting-started/index.html @@ -322,7 +322,7 @@

1. Set Paddle environment to live

PADDLE_SUBSCRIPTIONS["ENVIRONMENT"] = "live"
 

Make sure that PADDLE_SUBSCRIPTIONS["WEBSITE_URL"] points to the URL of the production website, which has to be approved by Paddle.

-

Remove the PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS'] setting.

+

Remove the PADDLE_SUBSCRIPTIONS["RESTRICTED_TO_IPS"] setting.

2. Flush staging data and set up Paddle subscription anew

(venv)$ python manage.py flush_paddle_billing_models
 (venv)$ python manage.py set_up_paddle_subscriptions
diff --git a/docs/index.html b/docs/index.html
index b5846da..ac6bc88 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -344,5 +344,5 @@ 
 
 
diff --git a/docs/search/search_index.json b/docs/search/search_index.json
index 482b2d7..96082bf 100644
--- a/docs/search/search_index.json
+++ b/docs/search/search_index.json
@@ -1 +1 @@
-{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Django Paddle Subscriptions Why do you need it? For SaaS (Software as a Service) businesses expanding into global markets, partnering with a reseller like Paddle can be a strategic move to navigate complex tax regulations and streamline operations. Resellers like Paddle act as intermediaries, handling payments, tax compliance, currency conversions, and localized pricing for their partners, freeing up SaaS companies to focus on their core product offerings. The rules for VAT (Value Added Tax) and sales tax are varied from country to country. For example, in the EU, VAT is charged based on the customer's location, regardless of the SaaS provider's headquarters. This means that SaaS businesses outside the EU may need to register for VAT to collect and remit taxes. Paddle simplifies this process by registering for VAT on behalf of its partners and automatically collecting the appropriate tax from each customer. Similarly, in the US, sales tax regulations vary from state to state. Resellers like Paddle typically handle sales tax compliance, ensuring that SaaS businesses only collect taxes in the jurisdictions where they are legally required. This can save businesses time and money, as they don't need to maintain their tax expertise or register for sales tax in multiple states. Also, buying power varies greatly between different countries around the world. In wealthier countries like the United States and Western Europe, people generally have more money to spend due to higher incomes and stronger currencies. However, in less developed countries across Africa, Asia, and parts of Latin America, buying power tends to be lower because people earn less money and the cost of living is often higher relative to their incomes. Django Paddle Subscriptions is a Django app for SaaS projects implementing free and paid subscriptions using Paddle Billing API . It saves you at least a month of work on implementation. And it is pretty flexible and configurable to meet your business needs. Who is it for? The Django Paddle Subscriptions app is for business owners and tech entrepreneurs who want to provide Django-based SaaS globally. Feature Value Supported modern browsers Chrome, Firefox, Safari, Opera, Microsoft Edge Supported Django versions 4.2, 5.0 Supported Python versions 3.10, 3.11, 3.12 Default styling with TailwindCSS \u2714\ufe0e Translatable \u2714\ufe0e Configurable \u2714\ufe0e Localized pricing widget \u2714\ufe0e Offered free and paid plans \u2714\ufe0e Subscriptions before or after signup \u2714\ufe0e Monthly and yearly pricing \u2714\ufe0e List of paid invoices \u2714\ufe0e Pausing and cancelling subscriptions \u2714\ufe0e Copy of Paddle data in your database \u2714\ufe0e Multiple SaaS with the same Paddle account \u2714\ufe0e Infrastructure for upsells \u2714\ufe0e Latest package version 1.3.0 What are the benefits? There are lots of benefits: Saves at least a month of development work. Highly flexible and configurable. Can be used for as many Django-based SaaS projects as necessary. The frontend is styled with TailwindCSS for quick start, but you can overwrite the templates and introduce your custom styling. Comes with handy management commands to fetch Paddle data and set up the environment. Allows using the same Paddle account for multiple Django-based SaaS projects. Developed with internationalization in mind. Compatible with Content-Security-Policy via Django-CSP. MIT license applied. Designed and implemented by the author of \"Web development with Django Cookbook.\" How does it work? You will need a seller's account at Paddle and your business and SaaS domains approved (which might take from a few days to two weeks). At first, implement the payments in the sandbox environment . At Paddle, create Products for each subscription plan and one monthly and one yearly price for each plan. For example, Premium plan as a product will have two prices: Premium monthly and Premium yearly. At your Django website, fetch all data from Paddle, create subscription plans, and attach the prices to the subscription plans accordingly. Check these workflows: Pricing \u2794 Subscription \u2794 Signup \u2794 Billing history Signup \u2794 Pricing \u2794 Subscription \u2794 Billing history Pausing subscription \u2794 Resuming subscription \u2794 Cancelling subscription Pausing subscription \u2794 Cancelling subscription When ready to go live, create the same products and prices at the live environment . Flush the Paddle data on your server, fetch the data from the live server, and connect the prices to your subscription plans. Create a 100% discount code and test subscriptions with that code on the live environment. Examples Django Paddle Subscriptions are used in production at these websites: 1st things 1st Remember Your People Credits The Django Paddle Subscriptions app under the hood uses paddle-billing-client , which was thoroughly crafted by Benjamin Gervan. In addition to that, Django Paddle Subscriptions uses currencies , django-ipware , and func-timeout . Disclaimer Django Paddle Subscriptions app is provided without any warranties or guarantees, either explicit or implied. The user is responsible for using the app responsibly and in compliance with all applicable laws and regulations. The user is also solely responsible for any financial losses or other issues that may arise from using the app. By using this app, the user agrees to indemnify and hold harmless the app's author from any claims, damages, losses, liabilities, costs, or expenses (including reasonable attorney's fees) arising from or in connection with the app's use or misuse. Contact For technical questions, feature requests, or bug reports, please contact Aidas Bendoraitis at https://www.djangotricks.com/feedback/ .","title":"Home"},{"location":"#django-paddle-subscriptions","text":"","title":"Django Paddle Subscriptions"},{"location":"#why-do-you-need-it","text":"For SaaS (Software as a Service) businesses expanding into global markets, partnering with a reseller like Paddle can be a strategic move to navigate complex tax regulations and streamline operations. Resellers like Paddle act as intermediaries, handling payments, tax compliance, currency conversions, and localized pricing for their partners, freeing up SaaS companies to focus on their core product offerings. The rules for VAT (Value Added Tax) and sales tax are varied from country to country. For example, in the EU, VAT is charged based on the customer's location, regardless of the SaaS provider's headquarters. This means that SaaS businesses outside the EU may need to register for VAT to collect and remit taxes. Paddle simplifies this process by registering for VAT on behalf of its partners and automatically collecting the appropriate tax from each customer. Similarly, in the US, sales tax regulations vary from state to state. Resellers like Paddle typically handle sales tax compliance, ensuring that SaaS businesses only collect taxes in the jurisdictions where they are legally required. This can save businesses time and money, as they don't need to maintain their tax expertise or register for sales tax in multiple states. Also, buying power varies greatly between different countries around the world. In wealthier countries like the United States and Western Europe, people generally have more money to spend due to higher incomes and stronger currencies. However, in less developed countries across Africa, Asia, and parts of Latin America, buying power tends to be lower because people earn less money and the cost of living is often higher relative to their incomes. Django Paddle Subscriptions is a Django app for SaaS projects implementing free and paid subscriptions using Paddle Billing API . It saves you at least a month of work on implementation. And it is pretty flexible and configurable to meet your business needs.","title":"Why do you need it?"},{"location":"#who-is-it-for","text":"The Django Paddle Subscriptions app is for business owners and tech entrepreneurs who want to provide Django-based SaaS globally. Feature Value Supported modern browsers Chrome, Firefox, Safari, Opera, Microsoft Edge Supported Django versions 4.2, 5.0 Supported Python versions 3.10, 3.11, 3.12 Default styling with TailwindCSS \u2714\ufe0e Translatable \u2714\ufe0e Configurable \u2714\ufe0e Localized pricing widget \u2714\ufe0e Offered free and paid plans \u2714\ufe0e Subscriptions before or after signup \u2714\ufe0e Monthly and yearly pricing \u2714\ufe0e List of paid invoices \u2714\ufe0e Pausing and cancelling subscriptions \u2714\ufe0e Copy of Paddle data in your database \u2714\ufe0e Multiple SaaS with the same Paddle account \u2714\ufe0e Infrastructure for upsells \u2714\ufe0e Latest package version 1.3.0","title":"Who is it for?"},{"location":"#what-are-the-benefits","text":"There are lots of benefits: Saves at least a month of development work. Highly flexible and configurable. Can be used for as many Django-based SaaS projects as necessary. The frontend is styled with TailwindCSS for quick start, but you can overwrite the templates and introduce your custom styling. Comes with handy management commands to fetch Paddle data and set up the environment. Allows using the same Paddle account for multiple Django-based SaaS projects. Developed with internationalization in mind. Compatible with Content-Security-Policy via Django-CSP. MIT license applied. Designed and implemented by the author of \"Web development with Django Cookbook.\"","title":"What are the benefits?"},{"location":"#how-does-it-work","text":"You will need a seller's account at Paddle and your business and SaaS domains approved (which might take from a few days to two weeks). At first, implement the payments in the sandbox environment . At Paddle, create Products for each subscription plan and one monthly and one yearly price for each plan. For example, Premium plan as a product will have two prices: Premium monthly and Premium yearly. At your Django website, fetch all data from Paddle, create subscription plans, and attach the prices to the subscription plans accordingly. Check these workflows: Pricing \u2794 Subscription \u2794 Signup \u2794 Billing history Signup \u2794 Pricing \u2794 Subscription \u2794 Billing history Pausing subscription \u2794 Resuming subscription \u2794 Cancelling subscription Pausing subscription \u2794 Cancelling subscription When ready to go live, create the same products and prices at the live environment . Flush the Paddle data on your server, fetch the data from the live server, and connect the prices to your subscription plans. Create a 100% discount code and test subscriptions with that code on the live environment.","title":"How does it work?"},{"location":"#examples","text":"Django Paddle Subscriptions are used in production at these websites: 1st things 1st Remember Your People","title":"Examples"},{"location":"#credits","text":"The Django Paddle Subscriptions app under the hood uses paddle-billing-client , which was thoroughly crafted by Benjamin Gervan. In addition to that, Django Paddle Subscriptions uses currencies , django-ipware , and func-timeout .","title":"Credits"},{"location":"#disclaimer","text":"Django Paddle Subscriptions app is provided without any warranties or guarantees, either explicit or implied. The user is responsible for using the app responsibly and in compliance with all applicable laws and regulations. The user is also solely responsible for any financial losses or other issues that may arise from using the app. By using this app, the user agrees to indemnify and hold harmless the app's author from any claims, damages, losses, liabilities, costs, or expenses (including reasonable attorney's fees) arising from or in connection with the app's use or misuse.","title":"Disclaimer"},{"location":"#contact","text":"For technical questions, feature requests, or bug reports, please contact Aidas Bendoraitis at https://www.djangotricks.com/feedback/ .","title":"Contact"},{"location":"CHANGELOG/","text":"Changelog All notable changes to this project will be documented in this file. The format is based on Keep a Changelog , and this project adheres to Semantic Versioning . [Unreleased] [v1.3.0] - 2024-02-11 Added Unit tests for fetching information from Paddle Billing. Fixed Saving adjustments fixed. [v1.2.1] - 2024-02-10 Changed Link to documentation [v1.2.0] - 2024-02-10 Added Templates added Markdown files added [v1.1.0] - 2024-02-10 Changed Functions refactored. Fixed Cosmetic styling adjustments. [v1.0.0] - 2024-02-06 Added Paddle Billing models. Custom Django Paddle Subscriptions models. Management commands to fetch data from Paddle Billing. Management command to set up the webhook. Management command to flush Paddle Billing models. Pricing widget. Subscription details page. Pausing and resuming subscriptions. Cancelling subscriptions. Billing history with invoice downloads. Lots of customizations via settings.","title":"Changelog"},{"location":"CHANGELOG/#changelog","text":"All notable changes to this project will be documented in this file. The format is based on Keep a Changelog , and this project adheres to Semantic Versioning .","title":"Changelog"},{"location":"CHANGELOG/#unreleased","text":"","title":"[Unreleased]"},{"location":"CHANGELOG/#v130-2024-02-11","text":"","title":"[v1.3.0] - 2024-02-11"},{"location":"CHANGELOG/#added","text":"Unit tests for fetching information from Paddle Billing.","title":"Added"},{"location":"CHANGELOG/#fixed","text":"Saving adjustments fixed.","title":"Fixed"},{"location":"CHANGELOG/#v121-2024-02-10","text":"","title":"[v1.2.1] - 2024-02-10"},{"location":"CHANGELOG/#changed","text":"Link to documentation","title":"Changed"},{"location":"CHANGELOG/#v120-2024-02-10","text":"","title":"[v1.2.0] - 2024-02-10"},{"location":"CHANGELOG/#added_1","text":"Templates added Markdown files added","title":"Added"},{"location":"CHANGELOG/#v110-2024-02-10","text":"","title":"[v1.1.0] - 2024-02-10"},{"location":"CHANGELOG/#changed_1","text":"Functions refactored.","title":"Changed"},{"location":"CHANGELOG/#fixed_1","text":"Cosmetic styling adjustments.","title":"Fixed"},{"location":"CHANGELOG/#v100-2024-02-06","text":"","title":"[v1.0.0] - 2024-02-06"},{"location":"CHANGELOG/#added_2","text":"Paddle Billing models. Custom Django Paddle Subscriptions models. Management commands to fetch data from Paddle Billing. Management command to set up the webhook. Management command to flush Paddle Billing models. Pricing widget. Subscription details page. Pausing and resuming subscriptions. Cancelling subscriptions. Billing history with invoice downloads. Lots of customizations via settings.","title":"Added"},{"location":"LICENSE/","text":"MIT License Copyright (c) Websightful UG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"License"},{"location":"LICENSE/#mit-license","text":"Copyright (c) Websightful UG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"MIT License"},{"location":"customization/","text":"Customization Conditional Showing of the Pricing Widget You can restrict the showing of pricing widget to specific IPs by setting the PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] setting: PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] = [ \"192.0.2.1\", # Your public IP address required for the staging or production environment \"127.0.0.1\", # Your local IP address required for the development environment ] To find your Public IP address, google for \"what's my ip\". Note that the public IP of a router changes every 2 weeks. Then in the templates of use the request.show_paddle_subscriptions to check whether the pricing widget needs to be included: {% if request.show_paddle_subscriptions %} {% load paddle_subscriptions_tags %}{% paddle_subscriptions_pricing %} {% endif %} Free and Custom Plan Call-to-action URLs If you have a free plan, set the PADDLE_SUBSCRIPTIONS[\"FREE_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the signup or waitlist page. If you have a custom plan, set the PADDLE_SUBSCRIPTIONS[\"CUSTOM_PRICING_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the page with information about it. Display Mode Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_DISPLAY_MODE\"] to \"overlay\" (default) or \"inline\" to display the checkout widget as a dialog box or as part of the layout. If your display mode is \"inline\" , the following settings are required too: PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_TARGET\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_STYLE\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_INITIAL_HEIGHT\"] Read about them at Paddle Billing documentation . Checkout Theme Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] to \"light\" (default) or \"dark\" to display light or dark user interface. In addition, you can pass a function accepting a request parameter which would return the \"light\" or \"dark\" based on user settings or other values: def get_paddle_subscriptions_theme(request): if request.user.is_authenticated and request.user.theme == request.user.ThemeChoices.DARK: return \"dark\" return \"light\" PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] = get_paddle_subscriptions_theme Other Checkout Settings The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_ADD_TAX_ID\"] setting defines whether the field for a tax number should be shown at checkout (default: True). The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_DISCOUNTS\"] setting defines whether the field for a discount code should be shown at checkout (default: True). Use the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_AUTHENTICATED\"] to redirect an authenticated user who has just subscribed to a custom success page. Set the URL path name, path, or URL of that page. If you allow the anonymous visitors to subscribe before signing up, set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_ANONYMOUS\"] to your signup page that handles the connecting the subscription by paddle_transaction_id cookie to the newly registered user (default: \"/signup/\" ). Pausing and Cancelling Subscriptions Set whether subscriptions pausing must happen before the next billing period or immediately with PADDLE_SUBSCRIPTIONS[\"WHEN_TO_PAUSE_SUBSCRIPTIONS\"] and PADDLE_SUBSCRIPTIONS[\"WHEN_TO_CANCEL_SUBSCRIPTIONS\"] settings. Set them to \"next_billing_period\" (default) or \"immediately\" . Administration All Paddle Billing models can be fetched to your Django project via management commands, but not all of them are valuable for introspection. Below are the settings of what to show in administration. Settings for Paddle Billing models: PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_ADMIN\"] (default: True) - show products. PADDLE_SUBSCRIPTIONS[\"SHOW_PRICE_ADMIN\"] (default: True) - show prices. PADDLE_SUBSCRIPTIONS[\"SHOW_DISCOUNT_ADMIN\"] (default: False) - show discounts. PADDLE_SUBSCRIPTIONS[\"SHOW_CUSTOMER_ADMIN\"] (default: True) - show customers. PADDLE_SUBSCRIPTIONS[\"SHOW_ADDRESS_ADMIN\"] (default: False) - show addresses. PADDLE_SUBSCRIPTIONS[\"SHOW_BUSINESS_ADMIN\"] (default: False) - show businesses. PADDLE_SUBSCRIPTIONS[\"SHOW_TRANSACTION_ADMIN\"] (default: True) - show transactions. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_ADMIN\"] (default: True) - show subscriptions. PADDLE_SUBSCRIPTIONS[\"SHOW_ADJUSTMENT_ADMIN\"] (default: False) - show adjustments. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_TYPE_ADMIN\"] (default: False) - show event types. PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_SETTING_ADMIN\"] (default: True) - show notification settings (your webhook URLs). PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_ADMIN\"] (default: False) - show notifications. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_ADMIN\"] (default: True) - show events. Settings for extra Paddle Subscriptions models: PADDLE_SUBSCRIPTIONS[\"SHOW_WEB_PROJECT_ADMIN\"] (default: True) - show web projects when you have more than one SaaS projects using the same Paddle seller's account. PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_CATEGORY_ADMIN\"] (default: True) - show product categories to group your products when you have upsells. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_PLAN_ADMIN\"] (default: True) - show subscription plans. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIBER_ADMIN\"] (default: True) - show subscribers. Templates and CSS The default templates are styled using TailwindCSS. To use them, it is recommended to copy them from site-packages into your project, build your CSS and collect translatable strings, and modify them as necessary. You can replace the CSS classes and markup to Bootstrap, Foundation, Bulma, other CSS framwork, or your custom CSS too. These are the Django Paddle Subscription templates: paddle_subscriptions/ includes/ billing_dates.html - information about the next billing dates. js.html - the JavaScripts included for Paddle Billing checkouts. pagination.html - pagination widget for billing history. pricing.html - list of all plans. paid_plans.html - list of paid plans. plan_overview.html - single plan overview. base.html - base page for subscriptions with the tab navigation. billing_history.html - billing history with downloadable invoices. subscribe.html - subscribing to a single plan. subscription_success.html - success page after successful subscription. subscription_details.html - main subscription page for registered users showing info about subscription plans or info about the current subscription. Using Content-Security-Policy with Django-CSP The Django Paddle Subscriptions app is compatible with Content-Security-Policy via Django-CSP app. To use it, enable nonces for script tags in the project's settings: CSP_INCLUDE_NONCE_IN = [\"script-src\", \"style-src\"] Support for Upsells Business-oriented SaaS projects allow you to buy extras after a chosen subscription is made. To implement that, you would create extra Products and Prices at Paddle Billing, link the Buy buttons to them, and handle the transactions. Use Django signals to add your custom logic to the Django Paddle Subscriptions app. You can either use the builtin post_save signal for that Transaction model, or use the custom webhook_triggered signal that is sent when any successful request from Paddle is sent to the webhook view. Here is an example of webhook_triggered signal receiver which logs JSON objects received from Paddle: # myproject/apps/misc/apps.py from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ def log_webhook_data(sender, **kwargs): import os import json from django.conf import settings from django.utils.timezone import now api_event = kwargs.get(\"api_event\") json_data = ( api_event.data.model_dump_json() if hasattr(api_event.data, \"model_dump_json\") else json.dumps(api_event.data) ) with open(os.path.join(settings.BASE_DIR, \"webhook_data.log\"), \"a\") as f: f.write( f\"\"\"{now():%Y-%m-%d %H:%M:%S} {api_event.event_type} {json_data} \"\"\" ) class MiscConfig(AppConfig): name = \"myproject.apps.misc\" verbose_name = _(\"Miscellaneous\") def ready(self): from paddle_subscriptions.signals import webhook_triggered webhook_triggered.connect(log_webhook_data) Note that you will receive many notifications for a single transaction to become completed, starting with the one with the status \"ready\" and ending with the one with the status \"completed.\" In addition, you can set the JavaScript callback functions at PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_EVENT_CALLBACK\"] to handle Paddle.js events , or PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_TRANSACTION_COMPLETED_CALLBACK\"] to handle successful transaction in the frontend.","title":"Customization"},{"location":"customization/#customization","text":"","title":"Customization"},{"location":"customization/#conditional-showing-of-the-pricing-widget","text":"You can restrict the showing of pricing widget to specific IPs by setting the PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] setting: PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] = [ \"192.0.2.1\", # Your public IP address required for the staging or production environment \"127.0.0.1\", # Your local IP address required for the development environment ] To find your Public IP address, google for \"what's my ip\". Note that the public IP of a router changes every 2 weeks. Then in the templates of use the request.show_paddle_subscriptions to check whether the pricing widget needs to be included: {% if request.show_paddle_subscriptions %} {% load paddle_subscriptions_tags %}{% paddle_subscriptions_pricing %} {% endif %}","title":"Conditional Showing of the Pricing Widget"},{"location":"customization/#free-and-custom-plan-call-to-action-urls","text":"If you have a free plan, set the PADDLE_SUBSCRIPTIONS[\"FREE_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the signup or waitlist page. If you have a custom plan, set the PADDLE_SUBSCRIPTIONS[\"CUSTOM_PRICING_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the page with information about it.","title":"Free and Custom Plan Call-to-action URLs"},{"location":"customization/#display-mode","text":"Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_DISPLAY_MODE\"] to \"overlay\" (default) or \"inline\" to display the checkout widget as a dialog box or as part of the layout. If your display mode is \"inline\" , the following settings are required too: PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_TARGET\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_STYLE\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_INITIAL_HEIGHT\"] Read about them at Paddle Billing documentation .","title":"Display Mode"},{"location":"customization/#checkout-theme","text":"Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] to \"light\" (default) or \"dark\" to display light or dark user interface. In addition, you can pass a function accepting a request parameter which would return the \"light\" or \"dark\" based on user settings or other values: def get_paddle_subscriptions_theme(request): if request.user.is_authenticated and request.user.theme == request.user.ThemeChoices.DARK: return \"dark\" return \"light\" PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] = get_paddle_subscriptions_theme","title":"Checkout Theme"},{"location":"customization/#other-checkout-settings","text":"The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_ADD_TAX_ID\"] setting defines whether the field for a tax number should be shown at checkout (default: True). The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_DISCOUNTS\"] setting defines whether the field for a discount code should be shown at checkout (default: True). Use the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_AUTHENTICATED\"] to redirect an authenticated user who has just subscribed to a custom success page. Set the URL path name, path, or URL of that page. If you allow the anonymous visitors to subscribe before signing up, set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_ANONYMOUS\"] to your signup page that handles the connecting the subscription by paddle_transaction_id cookie to the newly registered user (default: \"/signup/\" ).","title":"Other Checkout Settings"},{"location":"customization/#pausing-and-cancelling-subscriptions","text":"Set whether subscriptions pausing must happen before the next billing period or immediately with PADDLE_SUBSCRIPTIONS[\"WHEN_TO_PAUSE_SUBSCRIPTIONS\"] and PADDLE_SUBSCRIPTIONS[\"WHEN_TO_CANCEL_SUBSCRIPTIONS\"] settings. Set them to \"next_billing_period\" (default) or \"immediately\" .","title":"Pausing and Cancelling Subscriptions"},{"location":"customization/#administration","text":"All Paddle Billing models can be fetched to your Django project via management commands, but not all of them are valuable for introspection. Below are the settings of what to show in administration. Settings for Paddle Billing models: PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_ADMIN\"] (default: True) - show products. PADDLE_SUBSCRIPTIONS[\"SHOW_PRICE_ADMIN\"] (default: True) - show prices. PADDLE_SUBSCRIPTIONS[\"SHOW_DISCOUNT_ADMIN\"] (default: False) - show discounts. PADDLE_SUBSCRIPTIONS[\"SHOW_CUSTOMER_ADMIN\"] (default: True) - show customers. PADDLE_SUBSCRIPTIONS[\"SHOW_ADDRESS_ADMIN\"] (default: False) - show addresses. PADDLE_SUBSCRIPTIONS[\"SHOW_BUSINESS_ADMIN\"] (default: False) - show businesses. PADDLE_SUBSCRIPTIONS[\"SHOW_TRANSACTION_ADMIN\"] (default: True) - show transactions. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_ADMIN\"] (default: True) - show subscriptions. PADDLE_SUBSCRIPTIONS[\"SHOW_ADJUSTMENT_ADMIN\"] (default: False) - show adjustments. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_TYPE_ADMIN\"] (default: False) - show event types. PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_SETTING_ADMIN\"] (default: True) - show notification settings (your webhook URLs). PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_ADMIN\"] (default: False) - show notifications. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_ADMIN\"] (default: True) - show events. Settings for extra Paddle Subscriptions models: PADDLE_SUBSCRIPTIONS[\"SHOW_WEB_PROJECT_ADMIN\"] (default: True) - show web projects when you have more than one SaaS projects using the same Paddle seller's account. PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_CATEGORY_ADMIN\"] (default: True) - show product categories to group your products when you have upsells. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_PLAN_ADMIN\"] (default: True) - show subscription plans. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIBER_ADMIN\"] (default: True) - show subscribers.","title":"Administration"},{"location":"customization/#templates-and-css","text":"The default templates are styled using TailwindCSS. To use them, it is recommended to copy them from site-packages into your project, build your CSS and collect translatable strings, and modify them as necessary. You can replace the CSS classes and markup to Bootstrap, Foundation, Bulma, other CSS framwork, or your custom CSS too. These are the Django Paddle Subscription templates: paddle_subscriptions/ includes/ billing_dates.html - information about the next billing dates. js.html - the JavaScripts included for Paddle Billing checkouts. pagination.html - pagination widget for billing history. pricing.html - list of all plans. paid_plans.html - list of paid plans. plan_overview.html - single plan overview. base.html - base page for subscriptions with the tab navigation. billing_history.html - billing history with downloadable invoices. subscribe.html - subscribing to a single plan. subscription_success.html - success page after successful subscription. subscription_details.html - main subscription page for registered users showing info about subscription plans or info about the current subscription.","title":"Templates and CSS"},{"location":"customization/#using-content-security-policy-with-django-csp","text":"The Django Paddle Subscriptions app is compatible with Content-Security-Policy via Django-CSP app. To use it, enable nonces for script tags in the project's settings: CSP_INCLUDE_NONCE_IN = [\"script-src\", \"style-src\"]","title":"Using Content-Security-Policy with Django-CSP"},{"location":"customization/#support-for-upsells","text":"Business-oriented SaaS projects allow you to buy extras after a chosen subscription is made. To implement that, you would create extra Products and Prices at Paddle Billing, link the Buy buttons to them, and handle the transactions. Use Django signals to add your custom logic to the Django Paddle Subscriptions app. You can either use the builtin post_save signal for that Transaction model, or use the custom webhook_triggered signal that is sent when any successful request from Paddle is sent to the webhook view. Here is an example of webhook_triggered signal receiver which logs JSON objects received from Paddle: # myproject/apps/misc/apps.py from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ def log_webhook_data(sender, **kwargs): import os import json from django.conf import settings from django.utils.timezone import now api_event = kwargs.get(\"api_event\") json_data = ( api_event.data.model_dump_json() if hasattr(api_event.data, \"model_dump_json\") else json.dumps(api_event.data) ) with open(os.path.join(settings.BASE_DIR, \"webhook_data.log\"), \"a\") as f: f.write( f\"\"\"{now():%Y-%m-%d %H:%M:%S} {api_event.event_type} {json_data} \"\"\" ) class MiscConfig(AppConfig): name = \"myproject.apps.misc\" verbose_name = _(\"Miscellaneous\") def ready(self): from paddle_subscriptions.signals import webhook_triggered webhook_triggered.connect(log_webhook_data) Note that you will receive many notifications for a single transaction to become completed, starting with the one with the status \"ready\" and ending with the one with the status \"completed.\" In addition, you can set the JavaScript callback functions at PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_EVENT_CALLBACK\"] to handle Paddle.js events , or PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_TRANSACTION_COMPLETED_CALLBACK\"] to handle successful transaction in the frontend.","title":"Support for Upsells"},{"location":"getting-started/","text":"Getting Started How to Install 1. Download and install the package with pip Get Django Paddle Subscriptions from Gumroad . Create a directory private_wheels/ in your project's repository and add the wheel file of the app there. Link to this file in your requirements.txt : Django==4.2 file:./private_wheels/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl Install the pip requirements from the requirements.txt file into your project's virtual environment: (venv)$ pip install -r requirements.txt Alternatively to start quickly, install the wheel file into your Django project's virtual environment right from the shell: (venv)$ pip install /path/to/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl 2. Add the app to INSTALLED_APPS of your project settings INSTALLED_APPS = [ # ... \"paddle_subscriptions\", ] 3. Add SubscriptionMiddleware to the MIDDLEWARE setting MIDDLEWARE = [ # ... \"paddle_subscriptions.middleware.SubscriptionMiddleware\", ] It will allow to access the current subscriber's data at request.subscriber . 4. Add PADDLE_SUBSCRIPTIONS settings PADDLE_SUBSCRIPTIONS = { \"API_KEY\": \"...\", \"PUBLIC_KEY\": \"...\", \"CLIENT_SIDE_TOKEN\": \"...\", \"ENVIRONMENT\": \"sandbox\", \"WEBSITE_URL\": \"https://example.com\", # ... } Important note! Don't commit the keys and tokens to the version control for security reasons! Set the setting PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS'] = ['...'] to show pricing or other subscription-related widgets only to visitors from those IPs. 5. Add a path to urlpatterns from django.urls import path, include urlpatterns = [ # \u2026 path( \"subscriptions/\", include(\"paddle_subscriptions.urls\", namespace=\"paddle_subscriptions\"), ), ] 6. Create Paddle data In your Django project, create subscription plans with benefits for pricing widgets. If you have a free plan, set the call-to-action URL name at PADDLE_SUBSCRIPTIONS['FREE_PLAN_CTA_URL'] , for example, the sign up or waitlist form. At Paddle create Products for each paid subscription plan, and monthly and yearly prices for each product. You can skip monthly or yearly pricing if you want, but then you will need to modify the overwritten templates to exclude them there too. Deploy the data to a publicly accessible staging or production website. Paddle will send events to that website. 7. Link Paddle with your website Run the management command to fetch Paddle data and install the webhook: (venv)$ python manage.py set_up_paddle_subscriptions The webhook at https://example.com/subscriptions/webhook/ will be registered at Paddle and all Paddle events available in the API will be sent to it. Then, link your subscription plans with sandbox monthly and yearly prices. Also set the default payment link at Paddle (Paddle \u2794 Checkout \u2794 Checkout settings) to https://example.com/subscriptions/payments/ . It will redirect to the correct location based on your SaaS project if you have more than one with the same Paddle account. 8. Create a pricing page Add the following template tag either on the start page or on a separate pricing page view: {% load paddle_subscriptions_tags %} {% paddle_subscriptions_pricing %} 9. Copy the templates to your project Copy the templates from paddle_subscriptions/templates in site-packages to your project and adjust them as necessary. The copy of the templates serves two purposes: you can collect translatable strings into your project, and you can make the TailwindCSS classes discoverable by your installation. 10. Update your signup and account deletion views Your Signup view must link to the subscription that has been done before signup or create a new subscriber with a free plan if they haven't subscribed yet: from paddle_subscriptions.services import ( get_validated_unlinked_transaction, connect_new_user_to_subscription, create_subscriber_for_free_plan, get_initial_data_for_new_user, ) @transaction.atomic @never_cache def register(request, *arguments, **keywords): \"\"\" Displays the registration form and handles the registration action \"\"\" m = hashlib.md5() m.update(force_bytes(request.META[\"REMOTE_ADDR\"])) request.session.session_id = m.hexdigest()[:20] transaction = None if transaction_id := request.COOKIES.get(\"paddle_transaction_id\"): transaction = get_validated_unlinked_transaction(transaction_id) if request.method == \"POST\": form = RegistrationForm(request, request.POST) if form.is_valid(): user = form.save() if transaction: connect_new_user_to_subscription(user, transaction, subscriber_name=form.cleaned_data[\"company_name\"]) else: create_subscriber_for_free_plan(user, subscriber_name=form.cleaned_data[\"company_name\"]) response = redirect(\"accounts:register_pending\") if transaction: response.delete_cookie(\"paddle_transaction_id\") return response else: initial = None if transaction: initial = get_initial_data_for_new_user(transaction) initial[\"company_name\"] = transaction.business.name if transaction.business else \"\" form = RegistrationForm(request, initial=initial) if transaction: form.fields[\"email\"].widget.attrs[\"readonly\"] = True request.session.set_test_cookie() response = render( request, \"accounts/signup.html\", {\"form\": form}, ) return response Then your account deletion view must cancel the existing subscription: from paddle_subscriptions.services import cancel_subscription @login_required def delete_account(request): context = {} if ( request.user.is_authenticated and not request.user.is_staff and request.method == \"POST\" ): form = DeleteAccountForm(user=request.user, data=request.POST) if form.is_valid(): user = request.user if subscription := request.subscriber.current_subscription: cancel_subscription(subscription, effective_from=\"immediately\") if request.subscriber.membership_set.count() == 1: request.subscriber.delete() auth_logout(request) form.delete() response = redirect(\"accounts:delete_account_complete\") return response else: form = DeleteAccountForm(user=request.user) context[\"form\"] = form return render(request, \"accounts/delete_account.html\", context) How to Use 1. The subscription details page The page at https://example.com/subscriptions/ allows you to subscribe to a paid plan or view the details of your current subscription. Use the {% url \"paddle_subscriptions:subscription_details\" %} in the templates to link to that page. Test the pausing, resuming, and cancelling subscriptions there. Also test the billing history and invoices. 2. Check subscriber status in views or templates These are some common values that might be interesting in your views and templates about the current subscriber: # The slug of the current subscriber's subscription plan request.subscriber.plan.slug # Does the current subscriber have free access to their subscription plan? # (the plan itself is free or the subscriber has an exclusive manually set free access) request.subscriber.has_free_access # Is the current subscription active? request.subscriber.is_subscription_active # Will the current subscription be paused at the end of the billing cycle? request.subscriber.is_subscription_to_be_paused # Is the current subscription paused at the moment? request.subscriber.is_subscription_paused # Will the current subscription be cancelled at the end of the billing cycle? request.subscriber.is_subscription_to_be_cancelled # Is the current subscription cancelled at the moment? # (only possible for pricing without a free plan) request.subscriber.is_subscription_cancelled 3. Translate the strings in your templates If your website has more than one language, prepare the translations: Use management command makemessages to collect translatable strings into django.po files. Translate the strings to the languages you need. Then, use the management command compilemessages to compile them to django.mo files. When going live Paddle has an extensive list of steps about going live . Read it thoroughly. What relates to Django Paddle Subscriptions follows: 1. Set Paddle environment to live Set the environment to \"live\": PADDLE_SUBSCRIPTIONS[\"ENVIRONMENT\"] = \"live\" Make sure that PADDLE_SUBSCRIPTIONS[\"WEBSITE_URL\"] points to the URL of the production website, which has to be approved by Paddle. Remove the PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS'] setting. 2. Flush staging data and set up Paddle subscription anew (venv)$ python manage.py flush_paddle_billing_models (venv)$ python manage.py set_up_paddle_subscriptions Then, link your subscription plans with live monthly and yearly prices. 3. Test live payments and subscriptions Create a 100% discount code on the Paddle live environment and test your subscriptions with that code.","title":"Getting Started"},{"location":"getting-started/#getting-started","text":"","title":"Getting Started"},{"location":"getting-started/#how-to-install","text":"","title":"How to Install"},{"location":"getting-started/#1-download-and-install-the-package-with-pip","text":"Get Django Paddle Subscriptions from Gumroad . Create a directory private_wheels/ in your project's repository and add the wheel file of the app there. Link to this file in your requirements.txt : Django==4.2 file:./private_wheels/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl Install the pip requirements from the requirements.txt file into your project's virtual environment: (venv)$ pip install -r requirements.txt Alternatively to start quickly, install the wheel file into your Django project's virtual environment right from the shell: (venv)$ pip install /path/to/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl","title":"1. Download and install the package with pip"},{"location":"getting-started/#2-add-the-app-to-installed_apps-of-your-project-settings","text":"INSTALLED_APPS = [ # ... \"paddle_subscriptions\", ]","title":"2. Add the app to INSTALLED_APPS of your project settings"},{"location":"getting-started/#3-add-subscriptionmiddleware-to-the-middleware-setting","text":"MIDDLEWARE = [ # ... \"paddle_subscriptions.middleware.SubscriptionMiddleware\", ] It will allow to access the current subscriber's data at request.subscriber .","title":"3. Add SubscriptionMiddleware to the MIDDLEWARE setting"},{"location":"getting-started/#4-add-paddle_subscriptions-settings","text":"PADDLE_SUBSCRIPTIONS = { \"API_KEY\": \"...\", \"PUBLIC_KEY\": \"...\", \"CLIENT_SIDE_TOKEN\": \"...\", \"ENVIRONMENT\": \"sandbox\", \"WEBSITE_URL\": \"https://example.com\", # ... } Important note! Don't commit the keys and tokens to the version control for security reasons! Set the setting PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS'] = ['...'] to show pricing or other subscription-related widgets only to visitors from those IPs.","title":"4. Add PADDLE_SUBSCRIPTIONS settings"},{"location":"getting-started/#5-add-a-path-to-urlpatterns","text":"from django.urls import path, include urlpatterns = [ # \u2026 path( \"subscriptions/\", include(\"paddle_subscriptions.urls\", namespace=\"paddle_subscriptions\"), ), ]","title":"5. Add a path to urlpatterns"},{"location":"getting-started/#6-create-paddle-data","text":"In your Django project, create subscription plans with benefits for pricing widgets. If you have a free plan, set the call-to-action URL name at PADDLE_SUBSCRIPTIONS['FREE_PLAN_CTA_URL'] , for example, the sign up or waitlist form. At Paddle create Products for each paid subscription plan, and monthly and yearly prices for each product. You can skip monthly or yearly pricing if you want, but then you will need to modify the overwritten templates to exclude them there too. Deploy the data to a publicly accessible staging or production website. Paddle will send events to that website.","title":"6. Create Paddle data"},{"location":"getting-started/#7-link-paddle-with-your-website","text":"Run the management command to fetch Paddle data and install the webhook: (venv)$ python manage.py set_up_paddle_subscriptions The webhook at https://example.com/subscriptions/webhook/ will be registered at Paddle and all Paddle events available in the API will be sent to it. Then, link your subscription plans with sandbox monthly and yearly prices. Also set the default payment link at Paddle (Paddle \u2794 Checkout \u2794 Checkout settings) to https://example.com/subscriptions/payments/ . It will redirect to the correct location based on your SaaS project if you have more than one with the same Paddle account.","title":"7. Link Paddle with your website"},{"location":"getting-started/#8-create-a-pricing-page","text":"Add the following template tag either on the start page or on a separate pricing page view: {% load paddle_subscriptions_tags %} {% paddle_subscriptions_pricing %}","title":"8. Create a pricing page"},{"location":"getting-started/#9-copy-the-templates-to-your-project","text":"Copy the templates from paddle_subscriptions/templates in site-packages to your project and adjust them as necessary. The copy of the templates serves two purposes: you can collect translatable strings into your project, and you can make the TailwindCSS classes discoverable by your installation.","title":"9. Copy the templates to your project"},{"location":"getting-started/#10-update-your-signup-and-account-deletion-views","text":"Your Signup view must link to the subscription that has been done before signup or create a new subscriber with a free plan if they haven't subscribed yet: from paddle_subscriptions.services import ( get_validated_unlinked_transaction, connect_new_user_to_subscription, create_subscriber_for_free_plan, get_initial_data_for_new_user, ) @transaction.atomic @never_cache def register(request, *arguments, **keywords): \"\"\" Displays the registration form and handles the registration action \"\"\" m = hashlib.md5() m.update(force_bytes(request.META[\"REMOTE_ADDR\"])) request.session.session_id = m.hexdigest()[:20] transaction = None if transaction_id := request.COOKIES.get(\"paddle_transaction_id\"): transaction = get_validated_unlinked_transaction(transaction_id) if request.method == \"POST\": form = RegistrationForm(request, request.POST) if form.is_valid(): user = form.save() if transaction: connect_new_user_to_subscription(user, transaction, subscriber_name=form.cleaned_data[\"company_name\"]) else: create_subscriber_for_free_plan(user, subscriber_name=form.cleaned_data[\"company_name\"]) response = redirect(\"accounts:register_pending\") if transaction: response.delete_cookie(\"paddle_transaction_id\") return response else: initial = None if transaction: initial = get_initial_data_for_new_user(transaction) initial[\"company_name\"] = transaction.business.name if transaction.business else \"\" form = RegistrationForm(request, initial=initial) if transaction: form.fields[\"email\"].widget.attrs[\"readonly\"] = True request.session.set_test_cookie() response = render( request, \"accounts/signup.html\", {\"form\": form}, ) return response Then your account deletion view must cancel the existing subscription: from paddle_subscriptions.services import cancel_subscription @login_required def delete_account(request): context = {} if ( request.user.is_authenticated and not request.user.is_staff and request.method == \"POST\" ): form = DeleteAccountForm(user=request.user, data=request.POST) if form.is_valid(): user = request.user if subscription := request.subscriber.current_subscription: cancel_subscription(subscription, effective_from=\"immediately\") if request.subscriber.membership_set.count() == 1: request.subscriber.delete() auth_logout(request) form.delete() response = redirect(\"accounts:delete_account_complete\") return response else: form = DeleteAccountForm(user=request.user) context[\"form\"] = form return render(request, \"accounts/delete_account.html\", context)","title":"10. Update your signup and account deletion views"},{"location":"getting-started/#how-to-use","text":"","title":"How to Use"},{"location":"getting-started/#1-the-subscription-details-page","text":"The page at https://example.com/subscriptions/ allows you to subscribe to a paid plan or view the details of your current subscription. Use the {% url \"paddle_subscriptions:subscription_details\" %} in the templates to link to that page. Test the pausing, resuming, and cancelling subscriptions there. Also test the billing history and invoices.","title":"1. The subscription details page"},{"location":"getting-started/#2-check-subscriber-status-in-views-or-templates","text":"These are some common values that might be interesting in your views and templates about the current subscriber: # The slug of the current subscriber's subscription plan request.subscriber.plan.slug # Does the current subscriber have free access to their subscription plan? # (the plan itself is free or the subscriber has an exclusive manually set free access) request.subscriber.has_free_access # Is the current subscription active? request.subscriber.is_subscription_active # Will the current subscription be paused at the end of the billing cycle? request.subscriber.is_subscription_to_be_paused # Is the current subscription paused at the moment? request.subscriber.is_subscription_paused # Will the current subscription be cancelled at the end of the billing cycle? request.subscriber.is_subscription_to_be_cancelled # Is the current subscription cancelled at the moment? # (only possible for pricing without a free plan) request.subscriber.is_subscription_cancelled","title":"2. Check subscriber status in views or templates"},{"location":"getting-started/#3-translate-the-strings-in-your-templates","text":"If your website has more than one language, prepare the translations: Use management command makemessages to collect translatable strings into django.po files. Translate the strings to the languages you need. Then, use the management command compilemessages to compile them to django.mo files.","title":"3. Translate the strings in your templates"},{"location":"getting-started/#when-going-live","text":"Paddle has an extensive list of steps about going live . Read it thoroughly. What relates to Django Paddle Subscriptions follows:","title":"When going live"},{"location":"getting-started/#1-set-paddle-environment-to-live","text":"Set the environment to \"live\": PADDLE_SUBSCRIPTIONS[\"ENVIRONMENT\"] = \"live\" Make sure that PADDLE_SUBSCRIPTIONS[\"WEBSITE_URL\"] points to the URL of the production website, which has to be approved by Paddle. Remove the PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS'] setting.","title":"1. Set Paddle environment to live"},{"location":"getting-started/#2-flush-staging-data-and-set-up-paddle-subscription-anew","text":"(venv)$ python manage.py flush_paddle_billing_models (venv)$ python manage.py set_up_paddle_subscriptions Then, link your subscription plans with live monthly and yearly prices.","title":"2. Flush staging data and set up Paddle subscription anew"},{"location":"getting-started/#3-test-live-payments-and-subscriptions","text":"Create a 100% discount code on the Paddle live environment and test your subscriptions with that code.","title":"3. Test live payments and subscriptions"},{"location":"screenshots/","text":"Screenshots Pricing Monthly Pricing Yearly Pricing Subscription Details Current Status Paused Subscription Billing History","title":"Screenshots"},{"location":"screenshots/#screenshots","text":"","title":"Screenshots"},{"location":"screenshots/#pricing","text":"","title":"Pricing"},{"location":"screenshots/#monthly-pricing","text":"","title":"Monthly Pricing"},{"location":"screenshots/#yearly-pricing","text":"","title":"Yearly Pricing"},{"location":"screenshots/#subscription-details","text":"","title":"Subscription Details"},{"location":"screenshots/#current-status","text":"","title":"Current Status"},{"location":"screenshots/#paused-subscription","text":"","title":"Paused Subscription"},{"location":"screenshots/#billing-history","text":"","title":"Billing History"}]}
\ No newline at end of file
+{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Django Paddle Subscriptions Why do you need it? For SaaS (Software as a Service) businesses expanding into global markets, partnering with a reseller like Paddle can be a strategic move to navigate complex tax regulations and streamline operations. Resellers like Paddle act as intermediaries, handling payments, tax compliance, currency conversions, and localized pricing for their partners, freeing up SaaS companies to focus on their core product offerings. The rules for VAT (Value Added Tax) and sales tax are varied from country to country. For example, in the EU, VAT is charged based on the customer's location, regardless of the SaaS provider's headquarters. This means that SaaS businesses outside the EU may need to register for VAT to collect and remit taxes. Paddle simplifies this process by registering for VAT on behalf of its partners and automatically collecting the appropriate tax from each customer. Similarly, in the US, sales tax regulations vary from state to state. Resellers like Paddle typically handle sales tax compliance, ensuring that SaaS businesses only collect taxes in the jurisdictions where they are legally required. This can save businesses time and money, as they don't need to maintain their tax expertise or register for sales tax in multiple states. Also, buying power varies greatly between different countries around the world. In wealthier countries like the United States and Western Europe, people generally have more money to spend due to higher incomes and stronger currencies. However, in less developed countries across Africa, Asia, and parts of Latin America, buying power tends to be lower because people earn less money and the cost of living is often higher relative to their incomes. Django Paddle Subscriptions is a Django app for SaaS projects implementing free and paid subscriptions using Paddle Billing API . It saves you at least a month of work on implementation. And it is pretty flexible and configurable to meet your business needs. Who is it for? The Django Paddle Subscriptions app is for business owners and tech entrepreneurs who want to provide Django-based SaaS globally. Feature Value Supported modern browsers Chrome, Firefox, Safari, Opera, Microsoft Edge Supported Django versions 4.2, 5.0 Supported Python versions 3.10, 3.11, 3.12 Default styling with TailwindCSS \u2714\ufe0e Translatable \u2714\ufe0e Configurable \u2714\ufe0e Localized pricing widget \u2714\ufe0e Offered free and paid plans \u2714\ufe0e Subscriptions before or after signup \u2714\ufe0e Monthly and yearly pricing \u2714\ufe0e List of paid invoices \u2714\ufe0e Pausing and cancelling subscriptions \u2714\ufe0e Copy of Paddle data in your database \u2714\ufe0e Multiple SaaS with the same Paddle account \u2714\ufe0e Infrastructure for upsells \u2714\ufe0e Latest package version 1.3.0 What are the benefits? There are lots of benefits: Saves at least a month of development work. Highly flexible and configurable. Can be used for as many Django-based SaaS projects as necessary. The frontend is styled with TailwindCSS for quick start, but you can overwrite the templates and introduce your custom styling. Comes with handy management commands to fetch Paddle data and set up the environment. Allows using the same Paddle account for multiple Django-based SaaS projects. Developed with internationalization in mind. Compatible with Content-Security-Policy via Django-CSP. MIT license applied. Designed and implemented by the author of \"Web development with Django Cookbook.\" How does it work? You will need a seller's account at Paddle and your business and SaaS domains approved (which might take from a few days to two weeks). At first, implement the payments in the sandbox environment . At Paddle, create Products for each subscription plan and one monthly and one yearly price for each plan. For example, Premium plan as a product will have two prices: Premium monthly and Premium yearly. At your Django website, fetch all data from Paddle, create subscription plans, and attach the prices to the subscription plans accordingly. Check these workflows: Pricing \u2794 Subscription \u2794 Signup \u2794 Billing history Signup \u2794 Pricing \u2794 Subscription \u2794 Billing history Pausing subscription \u2794 Resuming subscription \u2794 Cancelling subscription Pausing subscription \u2794 Cancelling subscription When ready to go live, create the same products and prices at the live environment . Flush the Paddle data on your server, fetch the data from the live server, and connect the prices to your subscription plans. Create a 100% discount code and test subscriptions with that code on the live environment. Examples Django Paddle Subscriptions are used in production at these websites: 1st things 1st Remember Your People Credits The Django Paddle Subscriptions app under the hood uses paddle-billing-client , which was thoroughly crafted by Benjamin Gervan. In addition to that, Django Paddle Subscriptions uses currencies , django-ipware , and func-timeout . Disclaimer Django Paddle Subscriptions app is provided without any warranties or guarantees, either explicit or implied. The user is responsible for using the app responsibly and in compliance with all applicable laws and regulations. The user is also solely responsible for any financial losses or other issues that may arise from using the app. By using this app, the user agrees to indemnify and hold harmless the app's author from any claims, damages, losses, liabilities, costs, or expenses (including reasonable attorney's fees) arising from or in connection with the app's use or misuse. Contact For technical questions, feature requests, or bug reports, please contact Aidas Bendoraitis at https://www.djangotricks.com/feedback/ .","title":"Home"},{"location":"#django-paddle-subscriptions","text":"","title":"Django Paddle Subscriptions"},{"location":"#why-do-you-need-it","text":"For SaaS (Software as a Service) businesses expanding into global markets, partnering with a reseller like Paddle can be a strategic move to navigate complex tax regulations and streamline operations. Resellers like Paddle act as intermediaries, handling payments, tax compliance, currency conversions, and localized pricing for their partners, freeing up SaaS companies to focus on their core product offerings. The rules for VAT (Value Added Tax) and sales tax are varied from country to country. For example, in the EU, VAT is charged based on the customer's location, regardless of the SaaS provider's headquarters. This means that SaaS businesses outside the EU may need to register for VAT to collect and remit taxes. Paddle simplifies this process by registering for VAT on behalf of its partners and automatically collecting the appropriate tax from each customer. Similarly, in the US, sales tax regulations vary from state to state. Resellers like Paddle typically handle sales tax compliance, ensuring that SaaS businesses only collect taxes in the jurisdictions where they are legally required. This can save businesses time and money, as they don't need to maintain their tax expertise or register for sales tax in multiple states. Also, buying power varies greatly between different countries around the world. In wealthier countries like the United States and Western Europe, people generally have more money to spend due to higher incomes and stronger currencies. However, in less developed countries across Africa, Asia, and parts of Latin America, buying power tends to be lower because people earn less money and the cost of living is often higher relative to their incomes. Django Paddle Subscriptions is a Django app for SaaS projects implementing free and paid subscriptions using Paddle Billing API . It saves you at least a month of work on implementation. And it is pretty flexible and configurable to meet your business needs.","title":"Why do you need it?"},{"location":"#who-is-it-for","text":"The Django Paddle Subscriptions app is for business owners and tech entrepreneurs who want to provide Django-based SaaS globally. Feature Value Supported modern browsers Chrome, Firefox, Safari, Opera, Microsoft Edge Supported Django versions 4.2, 5.0 Supported Python versions 3.10, 3.11, 3.12 Default styling with TailwindCSS \u2714\ufe0e Translatable \u2714\ufe0e Configurable \u2714\ufe0e Localized pricing widget \u2714\ufe0e Offered free and paid plans \u2714\ufe0e Subscriptions before or after signup \u2714\ufe0e Monthly and yearly pricing \u2714\ufe0e List of paid invoices \u2714\ufe0e Pausing and cancelling subscriptions \u2714\ufe0e Copy of Paddle data in your database \u2714\ufe0e Multiple SaaS with the same Paddle account \u2714\ufe0e Infrastructure for upsells \u2714\ufe0e Latest package version 1.3.0","title":"Who is it for?"},{"location":"#what-are-the-benefits","text":"There are lots of benefits: Saves at least a month of development work. Highly flexible and configurable. Can be used for as many Django-based SaaS projects as necessary. The frontend is styled with TailwindCSS for quick start, but you can overwrite the templates and introduce your custom styling. Comes with handy management commands to fetch Paddle data and set up the environment. Allows using the same Paddle account for multiple Django-based SaaS projects. Developed with internationalization in mind. Compatible with Content-Security-Policy via Django-CSP. MIT license applied. Designed and implemented by the author of \"Web development with Django Cookbook.\"","title":"What are the benefits?"},{"location":"#how-does-it-work","text":"You will need a seller's account at Paddle and your business and SaaS domains approved (which might take from a few days to two weeks). At first, implement the payments in the sandbox environment . At Paddle, create Products for each subscription plan and one monthly and one yearly price for each plan. For example, Premium plan as a product will have two prices: Premium monthly and Premium yearly. At your Django website, fetch all data from Paddle, create subscription plans, and attach the prices to the subscription plans accordingly. Check these workflows: Pricing \u2794 Subscription \u2794 Signup \u2794 Billing history Signup \u2794 Pricing \u2794 Subscription \u2794 Billing history Pausing subscription \u2794 Resuming subscription \u2794 Cancelling subscription Pausing subscription \u2794 Cancelling subscription When ready to go live, create the same products and prices at the live environment . Flush the Paddle data on your server, fetch the data from the live server, and connect the prices to your subscription plans. Create a 100% discount code and test subscriptions with that code on the live environment.","title":"How does it work?"},{"location":"#examples","text":"Django Paddle Subscriptions are used in production at these websites: 1st things 1st Remember Your People","title":"Examples"},{"location":"#credits","text":"The Django Paddle Subscriptions app under the hood uses paddle-billing-client , which was thoroughly crafted by Benjamin Gervan. In addition to that, Django Paddle Subscriptions uses currencies , django-ipware , and func-timeout .","title":"Credits"},{"location":"#disclaimer","text":"Django Paddle Subscriptions app is provided without any warranties or guarantees, either explicit or implied. The user is responsible for using the app responsibly and in compliance with all applicable laws and regulations. The user is also solely responsible for any financial losses or other issues that may arise from using the app. By using this app, the user agrees to indemnify and hold harmless the app's author from any claims, damages, losses, liabilities, costs, or expenses (including reasonable attorney's fees) arising from or in connection with the app's use or misuse.","title":"Disclaimer"},{"location":"#contact","text":"For technical questions, feature requests, or bug reports, please contact Aidas Bendoraitis at https://www.djangotricks.com/feedback/ .","title":"Contact"},{"location":"CHANGELOG/","text":"Changelog All notable changes to this project will be documented in this file. The format is based on Keep a Changelog , and this project adheres to Semantic Versioning . [Unreleased] [v1.3.0] - 2024-02-11 Added Unit tests for fetching information from Paddle Billing. Fixed Saving adjustments fixed. [v1.2.1] - 2024-02-10 Changed Link to documentation [v1.2.0] - 2024-02-10 Added Templates added Markdown files added [v1.1.0] - 2024-02-10 Changed Functions refactored. Fixed Cosmetic styling adjustments. [v1.0.0] - 2024-02-06 Added Paddle Billing models. Custom Django Paddle Subscriptions models. Management commands to fetch data from Paddle Billing. Management command to set up the webhook. Management command to flush Paddle Billing models. Pricing widget. Subscription details page. Pausing and resuming subscriptions. Cancelling subscriptions. Billing history with invoice downloads. Lots of customizations via settings.","title":"Changelog"},{"location":"CHANGELOG/#changelog","text":"All notable changes to this project will be documented in this file. The format is based on Keep a Changelog , and this project adheres to Semantic Versioning .","title":"Changelog"},{"location":"CHANGELOG/#unreleased","text":"","title":"[Unreleased]"},{"location":"CHANGELOG/#v130-2024-02-11","text":"","title":"[v1.3.0] - 2024-02-11"},{"location":"CHANGELOG/#added","text":"Unit tests for fetching information from Paddle Billing.","title":"Added"},{"location":"CHANGELOG/#fixed","text":"Saving adjustments fixed.","title":"Fixed"},{"location":"CHANGELOG/#v121-2024-02-10","text":"","title":"[v1.2.1] - 2024-02-10"},{"location":"CHANGELOG/#changed","text":"Link to documentation","title":"Changed"},{"location":"CHANGELOG/#v120-2024-02-10","text":"","title":"[v1.2.0] - 2024-02-10"},{"location":"CHANGELOG/#added_1","text":"Templates added Markdown files added","title":"Added"},{"location":"CHANGELOG/#v110-2024-02-10","text":"","title":"[v1.1.0] - 2024-02-10"},{"location":"CHANGELOG/#changed_1","text":"Functions refactored.","title":"Changed"},{"location":"CHANGELOG/#fixed_1","text":"Cosmetic styling adjustments.","title":"Fixed"},{"location":"CHANGELOG/#v100-2024-02-06","text":"","title":"[v1.0.0] - 2024-02-06"},{"location":"CHANGELOG/#added_2","text":"Paddle Billing models. Custom Django Paddle Subscriptions models. Management commands to fetch data from Paddle Billing. Management command to set up the webhook. Management command to flush Paddle Billing models. Pricing widget. Subscription details page. Pausing and resuming subscriptions. Cancelling subscriptions. Billing history with invoice downloads. Lots of customizations via settings.","title":"Added"},{"location":"LICENSE/","text":"MIT License Copyright (c) Websightful UG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"License"},{"location":"LICENSE/#mit-license","text":"Copyright (c) Websightful UG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"MIT License"},{"location":"customization/","text":"Customization Conditional Showing of the Pricing Widget You can restrict the showing of pricing widget to specific IPs by setting the PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] setting: PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] = [ \"192.0.2.1\", # Your public IP address required for the staging or production environment \"127.0.0.1\", # Your local IP address required for the development environment ] To find your Public IP address, google for \"what's my ip\". Note that the public IP of a router changes every 2 weeks. Then in the templates of use the request.show_paddle_subscriptions to check whether the pricing widget needs to be included: {% if request.show_paddle_subscriptions %} {% load paddle_subscriptions_tags %}{% paddle_subscriptions_pricing %} {% endif %} Free and Custom Plan Call-to-action URLs If you have a free plan, set the PADDLE_SUBSCRIPTIONS[\"FREE_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the signup or waitlist page. If you have a custom plan, set the PADDLE_SUBSCRIPTIONS[\"CUSTOM_PRICING_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the page with information about it. Display Mode Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_DISPLAY_MODE\"] to \"overlay\" (default) or \"inline\" to display the checkout widget as a dialog box or as part of the layout. If your display mode is \"inline\" , the following settings are required too: PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_TARGET\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_STYLE\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_INITIAL_HEIGHT\"] Read about them at Paddle Billing documentation . Checkout Theme Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] to \"light\" (default) or \"dark\" to display light or dark user interface. In addition, you can pass a function accepting a request parameter which would return the \"light\" or \"dark\" based on user settings or other values: def get_paddle_subscriptions_theme(request): if request.user.is_authenticated and request.user.theme == request.user.ThemeChoices.DARK: return \"dark\" return \"light\" PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] = get_paddle_subscriptions_theme Other Checkout Settings The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_ADD_TAX_ID\"] setting defines whether the field for a tax number should be shown at checkout (default: True). The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_DISCOUNTS\"] setting defines whether the field for a discount code should be shown at checkout (default: True). Use the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_AUTHENTICATED\"] to redirect an authenticated user who has just subscribed to a custom success page. Set the URL path name, path, or URL of that page. If you allow the anonymous visitors to subscribe before signing up, set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_ANONYMOUS\"] to your signup page that handles the connecting the subscription by paddle_transaction_id cookie to the newly registered user (default: \"/signup/\" ). Pausing and Cancelling Subscriptions Set whether subscriptions pausing must happen before the next billing period or immediately with PADDLE_SUBSCRIPTIONS[\"WHEN_TO_PAUSE_SUBSCRIPTIONS\"] and PADDLE_SUBSCRIPTIONS[\"WHEN_TO_CANCEL_SUBSCRIPTIONS\"] settings. Set them to \"next_billing_period\" (default) or \"immediately\" . Administration All Paddle Billing models can be fetched to your Django project via management commands, but not all of them are valuable for introspection. Below are the settings of what to show in administration. Settings for Paddle Billing models: PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_ADMIN\"] (default: True) - show products. PADDLE_SUBSCRIPTIONS[\"SHOW_PRICE_ADMIN\"] (default: True) - show prices. PADDLE_SUBSCRIPTIONS[\"SHOW_DISCOUNT_ADMIN\"] (default: False) - show discounts. PADDLE_SUBSCRIPTIONS[\"SHOW_CUSTOMER_ADMIN\"] (default: True) - show customers. PADDLE_SUBSCRIPTIONS[\"SHOW_ADDRESS_ADMIN\"] (default: False) - show addresses. PADDLE_SUBSCRIPTIONS[\"SHOW_BUSINESS_ADMIN\"] (default: False) - show businesses. PADDLE_SUBSCRIPTIONS[\"SHOW_TRANSACTION_ADMIN\"] (default: True) - show transactions. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_ADMIN\"] (default: True) - show subscriptions. PADDLE_SUBSCRIPTIONS[\"SHOW_ADJUSTMENT_ADMIN\"] (default: False) - show adjustments. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_TYPE_ADMIN\"] (default: False) - show event types. PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_SETTING_ADMIN\"] (default: True) - show notification settings (your webhook URLs). PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_ADMIN\"] (default: False) - show notifications. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_ADMIN\"] (default: True) - show events. Settings for extra Paddle Subscriptions models: PADDLE_SUBSCRIPTIONS[\"SHOW_WEB_PROJECT_ADMIN\"] (default: True) - show web projects when you have more than one SaaS projects using the same Paddle seller's account. PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_CATEGORY_ADMIN\"] (default: True) - show product categories to group your products when you have upsells. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_PLAN_ADMIN\"] (default: True) - show subscription plans. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIBER_ADMIN\"] (default: True) - show subscribers. Templates and CSS The default templates are styled using TailwindCSS. To use them, it is recommended to copy them from site-packages into your project, build your CSS and collect translatable strings, and modify them as necessary. You can replace the CSS classes and markup to Bootstrap, Foundation, Bulma, other CSS framwork, or your custom CSS too. These are the Django Paddle Subscription templates: paddle_subscriptions/ includes/ billing_dates.html - information about the next billing dates. js.html - the JavaScripts included for Paddle Billing checkouts. pagination.html - pagination widget for billing history. pricing.html - list of all plans. paid_plans.html - list of paid plans. plan_overview.html - single plan overview. base.html - base page for subscriptions with the tab navigation. billing_history.html - billing history with downloadable invoices. subscribe.html - subscribing to a single plan. subscription_success.html - success page after successful subscription. subscription_details.html - main subscription page for registered users showing info about subscription plans or info about the current subscription. Using Content-Security-Policy with Django-CSP The Django Paddle Subscriptions app is compatible with Content-Security-Policy via Django-CSP app. To use it, enable nonces for script tags in the project's settings: CSP_INCLUDE_NONCE_IN = [\"script-src\", \"style-src\"] Support for Upsells Business-oriented SaaS projects allow you to buy extras after a chosen subscription is made. To implement that, you would create extra Products and Prices at Paddle Billing, link the Buy buttons to them, and handle the transactions. Use Django signals to add your custom logic to the Django Paddle Subscriptions app. You can either use the builtin post_save signal for that Transaction model, or use the custom webhook_triggered signal that is sent when any successful request from Paddle is sent to the webhook view. Here is an example of webhook_triggered signal receiver which logs JSON objects received from Paddle: # myproject/apps/misc/apps.py from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ def log_webhook_data(sender, **kwargs): import os import json from django.conf import settings from django.utils.timezone import now api_event = kwargs.get(\"api_event\") json_data = ( api_event.data.model_dump_json() if hasattr(api_event.data, \"model_dump_json\") else json.dumps(api_event.data) ) with open(os.path.join(settings.BASE_DIR, \"webhook_data.log\"), \"a\") as f: f.write( f\"\"\"{now():%Y-%m-%d %H:%M:%S} {api_event.event_type} {json_data} \"\"\" ) class MiscConfig(AppConfig): name = \"myproject.apps.misc\" verbose_name = _(\"Miscellaneous\") def ready(self): from paddle_subscriptions.signals import webhook_triggered webhook_triggered.connect(log_webhook_data) Note that you will receive many notifications for a single transaction to become completed, starting with the one with the status \"ready\" and ending with the one with the status \"completed.\" In addition, you can set the JavaScript callback functions at PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_EVENT_CALLBACK\"] to handle Paddle.js events , or PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_TRANSACTION_COMPLETED_CALLBACK\"] to handle successful transaction in the frontend.","title":"Customization"},{"location":"customization/#customization","text":"","title":"Customization"},{"location":"customization/#conditional-showing-of-the-pricing-widget","text":"You can restrict the showing of pricing widget to specific IPs by setting the PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] setting: PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] = [ \"192.0.2.1\", # Your public IP address required for the staging or production environment \"127.0.0.1\", # Your local IP address required for the development environment ] To find your Public IP address, google for \"what's my ip\". Note that the public IP of a router changes every 2 weeks. Then in the templates of use the request.show_paddle_subscriptions to check whether the pricing widget needs to be included: {% if request.show_paddle_subscriptions %} {% load paddle_subscriptions_tags %}{% paddle_subscriptions_pricing %} {% endif %}","title":"Conditional Showing of the Pricing Widget"},{"location":"customization/#free-and-custom-plan-call-to-action-urls","text":"If you have a free plan, set the PADDLE_SUBSCRIPTIONS[\"FREE_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the signup or waitlist page. If you have a custom plan, set the PADDLE_SUBSCRIPTIONS[\"CUSTOM_PRICING_PLAN_CTA_URL\"] to a URL path name, path, or a URL of the page with information about it.","title":"Free and Custom Plan Call-to-action URLs"},{"location":"customization/#display-mode","text":"Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_DISPLAY_MODE\"] to \"overlay\" (default) or \"inline\" to display the checkout widget as a dialog box or as part of the layout. If your display mode is \"inline\" , the following settings are required too: PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_TARGET\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_STYLE\"] PADDLE_SUBSCRIPTIONS[\"CHECKOUT_FRAME_INITIAL_HEIGHT\"] Read about them at Paddle Billing documentation .","title":"Display Mode"},{"location":"customization/#checkout-theme","text":"Set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] to \"light\" (default) or \"dark\" to display light or dark user interface. In addition, you can pass a function accepting a request parameter which would return the \"light\" or \"dark\" based on user settings or other values: def get_paddle_subscriptions_theme(request): if request.user.is_authenticated and request.user.theme == request.user.ThemeChoices.DARK: return \"dark\" return \"light\" PADDLE_SUBSCRIPTIONS[\"CHECKOUT_THEME\"] = get_paddle_subscriptions_theme","title":"Checkout Theme"},{"location":"customization/#other-checkout-settings","text":"The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_ADD_TAX_ID\"] setting defines whether the field for a tax number should be shown at checkout (default: True). The PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SHOW_DISCOUNTS\"] setting defines whether the field for a discount code should be shown at checkout (default: True). Use the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_AUTHENTICATED\"] to redirect an authenticated user who has just subscribed to a custom success page. Set the URL path name, path, or URL of that page. If you allow the anonymous visitors to subscribe before signing up, set the PADDLE_SUBSCRIPTIONS[\"CHECKOUT_SUCCESS_URL_FOR_ANONYMOUS\"] to your signup page that handles the connecting the subscription by paddle_transaction_id cookie to the newly registered user (default: \"/signup/\" ).","title":"Other Checkout Settings"},{"location":"customization/#pausing-and-cancelling-subscriptions","text":"Set whether subscriptions pausing must happen before the next billing period or immediately with PADDLE_SUBSCRIPTIONS[\"WHEN_TO_PAUSE_SUBSCRIPTIONS\"] and PADDLE_SUBSCRIPTIONS[\"WHEN_TO_CANCEL_SUBSCRIPTIONS\"] settings. Set them to \"next_billing_period\" (default) or \"immediately\" .","title":"Pausing and Cancelling Subscriptions"},{"location":"customization/#administration","text":"All Paddle Billing models can be fetched to your Django project via management commands, but not all of them are valuable for introspection. Below are the settings of what to show in administration. Settings for Paddle Billing models: PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_ADMIN\"] (default: True) - show products. PADDLE_SUBSCRIPTIONS[\"SHOW_PRICE_ADMIN\"] (default: True) - show prices. PADDLE_SUBSCRIPTIONS[\"SHOW_DISCOUNT_ADMIN\"] (default: False) - show discounts. PADDLE_SUBSCRIPTIONS[\"SHOW_CUSTOMER_ADMIN\"] (default: True) - show customers. PADDLE_SUBSCRIPTIONS[\"SHOW_ADDRESS_ADMIN\"] (default: False) - show addresses. PADDLE_SUBSCRIPTIONS[\"SHOW_BUSINESS_ADMIN\"] (default: False) - show businesses. PADDLE_SUBSCRIPTIONS[\"SHOW_TRANSACTION_ADMIN\"] (default: True) - show transactions. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_ADMIN\"] (default: True) - show subscriptions. PADDLE_SUBSCRIPTIONS[\"SHOW_ADJUSTMENT_ADMIN\"] (default: False) - show adjustments. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_TYPE_ADMIN\"] (default: False) - show event types. PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_SETTING_ADMIN\"] (default: True) - show notification settings (your webhook URLs). PADDLE_SUBSCRIPTIONS[\"SHOW_NOTIFICATION_ADMIN\"] (default: False) - show notifications. PADDLE_SUBSCRIPTIONS[\"SHOW_EVENT_ADMIN\"] (default: True) - show events. Settings for extra Paddle Subscriptions models: PADDLE_SUBSCRIPTIONS[\"SHOW_WEB_PROJECT_ADMIN\"] (default: True) - show web projects when you have more than one SaaS projects using the same Paddle seller's account. PADDLE_SUBSCRIPTIONS[\"SHOW_PRODUCT_CATEGORY_ADMIN\"] (default: True) - show product categories to group your products when you have upsells. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIPTION_PLAN_ADMIN\"] (default: True) - show subscription plans. PADDLE_SUBSCRIPTIONS[\"SHOW_SUBSCRIBER_ADMIN\"] (default: True) - show subscribers.","title":"Administration"},{"location":"customization/#templates-and-css","text":"The default templates are styled using TailwindCSS. To use them, it is recommended to copy them from site-packages into your project, build your CSS and collect translatable strings, and modify them as necessary. You can replace the CSS classes and markup to Bootstrap, Foundation, Bulma, other CSS framwork, or your custom CSS too. These are the Django Paddle Subscription templates: paddle_subscriptions/ includes/ billing_dates.html - information about the next billing dates. js.html - the JavaScripts included for Paddle Billing checkouts. pagination.html - pagination widget for billing history. pricing.html - list of all plans. paid_plans.html - list of paid plans. plan_overview.html - single plan overview. base.html - base page for subscriptions with the tab navigation. billing_history.html - billing history with downloadable invoices. subscribe.html - subscribing to a single plan. subscription_success.html - success page after successful subscription. subscription_details.html - main subscription page for registered users showing info about subscription plans or info about the current subscription.","title":"Templates and CSS"},{"location":"customization/#using-content-security-policy-with-django-csp","text":"The Django Paddle Subscriptions app is compatible with Content-Security-Policy via Django-CSP app. To use it, enable nonces for script tags in the project's settings: CSP_INCLUDE_NONCE_IN = [\"script-src\", \"style-src\"]","title":"Using Content-Security-Policy with Django-CSP"},{"location":"customization/#support-for-upsells","text":"Business-oriented SaaS projects allow you to buy extras after a chosen subscription is made. To implement that, you would create extra Products and Prices at Paddle Billing, link the Buy buttons to them, and handle the transactions. Use Django signals to add your custom logic to the Django Paddle Subscriptions app. You can either use the builtin post_save signal for that Transaction model, or use the custom webhook_triggered signal that is sent when any successful request from Paddle is sent to the webhook view. Here is an example of webhook_triggered signal receiver which logs JSON objects received from Paddle: # myproject/apps/misc/apps.py from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ def log_webhook_data(sender, **kwargs): import os import json from django.conf import settings from django.utils.timezone import now api_event = kwargs.get(\"api_event\") json_data = ( api_event.data.model_dump_json() if hasattr(api_event.data, \"model_dump_json\") else json.dumps(api_event.data) ) with open(os.path.join(settings.BASE_DIR, \"webhook_data.log\"), \"a\") as f: f.write( f\"\"\"{now():%Y-%m-%d %H:%M:%S} {api_event.event_type} {json_data} \"\"\" ) class MiscConfig(AppConfig): name = \"myproject.apps.misc\" verbose_name = _(\"Miscellaneous\") def ready(self): from paddle_subscriptions.signals import webhook_triggered webhook_triggered.connect(log_webhook_data) Note that you will receive many notifications for a single transaction to become completed, starting with the one with the status \"ready\" and ending with the one with the status \"completed.\" In addition, you can set the JavaScript callback functions at PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_EVENT_CALLBACK\"] to handle Paddle.js events , or PADDLE_SUBSCRIPTIONS[\"CHECKOUT_JS_TRANSACTION_COMPLETED_CALLBACK\"] to handle successful transaction in the frontend.","title":"Support for Upsells"},{"location":"getting-started/","text":"Getting Started How to Install 1. Download and install the package with pip Get Django Paddle Subscriptions from Gumroad . Create a directory private_wheels/ in your project's repository and add the wheel file of the app there. Link to this file in your requirements.txt : Django==4.2 file:./private_wheels/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl Install the pip requirements from the requirements.txt file into your project's virtual environment: (venv)$ pip install -r requirements.txt Alternatively to start quickly, install the wheel file into your Django project's virtual environment right from the shell: (venv)$ pip install /path/to/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl 2. Add the app to INSTALLED_APPS of your project settings INSTALLED_APPS = [ # ... \"paddle_subscriptions\", ] 3. Add SubscriptionMiddleware to the MIDDLEWARE setting MIDDLEWARE = [ # ... \"paddle_subscriptions.middleware.SubscriptionMiddleware\", ] It will allow to access the current subscriber's data at request.subscriber . 4. Add PADDLE_SUBSCRIPTIONS settings PADDLE_SUBSCRIPTIONS = { \"API_KEY\": \"...\", \"PUBLIC_KEY\": \"...\", \"CLIENT_SIDE_TOKEN\": \"...\", \"ENVIRONMENT\": \"sandbox\", \"WEBSITE_URL\": \"https://example.com\", # ... } Important note! Don't commit the keys and tokens to the version control for security reasons! Set the setting PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS'] = ['...'] to show pricing or other subscription-related widgets only to visitors from those IPs. 5. Add a path to urlpatterns from django.urls import path, include urlpatterns = [ # \u2026 path( \"subscriptions/\", include(\"paddle_subscriptions.urls\", namespace=\"paddle_subscriptions\"), ), ] 6. Create Paddle data In your Django project, create subscription plans with benefits for pricing widgets. If you have a free plan, set the call-to-action URL name at PADDLE_SUBSCRIPTIONS['FREE_PLAN_CTA_URL'] , for example, the sign up or waitlist form. At Paddle create Products for each paid subscription plan, and monthly and yearly prices for each product. You can skip monthly or yearly pricing if you want, but then you will need to modify the overwritten templates to exclude them there too. Deploy the data to a publicly accessible staging or production website. Paddle will send events to that website. 7. Link Paddle with your website Run the management command to fetch Paddle data and install the webhook: (venv)$ python manage.py set_up_paddle_subscriptions The webhook at https://example.com/subscriptions/webhook/ will be registered at Paddle and all Paddle events available in the API will be sent to it. Then, link your subscription plans with sandbox monthly and yearly prices. Also set the default payment link at Paddle (Paddle \u2794 Checkout \u2794 Checkout settings) to https://example.com/subscriptions/payments/ . It will redirect to the correct location based on your SaaS project if you have more than one with the same Paddle account. 8. Create a pricing page Add the following template tag either on the start page or on a separate pricing page view: {% load paddle_subscriptions_tags %} {% paddle_subscriptions_pricing %} 9. Copy the templates to your project Copy the templates from paddle_subscriptions/templates in site-packages to your project and adjust them as necessary. The copy of the templates serves two purposes: you can collect translatable strings into your project, and you can make the TailwindCSS classes discoverable by your installation. 10. Update your signup and account deletion views Your Signup view must link to the subscription that has been done before signup or create a new subscriber with a free plan if they haven't subscribed yet: from paddle_subscriptions.services import ( get_validated_unlinked_transaction, connect_new_user_to_subscription, create_subscriber_for_free_plan, get_initial_data_for_new_user, ) @transaction.atomic @never_cache def register(request, *arguments, **keywords): \"\"\" Displays the registration form and handles the registration action \"\"\" m = hashlib.md5() m.update(force_bytes(request.META[\"REMOTE_ADDR\"])) request.session.session_id = m.hexdigest()[:20] transaction = None if transaction_id := request.COOKIES.get(\"paddle_transaction_id\"): transaction = get_validated_unlinked_transaction(transaction_id) if request.method == \"POST\": form = RegistrationForm(request, request.POST) if form.is_valid(): user = form.save() if transaction: connect_new_user_to_subscription(user, transaction, subscriber_name=form.cleaned_data[\"company_name\"]) else: create_subscriber_for_free_plan(user, subscriber_name=form.cleaned_data[\"company_name\"]) response = redirect(\"accounts:register_pending\") if transaction: response.delete_cookie(\"paddle_transaction_id\") return response else: initial = None if transaction: initial = get_initial_data_for_new_user(transaction) initial[\"company_name\"] = transaction.business.name if transaction.business else \"\" form = RegistrationForm(request, initial=initial) if transaction: form.fields[\"email\"].widget.attrs[\"readonly\"] = True request.session.set_test_cookie() response = render( request, \"accounts/signup.html\", {\"form\": form}, ) return response Then your account deletion view must cancel the existing subscription: from paddle_subscriptions.services import cancel_subscription @login_required def delete_account(request): context = {} if ( request.user.is_authenticated and not request.user.is_staff and request.method == \"POST\" ): form = DeleteAccountForm(user=request.user, data=request.POST) if form.is_valid(): user = request.user if subscription := request.subscriber.current_subscription: cancel_subscription(subscription, effective_from=\"immediately\") if request.subscriber.membership_set.count() == 1: request.subscriber.delete() auth_logout(request) form.delete() response = redirect(\"accounts:delete_account_complete\") return response else: form = DeleteAccountForm(user=request.user) context[\"form\"] = form return render(request, \"accounts/delete_account.html\", context) How to Use 1. The subscription details page The page at https://example.com/subscriptions/ allows you to subscribe to a paid plan or view the details of your current subscription. Use the {% url \"paddle_subscriptions:subscription_details\" %} in the templates to link to that page. Test the pausing, resuming, and cancelling subscriptions there. Also test the billing history and invoices. 2. Check subscriber status in views or templates These are some common values that might be interesting in your views and templates about the current subscriber: # The slug of the current subscriber's subscription plan request.subscriber.plan.slug # Does the current subscriber have free access to their subscription plan? # (the plan itself is free or the subscriber has an exclusive manually set free access) request.subscriber.has_free_access # Is the current subscription active? request.subscriber.is_subscription_active # Will the current subscription be paused at the end of the billing cycle? request.subscriber.is_subscription_to_be_paused # Is the current subscription paused at the moment? request.subscriber.is_subscription_paused # Will the current subscription be cancelled at the end of the billing cycle? request.subscriber.is_subscription_to_be_cancelled # Is the current subscription cancelled at the moment? # (only possible for pricing without a free plan) request.subscriber.is_subscription_cancelled 3. Translate the strings in your templates If your website has more than one language, prepare the translations: Use management command makemessages to collect translatable strings into django.po files. Translate the strings to the languages you need. Then, use the management command compilemessages to compile them to django.mo files. When going live Paddle has an extensive list of steps about going live . Read it thoroughly. What relates to Django Paddle Subscriptions follows: 1. Set Paddle environment to live Set the environment to \"live\": PADDLE_SUBSCRIPTIONS[\"ENVIRONMENT\"] = \"live\" Make sure that PADDLE_SUBSCRIPTIONS[\"WEBSITE_URL\"] points to the URL of the production website, which has to be approved by Paddle. Remove the PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] setting. 2. Flush staging data and set up Paddle subscription anew (venv)$ python manage.py flush_paddle_billing_models (venv)$ python manage.py set_up_paddle_subscriptions Then, link your subscription plans with live monthly and yearly prices. 3. Test live payments and subscriptions Create a 100% discount code on the Paddle live environment and test your subscriptions with that code.","title":"Getting Started"},{"location":"getting-started/#getting-started","text":"","title":"Getting Started"},{"location":"getting-started/#how-to-install","text":"","title":"How to Install"},{"location":"getting-started/#1-download-and-install-the-package-with-pip","text":"Get Django Paddle Subscriptions from Gumroad . Create a directory private_wheels/ in your project's repository and add the wheel file of the app there. Link to this file in your requirements.txt : Django==4.2 file:./private_wheels/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl Install the pip requirements from the requirements.txt file into your project's virtual environment: (venv)$ pip install -r requirements.txt Alternatively to start quickly, install the wheel file into your Django project's virtual environment right from the shell: (venv)$ pip install /path/to/django_paddle_subscriptions-1.3.0-py2.py3-none-any.whl","title":"1. Download and install the package with pip"},{"location":"getting-started/#2-add-the-app-to-installed_apps-of-your-project-settings","text":"INSTALLED_APPS = [ # ... \"paddle_subscriptions\", ]","title":"2. Add the app to INSTALLED_APPS of your project settings"},{"location":"getting-started/#3-add-subscriptionmiddleware-to-the-middleware-setting","text":"MIDDLEWARE = [ # ... \"paddle_subscriptions.middleware.SubscriptionMiddleware\", ] It will allow to access the current subscriber's data at request.subscriber .","title":"3. Add SubscriptionMiddleware to the MIDDLEWARE setting"},{"location":"getting-started/#4-add-paddle_subscriptions-settings","text":"PADDLE_SUBSCRIPTIONS = { \"API_KEY\": \"...\", \"PUBLIC_KEY\": \"...\", \"CLIENT_SIDE_TOKEN\": \"...\", \"ENVIRONMENT\": \"sandbox\", \"WEBSITE_URL\": \"https://example.com\", # ... } Important note! Don't commit the keys and tokens to the version control for security reasons! Set the setting PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS'] = ['...'] to show pricing or other subscription-related widgets only to visitors from those IPs.","title":"4. Add PADDLE_SUBSCRIPTIONS settings"},{"location":"getting-started/#5-add-a-path-to-urlpatterns","text":"from django.urls import path, include urlpatterns = [ # \u2026 path( \"subscriptions/\", include(\"paddle_subscriptions.urls\", namespace=\"paddle_subscriptions\"), ), ]","title":"5. Add a path to urlpatterns"},{"location":"getting-started/#6-create-paddle-data","text":"In your Django project, create subscription plans with benefits for pricing widgets. If you have a free plan, set the call-to-action URL name at PADDLE_SUBSCRIPTIONS['FREE_PLAN_CTA_URL'] , for example, the sign up or waitlist form. At Paddle create Products for each paid subscription plan, and monthly and yearly prices for each product. You can skip monthly or yearly pricing if you want, but then you will need to modify the overwritten templates to exclude them there too. Deploy the data to a publicly accessible staging or production website. Paddle will send events to that website.","title":"6. Create Paddle data"},{"location":"getting-started/#7-link-paddle-with-your-website","text":"Run the management command to fetch Paddle data and install the webhook: (venv)$ python manage.py set_up_paddle_subscriptions The webhook at https://example.com/subscriptions/webhook/ will be registered at Paddle and all Paddle events available in the API will be sent to it. Then, link your subscription plans with sandbox monthly and yearly prices. Also set the default payment link at Paddle (Paddle \u2794 Checkout \u2794 Checkout settings) to https://example.com/subscriptions/payments/ . It will redirect to the correct location based on your SaaS project if you have more than one with the same Paddle account.","title":"7. Link Paddle with your website"},{"location":"getting-started/#8-create-a-pricing-page","text":"Add the following template tag either on the start page or on a separate pricing page view: {% load paddle_subscriptions_tags %} {% paddle_subscriptions_pricing %}","title":"8. Create a pricing page"},{"location":"getting-started/#9-copy-the-templates-to-your-project","text":"Copy the templates from paddle_subscriptions/templates in site-packages to your project and adjust them as necessary. The copy of the templates serves two purposes: you can collect translatable strings into your project, and you can make the TailwindCSS classes discoverable by your installation.","title":"9. Copy the templates to your project"},{"location":"getting-started/#10-update-your-signup-and-account-deletion-views","text":"Your Signup view must link to the subscription that has been done before signup or create a new subscriber with a free plan if they haven't subscribed yet: from paddle_subscriptions.services import ( get_validated_unlinked_transaction, connect_new_user_to_subscription, create_subscriber_for_free_plan, get_initial_data_for_new_user, ) @transaction.atomic @never_cache def register(request, *arguments, **keywords): \"\"\" Displays the registration form and handles the registration action \"\"\" m = hashlib.md5() m.update(force_bytes(request.META[\"REMOTE_ADDR\"])) request.session.session_id = m.hexdigest()[:20] transaction = None if transaction_id := request.COOKIES.get(\"paddle_transaction_id\"): transaction = get_validated_unlinked_transaction(transaction_id) if request.method == \"POST\": form = RegistrationForm(request, request.POST) if form.is_valid(): user = form.save() if transaction: connect_new_user_to_subscription(user, transaction, subscriber_name=form.cleaned_data[\"company_name\"]) else: create_subscriber_for_free_plan(user, subscriber_name=form.cleaned_data[\"company_name\"]) response = redirect(\"accounts:register_pending\") if transaction: response.delete_cookie(\"paddle_transaction_id\") return response else: initial = None if transaction: initial = get_initial_data_for_new_user(transaction) initial[\"company_name\"] = transaction.business.name if transaction.business else \"\" form = RegistrationForm(request, initial=initial) if transaction: form.fields[\"email\"].widget.attrs[\"readonly\"] = True request.session.set_test_cookie() response = render( request, \"accounts/signup.html\", {\"form\": form}, ) return response Then your account deletion view must cancel the existing subscription: from paddle_subscriptions.services import cancel_subscription @login_required def delete_account(request): context = {} if ( request.user.is_authenticated and not request.user.is_staff and request.method == \"POST\" ): form = DeleteAccountForm(user=request.user, data=request.POST) if form.is_valid(): user = request.user if subscription := request.subscriber.current_subscription: cancel_subscription(subscription, effective_from=\"immediately\") if request.subscriber.membership_set.count() == 1: request.subscriber.delete() auth_logout(request) form.delete() response = redirect(\"accounts:delete_account_complete\") return response else: form = DeleteAccountForm(user=request.user) context[\"form\"] = form return render(request, \"accounts/delete_account.html\", context)","title":"10. Update your signup and account deletion views"},{"location":"getting-started/#how-to-use","text":"","title":"How to Use"},{"location":"getting-started/#1-the-subscription-details-page","text":"The page at https://example.com/subscriptions/ allows you to subscribe to a paid plan or view the details of your current subscription. Use the {% url \"paddle_subscriptions:subscription_details\" %} in the templates to link to that page. Test the pausing, resuming, and cancelling subscriptions there. Also test the billing history and invoices.","title":"1. The subscription details page"},{"location":"getting-started/#2-check-subscriber-status-in-views-or-templates","text":"These are some common values that might be interesting in your views and templates about the current subscriber: # The slug of the current subscriber's subscription plan request.subscriber.plan.slug # Does the current subscriber have free access to their subscription plan? # (the plan itself is free or the subscriber has an exclusive manually set free access) request.subscriber.has_free_access # Is the current subscription active? request.subscriber.is_subscription_active # Will the current subscription be paused at the end of the billing cycle? request.subscriber.is_subscription_to_be_paused # Is the current subscription paused at the moment? request.subscriber.is_subscription_paused # Will the current subscription be cancelled at the end of the billing cycle? request.subscriber.is_subscription_to_be_cancelled # Is the current subscription cancelled at the moment? # (only possible for pricing without a free plan) request.subscriber.is_subscription_cancelled","title":"2. Check subscriber status in views or templates"},{"location":"getting-started/#3-translate-the-strings-in-your-templates","text":"If your website has more than one language, prepare the translations: Use management command makemessages to collect translatable strings into django.po files. Translate the strings to the languages you need. Then, use the management command compilemessages to compile them to django.mo files.","title":"3. Translate the strings in your templates"},{"location":"getting-started/#when-going-live","text":"Paddle has an extensive list of steps about going live . Read it thoroughly. What relates to Django Paddle Subscriptions follows:","title":"When going live"},{"location":"getting-started/#1-set-paddle-environment-to-live","text":"Set the environment to \"live\": PADDLE_SUBSCRIPTIONS[\"ENVIRONMENT\"] = \"live\" Make sure that PADDLE_SUBSCRIPTIONS[\"WEBSITE_URL\"] points to the URL of the production website, which has to be approved by Paddle. Remove the PADDLE_SUBSCRIPTIONS[\"RESTRICTED_TO_IPS\"] setting.","title":"1. Set Paddle environment to live"},{"location":"getting-started/#2-flush-staging-data-and-set-up-paddle-subscription-anew","text":"(venv)$ python manage.py flush_paddle_billing_models (venv)$ python manage.py set_up_paddle_subscriptions Then, link your subscription plans with live monthly and yearly prices.","title":"2. Flush staging data and set up Paddle subscription anew"},{"location":"getting-started/#3-test-live-payments-and-subscriptions","text":"Create a 100% discount code on the Paddle live environment and test your subscriptions with that code.","title":"3. Test live payments and subscriptions"},{"location":"screenshots/","text":"Screenshots Pricing Monthly Pricing Yearly Pricing Subscription Details Current Status Paused Subscription Billing History","title":"Screenshots"},{"location":"screenshots/#screenshots","text":"","title":"Screenshots"},{"location":"screenshots/#pricing","text":"","title":"Pricing"},{"location":"screenshots/#monthly-pricing","text":"","title":"Monthly Pricing"},{"location":"screenshots/#yearly-pricing","text":"","title":"Yearly Pricing"},{"location":"screenshots/#subscription-details","text":"","title":"Subscription Details"},{"location":"screenshots/#current-status","text":"","title":"Current Status"},{"location":"screenshots/#paused-subscription","text":"","title":"Paused Subscription"},{"location":"screenshots/#billing-history","text":"","title":"Billing History"}]}
\ No newline at end of file
diff --git a/docs/sitemap.xml b/docs/sitemap.xml
index dd01fdd..0db564e 100644
--- a/docs/sitemap.xml
+++ b/docs/sitemap.xml
@@ -2,32 +2,32 @@
 
     
          https://websightful.github.io/django-paddle-subscriptions-docs/
-         2024-02-11
+         2024-02-13
          daily
     
     
          https://websightful.github.io/django-paddle-subscriptions-docs/CHANGELOG/
-         2024-02-11
+         2024-02-13
          daily
     
     
          https://websightful.github.io/django-paddle-subscriptions-docs/LICENSE/
-         2024-02-11
+         2024-02-13
          daily
     
     
          https://websightful.github.io/django-paddle-subscriptions-docs/customization/
-         2024-02-11
+         2024-02-13
          daily
     
     
          https://websightful.github.io/django-paddle-subscriptions-docs/getting-started/
-         2024-02-11
+         2024-02-13
          daily
     
     
          https://websightful.github.io/django-paddle-subscriptions-docs/screenshots/
-         2024-02-11
+         2024-02-13
          daily
     
 
\ No newline at end of file
diff --git a/docs/sitemap.xml.gz b/docs/sitemap.xml.gz
index 00a16d9..cca1cb4 100644
Binary files a/docs/sitemap.xml.gz and b/docs/sitemap.xml.gz differ
diff --git a/src/getting-started.md b/src/getting-started.md
index 71f6c5a..7cc77aa 100644
--- a/src/getting-started.md
+++ b/src/getting-started.md
@@ -274,7 +274,7 @@ PADDLE_SUBSCRIPTIONS["ENVIRONMENT"] = "live"
 
 Make sure that `PADDLE_SUBSCRIPTIONS["WEBSITE_URL"]` points to the URL of the production website, which has to be approved by Paddle.
 
-Remove the `PADDLE_SUBSCRIPTIONS['RESTRICTED_TO_IPS']` setting.
+Remove the `PADDLE_SUBSCRIPTIONS["RESTRICTED_TO_IPS"]` setting.
 
 ### 2. Flush staging data and set up Paddle subscription anew