SaaS Monetization · 9 min read · Updated 15 August 2026
How to accept payments in an AI-built app with your own Stripe keys
Payments run through your own Stripe account. On the Pro plan you paste your Stripe secret key under More and Stripe (Klarna) on the project card, where it is encrypted before it is stored. Your app then calls the injected checkout method with its line items and the customer is redirected to a Stripe Checkout page that accepts card and Klarna. NorthernGo never sees card details.
It is your Stripe account, not a NorthernGo payment product
This is the part to be precise about before any code. NorthernGo does not resell payments. You bring your own Stripe account, your own keys and your own money flow, and the platform does one thing: it holds your secret key encrypted and uses it server-side to create a Checkout session when your app asks for one.
The consequences follow from that, and they are written into the terms rather than implied. You are legally responsible towards your own customers for support, refunds and terms of sale. NorthernGo facilitates the connection to Stripe and never processes, sees or stores your customers' card details — those are entered on Stripe's own hosted page, on Stripe's domain, and never touch an app you built here. It also follows that you must never store card numbers in the app's built-in database; that is explicitly prohibited, along with national identity numbers and medical data, and there is nothing in the API that would make it a good idea anyway.
The feature is on the Pro plan. Both the setup call and the checkout call verify the owner's plan independently, which matters later.
Step 1: Save your Stripe secret key
Open My Projects, press More on the project card and choose Stripe (Klarna). The panel asks you to paste your Stripe secret key and links straight to the API keys page in your Stripe Dashboard. The field is a password field, the placeholder shows sk_live_..., and the button says Save key.
Use a test key first. A key beginning sk_test_ works through exactly the same path and gives you Stripe's test mode, where you can complete a purchase with a test card and see the session appear in your dashboard without moving real money. Swap in the live key when the flow is right.
What happens to the key is worth knowing, because "we store your key" is a sentence that deserves detail. The request verifies your login, verifies that you actually own the project, and rejects the save unless your plan is Pro. The key is then encrypted with AES-256-CBC using a key derived with scrypt from a server secret, with a fresh random initialisation vector per value, and the result is stored in a private system collection that the public database routes refuse to read or write. Your app's own end users cannot query it, and neither can anyone else's app. If the server secret is ever rotated, the key is transparently read with the previous secret and re-encrypted with the new one on next use, so a rotation cannot break a live checkout.
When the save succeeds, the project is flagged as connected and the project card starts showing Payments active. That flag is the visible confirmation that the key landed.
Step 2: Ask for the checkout call by name
Every generated app has the platform SDK injected into it, and payments are exposed as window.NorthernGoPayments.checkout(). It takes an array of line items:
await window.NorthernGoPayments.checkout([
{ name: 'Annual licence', price: 1490, quantity: 1 }
]);
price is in whole currency units, not the smallest unit — 1490 means 1490 kronor, and the server multiplies by 100 before it reaches Stripe. quantity defaults to 1 if you leave it out. name is the product name your customer reads on the Stripe page, so write it as a customer-facing label rather than an internal SKU.
There is a wrinkle worth stating plainly. The generation prompts document the database, AI, e-mail, Shopify and webhook parts of the SDK, but they do not document payments. Ask for "a buy button" and the AI has no instruction telling it that this method exists, so it may invent a form or a dead button instead. Name the call in your prompt:
Add a Buy button that calls
window.NorthernGoPayments.checkout([{ name: 'Annual licence', price: 1490, quantity: 1 }])inside a try/catch, and showserror.messagein the interface if it fails.
That instruction is specific enough that the three-agent pipeline has nothing left to guess. It is also worth saving the order in your own data before you redirect, because the redirect leaves your app entirely:
async function buy(item) {
try {
await window.NorthernGoDB.save('orders', {
item: item.name, amount: item.price, status: 'started',
createdAt: new Date().toISOString()
});
await window.NorthernGoPayments.checkout([item]);
} catch (err) {
showMessage(err.message);
}
}
The built-in database is already wired in, so this costs you nothing extra and gives you a record of intent that survives the customer closing the tab.
Step 3: Test on the live link, not in the editor preview
Checkout does not work in the workspace preview. The preview bridge answers the request with a clear refusal: Not available in the editor preview — save the project and open the app via its ?app= link. This is deliberate rather than broken; the preview runs in a sandboxed frame that must not be able to trigger live payment sessions.
So: save the project, open it through its own link — the ?app= fallback, a PWA subdomain or a custom domain — and buy something with a test card there. When the session is created, the browser is sent to Stripe's hosted page. After payment the customer returns to northerngo.com/?app=<projectId>&payment=success, or &payment=cancelled if they backed out.
What the session actually is
Precision here saves you from promising your customers something the integration does not do.
- Payment methods: card and Klarna. Klarna also has to be enabled in your own Stripe account and is only offered in the countries and currencies Stripe supports it for.
- Currency: Swedish kronor. The SDK method does not pass a currency, so the server default applies.
- Mode: a one-time payment. The session is created in payment mode, which means there is no recurring billing, no subscription object, no trial period and no automatic renewal. If you are selling a monthly plan, this integration will happily charge one month and then never charge again.
- Return URLs: the defaults above, unless you call the endpoint directly and set your own.
That last point is the escape hatch for the first three. The underlying route accepts currency, successUrl and cancelUrl, and the SDK method simply does not forward them:
const res = await fetch(
'https://northerngo-backend.onrender.com/api/app-db/' + window.NG_PROJECT_ID + '/stripe/checkout',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
items: [{ name: 'Annual licence', price: 149, quantity: 1 }],
currency: 'eur',
successUrl: 'https://your-app.northerngo.com/?paid=1',
cancelUrl: 'https://your-app.northerngo.com/?cancelled=1'
})
}
);
const json = await res.json();
if (json.success) window.location.href = json.url;
Limitations you have to design around
Amounts are sent from the browser. The checkout route is public on purpose — your paying customers are not logged in to NorthernGo — and it builds the Stripe line items from the name and price in the request. Anyone who can open developer tools can therefore ask for a session at a price you did not set. Treat the return to ?payment=success as a hint, not as proof: check the actual amount in your Stripe Dashboard before you ship goods or unlock anything valuable, and prefer selling things where a manual or after-the-fact check is realistic.
There is no webhook fulfilment. Nothing in the platform listens for checkout.session.completed and writes the result back into your app's data. The redirect is all you get, and a customer who pays and then closes the tab before the redirect completes will not be recorded by your app at all. Stripe has the truth; your app has an intention.
No subscriptions. See above. Recurring revenue needs Stripe's own subscription mode, which this route does not create.
Downgrading turns payments off. The plan check runs again on every checkout, against the owner's account. Drop from Pro to Premium and live customers get Payments are disabled because the app owner does not have the Pro plan. Your saved key is untouched and comes back the moment the plan does, but the shop is closed in the meantime.
Exported builds have no payments object. The ZIP export ships the app with the inline SDK, which covers database, authentication and AI but does not define window.NorthernGoPayments. In an exported or Capacitor build, use the direct fetch above.
You own the compliance work. Terms of sale, refund policy, receipts, VAT and consumer rights are yours, not the platform's. If you are selling to consumers in the EU, read the GDPR and EU compliance notes alongside this page — an app that takes payments and has login also needs its account deletion path working.
Troubleshooting
"The app owner has not configured their Stripe key yet." No key is stored for the project. Save it again under More → Stripe (Klarna) and confirm that the card shows Payments active afterwards.
"Payments are disabled because the app owner does not have the Pro plan." The owning account is not on Pro. This is checked at payment time, not just at setup.
"Stripe Checkout requires the Pro plan." Same cause, raised while saving the key rather than while paying.
The button does nothing and the console is empty. Almost always window.NorthernGoPayments.checkout() was never called — the AI built a form instead. Search the generated code for NorthernGoPayments; if it is not there, ask again with the exact call spelled out.
It fails only in the editor. Expected. Open the app through its own link instead.
Stripe returns an error mentioning the payment method. Klarna is requested for every session. If it is not activated in your Stripe account, or your currency and country are not supported for it, Stripe rejects the session — activate Klarna in the dashboard or contact Stripe about availability.
The amount is a hundred times too big or too small. price is in kronor, not öre. 1490 is 1490 kr.
Frequently asked questions
Can I take real payments in an app I built with AI?
Yes, through your own Stripe account on the Pro plan. You save your Stripe secret key on the project, the app calls the injected checkout method with its line items, and the customer pays on Stripe’s hosted page with card or Klarna. The money goes to your Stripe balance and payouts follow your own Stripe settings.
Is it safe to paste my Stripe secret key into NorthernGo?
The key is encrypted with AES-256-CBC using a key derived from a server secret, with a unique initialisation vector per value, and stored in a private system collection that the public database routes cannot read. It is only decrypted server-side when a checkout session is created, and it is never sent to the browser. Start with a test key if you want to verify the flow first.
Can I sell monthly subscriptions this way?
No. The session is created as a one-time payment, so there is no recurring charge, no trial and no renewal. You can sell a month of access as a single purchase and handle renewal yourself, but genuine subscription billing needs Stripe’s own subscription mode, which this integration does not create.
Why does the checkout button work on the live link but not in the editor?
The editor preview blocks payment calls on purpose and answers that the action is unavailable there. The preview runs in a sandboxed frame that must not be able to start live payment sessions. Save the project and open the app through its own link, a PWA subdomain or a custom domain, and test with a Stripe test key.
Who is responsible if a customer wants a refund?
You are. The terms are explicit that if you use the Stripe integration to accept payments in your app, you are legally responsible towards your own customers for support, refunds and terms of sale. NorthernGo facilitates the connection to Stripe and never processes, sees or stores your customers’ card details. Refunds are issued from your own Stripe Dashboard.
Build it yourself
NorthernGo turns a plain-text description into a working web app with a database, login and a live URL. Local AI generation runs on your own GPU, is unlimited, and is free on every plan.