{"id":127008,"date":"2025-04-14T16:02:06","date_gmt":"2025-04-14T16:02:06","guid":{"rendered":"\/tutorials\/?p=127008"},"modified":"2026-06-19T06:45:23","modified_gmt":"2026-06-19T06:45:23","slug":"hostinger-horizons-stripe-integration","status":"publish","type":"post","link":"\/ng\/tutorials\/hostinger-horizons-stripe-integration\/","title":{"rendered":"How to integrate Stripe payments with Hostinger Horizons"},"content":{"rendered":"<p>Stripe is a payment platform that lets you accept online payments and manage subscriptions securely. Integrating Stripe with a Hostinger Horizons web app gives you a complete, server-side subscription system without writing backend code yourself.<\/p><p>To integrate Stripe with your Hostinger Horizons web app, follow these steps:<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>Prepare a database to store user and subscription data.<\/li>\n\n\n\n<li>Add sign-up and login for user accounts.<\/li>\n\n\n\n<li>Create a Stripe account.<\/li>\n\n\n\n<li>Build a subscription product and copy your API keys.<\/li>\n\n\n\n<li>Configure Stripe webhooks.<\/li>\n\n\n\n<li>Store your keys as environment variables.<\/li>\n\n\n\n<li>Link Stripe to your Horizons project.<\/li>\n\n\n\n<li>Test the payment flow.<\/li>\n\n\n\n<li>Add a customer portal so subscribers can manage their plans.<\/li>\n\n\n\n<li>Go live to accept real payments.<\/li>\n<\/ol><p><\/p><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-before-you-start\"><strong>Before you start<\/strong><\/h2><p>Before adding Stripe, <a href=\"\/ng\/tutorials\/connect-custom-domain-to-web-app\/\">connect your web app to a custom domain<\/a>. Stripe requires a live domain when setting up webhooks and going live, so this step is essential.<\/p><p>We&rsquo;ll build a recurring subscription model where users pay a fixed monthly fee to access premium content. The same steps apply to any subscription-based use case, including membership sites, SaaS tools, and gated communities.<\/p><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-1-set-up-the-database-for-your-project\"><strong>1. Set up the database for your project<\/strong><\/h2><p>Hostinger <a href=\"\/horizons\/ai-app-builder\">AI app builder<\/a> includes an integrated database you can access directly from the editor using the <strong>Data<\/strong> button. Before connecting Stripe, make sure your project has a database set up to store user and subscription data.<\/p><p>You don&rsquo;t need to configure anything manually. Describe what you need in the Horizons chat, and the AI sets up the necessary database collections for you.<\/p><p>Open your Horizons project and use a prompt like:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>Add user accounts to my project.<\/pre><p>Once submitted, your data dashboard appears in the editor. You can view and manage live data after publishing your project.<\/p><figure data-wp-context='{\"imageId\":\"6a5885283f830\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a5885283f830\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Horizons-editor-with-the-Data-button-highlighted.png\/w=1024,h=1024,fit=scale-down\" alt='\"Horizons' editor with the data button highlighted class='\"wp-image-151344\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><figure class=\"wp-block-image size-large\"><a class=\"hgr-tutorials-cta hgr-tutorials-cta-horizons\" href=\"\/ng\/horizons\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"600\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/03\/Horizons-in-text-banner-no-code-website-builder.png\/w=1024,h=1024,fit=scale-down\" alt=\"\" class=\"wp-image-129223\" srcset=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/03\/Horizons-in-text-banner-no-code-website-builder.png\/w=2048,fit=scale-down 2048w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/03\/Horizons-in-text-banner-no-code-website-builder.png\/w=300,fit=scale-down 300w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/03\/Horizons-in-text-banner-no-code-website-builder.png\/w=1024,fit=scale-down 1024w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/03\/Horizons-in-text-banner-no-code-website-builder.png\/w=150,fit=scale-down 150w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/03\/Horizons-in-text-banner-no-code-website-builder.png\/w=768,fit=scale-down 768w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/03\/Horizons-in-text-banner-no-code-website-builder.png\/w=1536,fit=scale-down 1536w\" sizes=\"auto, (max-width: 2048px) 100vw, 2048px\" \/><\/a><\/figure><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-2-add-sign-up-and-log-in-functionality\"><strong>2. Add sign-up and log-in functionality<\/strong><\/h2><p>With subscriptions, users need accounts so their subscription status ties to their identity. Add authentication before connecting Stripe.<\/p><p>In the Horizons chat, use a prompt like:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>Add sign-up and login flows to my project with secure authentication.<\/pre><p>If you&rsquo;ve already added authentication, verify it&rsquo;s set up correctly with:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>Check if sign-up and login flows are fully and securely integrated with the database. I plan to use Stripe for subscriptions, so ensure user accounts are properly managed.<\/pre><figure data-wp-context='{\"imageId\":\"6a588528428bb\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a588528428bb\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Horizons-web-app-preview-login-page.png\/w=1024,h=1024,fit=scale-down\" alt='\"Horizons' preview pane for a web app login page class='\"wp-image-151345\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-3-sign-up-for-a-stripe-account\"><strong>3. Sign up for a Stripe account<\/strong><\/h2><p>To start accepting payments, you&rsquo;ll need a Stripe account:<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>Go to the <a href=\"%5C%22https:\/\/dashboard.stripe.com\/register%5C%22\">Stripe registration page<\/a> and create your free account.<\/li>\n\n\n\n<li>Enter your email, password, and business or personal details.<\/li>\n\n\n\n<li>Check your inbox and verify your email address to activate the account.<\/li>\n<\/ol><p>Once your account is created, you&rsquo;ll be redirected to Stripe Sandbox mode, a test environment that lets you simulate payments before going live.<\/p><p>If you want to set up your live Stripe account from the start, click <strong>Switch to live account<\/strong> in the top-right corner of the Stripe dashboard and complete the onboarding process.<\/p><figure data-wp-context='{\"imageId\":\"6a58852844f14\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a58852844f14\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Stripe-dashboard-in-Sandbox-mode-with-the-Switch-to-live-account-button-scaled.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' dashboard in sandbox mode with the switch to live account button class='\"wp-image-151346\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-4-create-a-subscription-product-and-get-your-api-keys\"><strong>4. Create a subscription product and get your API keys<\/strong><\/h2><p>A subscription product sets what users pay and how often, and your API keys let Horizons talk to Stripe. First, create the product:<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>Go to <strong>Product catalog<\/strong> in your Stripe dashboard.<\/li>\n\n\n\n<li>Click <strong>+ Add a product<\/strong>, then fill in the details:\n<ul class='\"wp-block-list\" wp-block-list'>\n<li><strong>Name<\/strong>. Enter a clear name, such as Pro Plan.<\/li>\n\n\n\n<li><strong>Pricing model<\/strong>. Select Recurring.<\/li>\n\n\n\n<li><strong>Amount<\/strong>. For testing, set this to <strong>$0<\/strong> so you can run the full purchase flow without being charged, then update the price before going live.<\/li>\n\n\n\n<li><strong>Billing period<\/strong>. Choose Monthly, or adjust to fit your needs.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Click <strong>Add product<\/strong> to save it.<\/li>\n<\/ol><figure data-wp-context='{\"imageId\":\"6a588528460d9\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a588528460d9\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img loading=\"lazy\" decoding=\"async\" width=\"2842\" height=\"1364\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' product catalog creation dialog class='\"wp-image-127018\"' srcset=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=2842,fit=scale-down 2842w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=300,fit=scale-down 300w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=1024,fit=scale-down 1024w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=150,fit=scale-down 150w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=768,fit=scale-down 768w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=1536,fit=scale-down 1536w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-add-a-product.png\/w=2048,fit=scale-down 2048w\" sizes=\"auto, (max-width: 2842px) 100vw, 2842px\" \/><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><ol start='\"4\"' class='\"wp-block-list\" wp-block-list'>\n<li>Open the product, click the three-dot icon next to the price, and select <strong>Copy price ID<\/strong>.<\/li>\n<\/ol><p>Save this price ID. You&rsquo;ll need it later, and it looks like <strong>price_&hellip;<\/strong>.<\/p><figure data-wp-context='{\"imageId\":\"6a58852846f2f\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a58852846f2f\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img loading=\"lazy\" decoding=\"async\" width=\"1540\" height=\"910\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-products-copy-price-id.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' product catalog with the copy price id option highlighted class='\"wp-image-127019\"' srcset=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-products-copy-price-id.png\/w=1540,fit=scale-down 1540w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-products-copy-price-id.png\/w=300,fit=scale-down 300w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-products-copy-price-id.png\/w=1024,fit=scale-down 1024w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-products-copy-price-id.png\/w=150,fit=scale-down 150w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-products-copy-price-id.png\/w=768,fit=scale-down 768w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-products-copy-price-id.png\/w=1536,fit=scale-down 1536w\" sizes=\"auto, (max-width: 1540px) 100vw, 1540px\" \/><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><p>Then, copy your API keys:<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>Go to the <strong>API Keys<\/strong> page in your Stripe dashboard.<\/li>\n\n\n\n<li>Under <strong>Standard keys<\/strong>, copy both:\n<ul class='\"wp-block-list\" wp-block-list'>\n<li>Publishable key, which starts with <strong>pk_live_&hellip;<\/strong> (<strong>pk_test_&hellip;<\/strong> in Sandbox mode).<\/li>\n\n\n\n<li>Secret key, which starts with <strong>sk_live_&hellip;<\/strong> (<strong>sk_test_&hellip;<\/strong> in Sandbox mode).<\/li>\n<\/ul>\n<\/li>\n<\/ol><figure data-wp-context='{\"imageId\":\"6a5885284a136\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a5885284a136\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Stripe-API-Keys-page-with-both-keys.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' api keys page with both highlighted class='\"wp-image-151347\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><p><div class=\"announcement-block announcement-block--important\">\n            <span class=\"announcement-block__heading\">\n                <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                    <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n                          d=\"M12 22.5C17.799 22.5 22.5 17.799 22.5 12C22.5 6.20101 17.799 1.5 12 1.5C6.20101 1.5 1.5 6.20101 1.5 12C1.5 17.799 6.20101 22.5 12 22.5ZM13.637 7.65198C13.637 6.74791 12.9041 6.01501 12 6.01501C11.0959 6.01501 10.363 6.74791 10.363 7.65198C10.5335 9.53749 10.875 13.383 10.875 13.383C10.875 14.0043 11.3787 14.508 12 14.508C12.6213 14.508 13.125 14.0043 13.125 13.383V13.38L13.637 7.65198ZM11.9927 15.714C11.3714 15.714 10.8677 16.2177 10.8677 16.839C10.8677 17.4603 11.3714 17.964 11.9927 17.964H12.0073C12.6286 17.964 13.1323 17.4603 13.1323 16.839C13.1323 16.2177 12.6286 15.714 12.0073 15.714H11.9927Z\"\n                          fill=\"#FEA419\"\/>\n                <\/svg>\n                Important\n            <\/span>\n            <p class=\"announcement-block__content\">\n                <strong>Important!<\/strong> Your secret key provides full access to your Stripe account. Never share it or expose it in your frontend code, and save it somewhere secure, because you won&rsquo;t be able to view it again after leaving the page.\n            <\/p><\/div>\n\n\n\n<\/p><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-5-set-up-stripe-webhooks\"><strong>5. Set up Stripe webhooks<\/strong><\/h2><p>Webhooks are how Stripe communicates with your project. They keep subscription statuses in sync, for example when a payment succeeds, fails, or a user cancels their plan.<\/p><p>First, ask Horizons to create a webhook endpoint. Horizons uses an Express API server for server-side logic, so use a prompt like this to add the API route that receives Stripe webhook events:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>Create an API route on the server that exposes an endpoint URL for handling Stripe webhooks. You can name it stripe-webhook. Don't make any other changes to the project!<\/pre><p>Horizons generates a webhook endpoint URL. Copy it, since you&rsquo;ll need it in the next step.<\/p><p>Then, create the webhook in Stripe:<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>Go to <strong>Developers &rarr; Webhooks<\/strong> in your Stripe dashboard.<\/li>\n\n\n\n<li>Click <strong>+ Add destination<\/strong>.<\/li>\n\n\n\n<li>In the first step, select <strong>Your account<\/strong>, then search for and select these three events:\n<ul class='\"wp-block-list\" wp-block-list'>\n<li><strong>checkout.session.completed<\/strong>.<\/li>\n\n\n\n<li><strong>customer.subscription.updated<\/strong>.<\/li>\n\n\n\n<li><strong>customer.subscription.deleted<\/strong>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Click <strong>Continue<\/strong>.<\/li>\n<\/ol><figure data-wp-context='{\"imageId\":\"6a5885284c52c\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a5885284c52c\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Stripe-webhook-destination-setup-with-event-destination-selection.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' webhook destination setup with event selection class='\"wp-image-151348\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><ol start='\"5\"' class='\"wp-block-list\" wp-block-list'>\n<li>In the next step, select <strong>Webhook endpoint<\/strong> and click <strong>Continue<\/strong>.<\/li>\n\n\n\n<li>Fill in the following fields:\n<ul class='\"wp-block-list\" wp-block-list'>\n<li><strong>Destination name<\/strong>: enter something like &ldquo;Horizons webhook for subscriptions.&rdquo;<\/li>\n\n\n\n<li><strong>Endpoint URL<\/strong>: paste the URL generated by Horizons in the previous step.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Complete the setup.<\/li>\n<\/ol><figure data-wp-context='{\"imageId\":\"6a5885284f0f3\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a5885284f0f3\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Stripe-webhook-destination-setup-with-the-endpoint-URL-field.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' webhook destination setup with the endpoint url field class='\"wp-image-151349\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><p>After completing the setup, Stripe provides a signing secret that starts with <strong>whsec_&hellip;<\/strong>. Copy and save it, since you&rsquo;ll need it in the next step.<\/p><figure data-wp-context='{\"imageId\":\"6a58852850ed4\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a58852850ed4\" class='\"wp-block-image wp-lightbox-container' aligncenter size-full><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Stripe-signing-secret-field-in-the-destination-details-highlighted.png\/public\" alt='\"Stripe' signing secret field in the destination details class='\"wp-image-151350\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-6-save-your-stripe-keys-as-environment-variables\"><strong>6. Save your Stripe keys as environment variables<\/strong><\/h2><p>To keep your secret key and webhook signing secret secure, save them as environment variables on the Horizons API server. This keeps them out of your frontend code.<\/p><p>In the Horizons chat, use this prompt, replacing the placeholder values with your actual keys from steps 4 and 5:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>Add the following environment variables to the API server:\n\nSTRIPE_SECRET_KEY = sk_live_&hellip;\nSTRIPE_WEBHOOK_SECRET = whsec_&hellip;\n\nDon't make any other changes to the project!<\/pre><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-7-connect-stripe-with-your-horizons-project\"><strong>7. Connect Stripe with your Horizons project<\/strong><\/h2><p>The prompt below securely connects your Stripe subscription to your project, handling checkout, webhooks, the subscription product, and access control in one step.<\/p><p>Before sending, replace the placeholder values with:<\/p><ul class='\"wp-block-list\" wp-block-list'>\n<li>Your price ID (from step 4), which looks like <strong>price_&hellip;<\/strong>.<\/li>\n\n\n\n<li>Your publishable key (from step 4), which looks like <strong>pk_live_&hellip;<\/strong>.<\/li>\n\n\n\n<li>Your actual domain in place of <strong>your-domain<\/strong>.<\/li>\n<\/ul><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>I want to securely integrate Stripe to sell subscriptions in my Hostinger Horizons project.\n\nI have already stored my Stripe keys as environment variables on the API server:\n\nSecret key: STRIPE_SECRET_KEY\nWebhook signing secret: STRIPE_WEBHOOK_SECRET\n\nStep 1: Checkout session &amp; webhooks\n\nCreate an API route on the server that handles Stripe checkout sessions. When a user starts the subscription purchase flow, securely create a Stripe Checkout session using my stored secret key and return the session URL for redirecting the user.\n\nWhen creating the Stripe Checkout session, pass both success_url and cancel_url. Make sure these URLs use my site's domain: your-domain.\n\nCreate a Stripe customer and save the generated stripe_customer_id to the database.\n\nFor any updates received from the Stripe webhook, use the stripe_customer_id to find and update the correct user record in the database.\n\nStep 2: Subscription product\n\nAdd my Stripe subscription product to the Horizons project.\n\nStripe product price ID: price_&hellip;\nStripe publishable key: pk_live_&hellip;\n\nAdd an \"Upgrade\" button in the project that triggers the subscription purchase flow.\n\nEnsure the subscription is fully linked to the user database.\n\nOnly users with an active subscription can access premium features.\n\nStep 3: Access control\n\nInstantly grant users premium access after purchase.\n\nEnsure subscription status is checked in real-time when users log in, create an account, or try to access premium features.\n\nStep 4: Security &amp; correctness\n\nEnsure the integration is secure and does not expose secret keys to the frontend.\n\nHandle all Stripe communication server-side via the API server.<\/pre><p>Give Horizons a moment to process and apply the changes.<\/p><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-8-test-the-payment-integration\"><strong>8. Test the payment integration<\/strong><\/h2><p>Your web app should now be ready to accept test payments. You can&rsquo;t test the Stripe integration using the preview pane in Horizons, because the live preview runs within a sandboxed iframe that restricts redirects for security.<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>Click <strong>Publish<\/strong> in the top-right corner of the project dashboard to launch your app.<\/li>\n\n\n\n<li>Open your web app through your custom domain and try subscribing.<\/li>\n\n\n\n<li>On the Stripe checkout page, use these test details:\n<ul class='\"wp-block-list\" wp-block-list'>\n<li><strong>Card number<\/strong>. 4242 4242 4242 4242.<\/li>\n\n\n\n<li><strong>Expiration date<\/strong>. Any future date.<\/li>\n\n\n\n<li><strong>CVC<\/strong>. Any 3-digit number (4 digits for Amex test cards).<\/li>\n\n\n\n<li><strong>Name, email, country<\/strong>. Any values.<\/li>\n<\/ul>\n<\/li>\n<\/ol><figure data-wp-context='{\"imageId\":\"6a5885285203d\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a5885285203d\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img loading=\"lazy\" decoding=\"async\" width=\"1824\" height=\"1498\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-checkout.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' checkout page with the test card details class='\"wp-image-127023\"' srcset=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-checkout.png\/w=1824,fit=scale-down 1824w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-checkout.png\/w=300,fit=scale-down 300w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-checkout.png\/w=1024,fit=scale-down 1024w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-checkout.png\/w=150,fit=scale-down 150w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-checkout.png\/w=768,fit=scale-down 768w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-checkout.png\/w=1536,fit=scale-down 1536w\" sizes=\"auto, (max-width: 1824px) 100vw, 1824px\" \/><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><p>If the payment succeeds, you&rsquo;ll be redirected back to your app with premium access granted. You can also verify the subscription in your Stripe dashboard under <strong>Customers<\/strong>.<\/p><p>        <div class=\"protip\">\n            <div class=\"protip__heading\">\n                <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                    <path d=\"M1.49234 23.5024C1.23229 23.5024 0.972242 23.4024 0.782206 23.2123C0.562165 22.9923 0.452144 22.6822 0.502153 22.3722C0.562165 21.9221 1.14227 17.9113 3.00262 16.351C3.63274 15.8209 4.43289 15.5509 5.26305 15.5609C6.09321 15.5909 6.87335 15.9109 7.47347 16.4911C8.6937 17.6913 8.76371 19.6717 7.6435 20.9919C6.0832 22.8523 2.08245 23.4324 1.63237 23.4924C1.59236 23.4924 1.54235 23.4924 1.50234 23.4924L1.49234 23.5024ZM5.16303 17.5613C4.84297 17.5613 4.53291 17.6713 4.29287 17.8813C3.60274 18.4614 3.07264 19.9317 2.75258 21.242C4.06282 20.9219 5.5331 20.3918 6.11321 19.7017C6.55329 19.1716 6.54329 18.3814 6.0832 17.9213C5.85316 17.7013 5.5431 17.5713 5.20304 17.5613C5.19304 17.5613 5.17303 17.5613 5.16303 17.5613ZM11.7243 21.8821C11.4942 21.8821 11.2642 21.8021 11.0841 21.652C10.8541 21.462 10.7241 21.1819 10.7241 20.8819V15.9109L8.08358 13.2705H3.11264C2.81259 13.2705 2.53254 13.1404 2.3425 12.9104C2.15246 12.6803 2.07245 12.3803 2.12246 12.0902C2.19247 11.7102 2.84259 8.36953 4.70294 7.12929C6.33325 6.04909 8.96375 6.49918 10.244 6.80923C11.5442 4.96889 13.2546 3.4286 15.2349 2.33839C17.4553 1.11816 19.9858 0.518051 22.4963 0.498047C23.0464 0.498047 23.4865 0.948132 23.4865 1.49824C23.4865 5.0389 22.3763 9.97983 17.1753 13.7605C17.4853 15.0408 17.9354 17.6613 16.8552 19.2816C15.615 21.1419 12.2744 21.7921 11.8943 21.8621C11.8343 21.8721 11.7743 21.8821 11.7143 21.8821H11.7243ZM12.7245 16.181V19.6016C13.7146 19.2916 14.7948 18.7915 15.2049 18.1814C15.675 17.4812 15.605 16.091 15.385 14.9008C14.5248 15.3808 13.6346 15.8109 12.7245 16.181ZM9.66388 12.0302L11.9643 14.3307C13.1845 13.8306 14.3648 13.2204 15.485 12.5103C19.9358 9.51974 21.2361 5.60901 21.4561 2.53843C19.6157 2.67846 17.8254 3.20856 16.2051 4.09872C14.2847 5.14892 12.6544 6.68921 11.4942 8.54956C10.7841 9.65977 10.174 10.82 9.66388 12.0302ZM4.39289 11.2701H7.81353C8.1936 10.3599 8.63368 9.46974 9.11377 8.60957C7.92355 8.38953 6.51329 8.31952 5.81315 8.78961C5.19304 9.19968 4.70294 10.3099 4.39289 11.2701Z\" fill=\"#673DE6\"\/>\n                <\/svg>\n                <p class=\"protip__title\">\n                    Pro tip                <\/p>\n            <\/div>\n            <p class=\"protip__content\"> Since you set the test product price to <strong>$0<\/strong> in step 4, you can complete the full purchase flow without any charges. Update the price to your actual rate before going live.<\/p>\n                    <\/div>\n        \n\n\n\n<\/p><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-9-add-a-customer-portal-for-subscription-management\"><strong>9. Add a customer portal for subscription management<\/strong><\/h2><p>Once your subscription flow is working, give users the ability to manage their own subscriptions through Stripe&rsquo;s built-in customer portal, where they can update payment methods, view invoices, or cancel.<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>Go to <strong>Settings &rarr; Billing &rarr; Customer portal<\/strong>.<\/li>\n\n\n\n<li>Find the <strong>Launch customer portal with a link<\/strong> section.<\/li>\n\n\n\n<li>Click <strong>Activate link<\/strong> to enable the portal.<\/li>\n<\/ol><figure data-wp-context='{\"imageId\":\"6a588528542e7\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a588528542e7\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/Stripe-Customer-Portal-settings-page-with-the-Activate-link-button-highlighted.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' customer portal settings page with the activate link button highlighted class='\"wp-image-151351\"'><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><p>Then, go back to Horizons and use this prompt:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>Create a new API route on the server that securely generates a link to the Stripe Customer Portal for the logged-in user.\n\nThen, add a \"Manage subscription\" button to my project. This button should be visible only to paid users. Clicking it should redirect users to the Stripe Customer Portal, where they can manage their subscriptions.<\/pre><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-10-switch-to-live-mode\"><strong>10. Switch to live mode<\/strong><\/h2><p>Once you&rsquo;ve <a href=\"\/ng\/tutorials\/web-app-testing\/\">tested your web app<\/a> and are ready to accept real payments, switch to live mode in Stripe.<\/p><p><div class=\"announcement-block announcement-block--important\">\n            <span class=\"announcement-block__heading\">\n                <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                    <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n                          d=\"M12 22.5C17.799 22.5 22.5 17.799 22.5 12C22.5 6.20101 17.799 1.5 12 1.5C6.20101 1.5 1.5 6.20101 1.5 12C1.5 17.799 6.20101 22.5 12 22.5ZM13.637 7.65198C13.637 6.74791 12.9041 6.01501 12 6.01501C11.0959 6.01501 10.363 6.74791 10.363 7.65198C10.5335 9.53749 10.875 13.383 10.875 13.383C10.875 14.0043 11.3787 14.508 12 14.508C12.6213 14.508 13.125 14.0043 13.125 13.383V13.38L13.637 7.65198ZM11.9927 15.714C11.3714 15.714 10.8677 16.2177 10.8677 16.839C10.8677 17.4603 11.3714 17.964 11.9927 17.964H12.0073C12.6286 17.964 13.1323 17.4603 13.1323 16.839C13.1323 16.2177 12.6286 15.714 12.0073 15.714H11.9927Z\"\n                          fill=\"#FEA419\"\/>\n                <\/svg>\n                Important\n            <\/span>\n            <p class=\"announcement-block__content\">\n                <strong>Important!<\/strong> Once live mode is active, test card numbers no longer work. Real credit cards result in actual charges, so proceed carefully.\n            <\/p><\/div>\n\n\n\n<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li>In your Stripe dashboard, click <strong>Get your live account<\/strong> at the top of the page and complete the onboarding, which includes entering your business details and bank account information.<\/li>\n<\/ol><figure data-wp-context='{\"imageId\":\"6a58852855487\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a58852855487\" class='\"wp-block-image wp-lightbox-container' aligncenter size-large><img loading=\"lazy\" decoding=\"async\" width=\"1990\" height=\"1430\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-live-account-onboarding.png\/w=1024,h=1024,fit=scale-down\" alt='\"Stripe' verify your business dialog to get a live account class='\"wp-image-127025\"' srcset=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-live-account-onboarding.png\/w=1990,fit=scale-down 1990w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-live-account-onboarding.png\/w=300,fit=scale-down 300w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-live-account-onboarding.png\/w=1024,fit=scale-down 1024w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-live-account-onboarding.png\/w=150,fit=scale-down 150w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-live-account-onboarding.png\/w=768,fit=scale-down 768w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2025\/04\/stripe-live-account-onboarding.png\/w=1536,fit=scale-down 1536w\" sizes=\"auto, (max-width: 1990px) 100vw, 1990px\" \/><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" aria-label=\"Enlarge\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.imageButtonRight\" data-wp-style--top=\"state.imageButtonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><ol start='\"2\"' class='\"wp-block-list\" wp-block-list'>\n<li>Go back to <strong>Product catalog<\/strong> and create a new product with your actual live pricing.<\/li>\n\n\n\n<li>Go to <strong>API Keys<\/strong> and copy your live publishable key (<strong>pk_live_&hellip;<\/strong>) and live secret key (<strong>sk_live_&hellip;<\/strong>).<\/li>\n\n\n\n<li>Set up a new webhook endpoint pointing to your live domain (repeat step 5 using your live domain URL).<\/li>\n\n\n\n<li>In Horizons, update your environment variables with the live keys (repeat step 6 with live values).<\/li>\n<\/ol><p>Use this prompt to update the integration with your live credentials:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>I've switched Stripe to live mode. Can you update my web app with the live price ID and publishable key? Here are the details:\n\nprice ID: price_&hellip;\npublishable key: pk_live_&hellip;<\/pre><p>Re-publish your app once Horizons finishes processing.<\/p><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-why-integrate-stripe-with-hostinger-horizons\"><strong>Why integrate Stripe with Hostinger Horizons?<\/strong><\/h2><p>Connecting Stripe with Hostinger Horizons gives you a complete, server-side way to accept recurring payments directly in your web app. Horizons handles your frontend and backend while Stripe manages the payments, so you get:<\/p><ul class='\"wp-block-list\" wp-block-list'>\n<li>Recurring billing on a monthly, yearly, or custom cycle<\/li>\n\n\n\n<li>Server-side payment processing that keeps sensitive keys off the frontend.<\/li>\n\n\n\n<li>Webhook-based subscription tracking that keeps statuses in sync automatically.<\/li>\n\n\n\n<li>A customer portal for updating payment methods, viewing invoices, and canceling.<\/li>\n<\/ul><p>Whether you&rsquo;re running a paid membership platform, a SaaS tool, or a premium content site, this setup gives you a strong base to <a href=\"\/ng\/tutorials\/how-to-monetize-a-web-app\/\">monetize your app<\/a> and grow it over time.<\/p><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-stripe-integration-use-cases\"><strong>Stripe integration use cases<\/strong><\/h2><p>A recurring subscription is one of several ways to charge with Stripe. Two other common models are one-time per-item purchases and pay-what-you-want donations.<\/p><h3 class='\"wp-block-heading\" wp-block-heading'><strong>Per-item purchases<\/strong><\/h3><p>For individual items or digital products like ebooks or courses, <a href=\"%5C%22https:\/\/www.hostinger.com\/support\/12038921-hostinger-horizons-integration-with-online-store\/%5C%22\">Hostinger Horizons has a built-in Online Store<\/a> that handles one-time payments automatically, so you don&rsquo;t need to set up Stripe yourself.<\/p><p>To handle it manually instead, create a product for each item in Stripe and set a one-time payment pricing model to process single transactions.<\/p><p>Then, note each product&rsquo;s price ID and share it with Hostinger Horizons so it updates the payment process for each item. Here&rsquo;s an example prompt:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>I want to set up Stripe payments for the following products. Here are their price IDs:\nprice_abc123... for \"Product 1\"\nprice_xyz789... for \"Product 2\"<\/pre><h3 class='\"wp-block-heading\" wp-block-heading'><strong>Donations and pay-what-you-want<\/strong><\/h3><p>A pay-what-you-want model lets users choose how much to donate, which suits creators, nonprofits, and other donation-based web apps.<\/p><p>In Stripe, go to <strong>Payment Links &rarr; Create payment link<\/strong>, then select <strong>Customers choose what to pay<\/strong> as the payment type. Configure the other settings and click <strong>Create link<\/strong>.<\/p><p>Then, copy the generated link and share it with Hostinger Horizons. To add a donation button, use a prompt like this:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>I want to add a Support Us button that lets users contribute any amount. Link it to [the Stripe donation link].<\/pre><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-security-best-practices-when-using-stripe-on-your-web-app\"><strong>Security best practices when using Stripe on your web app<\/strong><\/h2><p>When integrating Stripe into your web app, follow these tips to minimize vulnerabilities:<\/p><ul class='\"wp-block-list\" wp-block-list'>\n<li><strong>Never expose secret keys in frontend code<\/strong>. Secret keys provide full access to your Stripe account, so always store them as server-side environment variables, as shown in step 6.<\/li>\n\n\n\n<li><strong>Validate webhook signatures server-side<\/strong>. Stripe includes a signature with each webhook event to prove it&rsquo;s genuine, so use your <strong>STRIPE_WEBHOOK_SECRET<\/strong> to verify it before processing any event.<\/li>\n\n\n\n<li><strong>Use HTTPS to encrypt all data between users and your app<\/strong>. Hostinger provides free SSL for your web app, and Stripe&rsquo;s checkout page is served over HTTPS by default.<\/li>\n\n\n\n<li><strong>Keep test and live environments separate<\/strong>. When moving to production, switch to live mode keys, update webhook endpoints to production URLs, and keep test data away from real transactions.<\/li>\n<\/ul><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-troubleshooting-stripe-integration-issues\"><strong>Troubleshooting Stripe integration issues<\/strong><\/h2><p>Even with a proper setup, you may run into issues. Here are the most common ones and how to fix them:<\/p><h3 class='\"wp-block-heading\" wp-block-heading'><strong>Invalid price ID or API keys<\/strong><\/h3><p>This happens when the keys in your project don&rsquo;t match those in your Stripe dashboard.<\/p><ul class='\"wp-block-list\" wp-block-list'>\n<li>Go to <strong>Developers &rarr; API keys &rarr; Standard keys<\/strong> to find the correct publishable key.<\/li>\n\n\n\n<li>For price IDs, go to <strong>Product catalog<\/strong>, open your product, and click the three-dot icon next to the price.<\/li>\n\n\n\n<li>Ask Horizons to update the credentials with the correct values.<\/li>\n\n\n\n<li>Double-check for typos or extra spaces.<\/li>\n<\/ul><h3 class='\"wp-block-heading\" wp-block-heading'><strong>Webhook not firing<\/strong><\/h3><p>This happens when Stripe can&rsquo;t reach your webhook endpoint, or the endpoint isn&rsquo;t processing events correctly.<\/p><ul class='\"wp-block-list\" wp-block-list'>\n<li>Verify your webhook endpoint URL is correct in <strong>Developers &rarr; Webhooks<\/strong>.<\/li>\n\n\n\n<li>View webhook attempts in <strong>Developers &rarr; Events<\/strong>.<\/li>\n\n\n\n<li>Test the webhook using Stripe&rsquo;s built-in webhook tester in the Webhooks tab.<\/li>\n\n\n\n<li>Make sure your <strong>STRIPE_WEBHOOK_SECRET<\/strong> environment variable is set correctly in Horizons.<\/li>\n<\/ul><h3 class='\"wp-block-heading\" wp-block-heading'><strong>Subscription status not updating after payment<\/strong><\/h3><p>This happens when the webhook isn&rsquo;t updating the user record in the database correctly.<\/p><p>Take a screenshot of the issue and describe the expected behavior to Horizons:<\/p><pre class='\"EnlighterJSRAW\"' data-enlighter-language='\"raw\"' data-enlighter-theme='\"\"' data-enlighter-highlight='\"\"' data-enlighter-linenumbers='\"\"' data-enlighter-lineoffset='\"\"' data-enlighter-title='\"\"' data-enlighter-group='\"\"'>After completing the subscription purchase flow, users are redirected back to the project, but their subscription status is not updated, and premium features are not unlocked. Ensure the subscription is verified on return and the user is granted access to premium features immediately. Identify and fix the issue.<\/pre><h3 class='\"wp-block-heading\" wp-block-heading'><strong>Checkout failing to redirect<\/strong><\/h3><p>This occurs when the success and cancel URLs aren&rsquo;t configured correctly.<\/p><ul class='\"wp-block-list\" wp-block-list'>\n<li>Verify that the success and cancel URLs match your actual domain.<\/li>\n\n\n\n<li>Check the browser console for errors during the redirect.<\/li>\n\n\n\n<li>Make sure the domain in your Stripe Checkout session matches your published app URL.<\/li>\n<\/ul><h2 class='\"wp-block-heading\" wp-block-heading' id=\"h-how-to-create-a-membership-website\"><strong>How to create a membership website<\/strong><\/h2><p>A membership website builds on the Stripe subscription system you just set up, adding membership tiers, gated content, and a member area on top of the billing flow.<\/p><p>The sign-up, login, and subscription logic already handle the hard part, so the rest is mostly content structure and access rules.<\/p><p>Here are the steps to build a membership website:<\/p><ol class='\"wp-block-list\" wp-block-list'>\n<li><strong>Define your membership tiers<\/strong>. Decide how many levels you need, such as a free tier and one or more paid tiers, then create a Stripe price for each and connect it to your project the same way you connected your first subscription product.<\/li>\n\n\n\n<li><strong>Gate content by tier<\/strong>. Extend your access control so each piece of content checks the user&rsquo;s active tier, not only whether they hold any subscription.<\/li>\n\n\n\n<li><strong>Add a member dashboard<\/strong>. Give members one place to see their tier, open their content, and launch the Stripe customer portal to manage billing.<\/li>\n\n\n\n<li><strong>Organize your member-only content<\/strong>. Group your premium pages, downloads, or courses so each tier sees only what it pays for.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Stripe is a payment platform that lets you accept online payments and manage subscriptions securely. Integrating Stripe with a Hostinger Horizons web app gives you a complete, server-side subscription system without writing backend code yourself. To integrate Stripe with your Hostinger Horizons web app, follow these steps: Before you start Before adding Stripe, connect your [&#8230;]<\/p>\n<p><a class=\"btn btn-secondary understrap-read-more-link\" href=\"\/ng\/tutorials\/hostinger-horizons-stripe-integration\/\">Read More&#8230;<\/a><\/p>\n","protected":false},"author":411,"featured_media":148307,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"How to integrate Stripe payments with Hostinger Horizons","rank_math_description":"Integrate Stripe with Hostinger Horizons to accept subscriptions. Set up server-side payments, webhooks, and a customer portal, then switch to live mode.","rank_math_focus_keyword":"how to integrate stripe to your web app","footnotes":""},"categories":[22651],"tags":[],"class_list":["post-127008","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-app"],"hreflangs":[{"locale":"en-US","link":"https:\/\/www.hostinger.com\/tutorials\/hostinger-horizons-stripe-integration","default":0},{"locale":"en-GB","link":"https:\/\/www.hostinger.com\/uk\/tutorials\/hostinger-horizons-stripe-integration","default":0},{"locale":"en-IN","link":"https:\/\/www.hostinger.com\/in\/tutorials\/hostinger-horizons-stripe-integration","default":0},{"locale":"en-CA","link":"https:\/\/www.hostinger.com\/ca\/tutorials\/hostinger-horizons-stripe-integration","default":0},{"locale":"en-PH","link":"https:\/\/www.hostinger.com\/ph\/tutorials\/hostinger-horizons-stripe-integration","default":0},{"locale":"en-MY","link":"https:\/\/www.hostinger.com\/my\/tutorials\/hostinger-horizons-stripe-integration","default":0},{"locale":"en-AU","link":"https:\/\/www.hostinger.com\/au\/tutorials\/hostinger-horizons-stripe-integration","default":0},{"locale":"en-NG","link":"https:\/\/www.hostinger.com\/ng\/tutorials\/hostinger-horizons-stripe-integration","default":0}],"_links":{"self":[{"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/posts\/127008","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/users\/411"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/comments?post=127008"}],"version-history":[{"count":11,"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/posts\/127008\/revisions"}],"predecessor-version":[{"id":148306,"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/posts\/127008\/revisions\/148306"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/media\/148307"}],"wp:attachment":[{"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/media?parent=127008"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/categories?post=127008"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hostinger.com\/ng\/tutorials\/wp-json\/wp\/v2\/tags?post=127008"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}