Skip to content

feat(payments): PayPal checkout created on click - #366

Merged
naor-gal merged 2 commits into
mainfrom
feat/paypal-one-click-checkout
Nov 4, 2026
Merged

naor-gal merged 2 commits into
mainfrom
feat/paypal-one-click-checkout

Conversation

@naor-gal

@naor-gal naor-gal commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Summary

PayPal checkout can now be created on click, so the buyer clicks once.

Today a page has to create the checkout before it can mount PayPal's button, because the button needs the checkout's PayPal details. So the buyer clicks the app's own button, waits 1-3 seconds for PayPal's button to appear, and clicks again.

mountCheckout() now also accepts a checkout to create on click:

const mount = await base44.payments.mountCheckout(element, {
  provider: "paypal",
  currency: "usd",
  intent: "capture", // or "subscription"
  createCheckout: async () => (await base44.functions.invoke("createCheckout", { productId })).data,
}, { onComplete, onError });

mount.setDisabled(!formIsValid);
  • PayPal's button renders as soon as the page loads, from the new paypal.button details in GET /payments/config.
  • createCheckout() runs inside the buyer's click. PayPal's session.start() takes the order as a promise, so its window opens right away and continues once the order exists. Page views create no orders.
  • The created checkout must match the button (PayPal, same intent, currency and merchant) or the click fails with onError. A rejection from createCheckout(), for example an empty required field, closes PayPal's window and reaches onError.
  • New CheckoutMount.setDisabled() greys out the button until a form is valid. Stripe ignores it.
  • Passing an existing checkout works exactly as before. Stripe is unchanged, since its embedded checkout needs its session to render.
  • Mounting on click rejects when the backend has no paypal.button details yet, which also covers backends that don't send them.

Testing

  • vitest: 434 passed, including four new on-click tests: the button shows before the order exists and the order is created on click, a mismatched checkout is refused, mounting waits until PayPal is ready, and a disabled button ignores clicks.
  • test:types: passes, with new checks for the on-click form, setDisabled(), and refusing it for Stripe.
  • eslint is clean.

🤖 Generated with Claude Code

… once

mountCheckout() also accepts { provider: 'paypal', currency, intent, createCheckout }. PayPal's button renders on page load from the payments config, and createCheckout() runs inside the buyer's click, so the app no longer needs its own button that creates the order first. The created checkout must match the button's provider, intent, currency and merchant. CheckoutMount gains setDisabled() to keep the button off until a form is valid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/sdk@0.8.58-beta.0-pr.366.dccfb00

Prefer not to change any import paths? Install using npm alias so your code still imports @base44/sdk:

npm i "@base44/sdk@npm:@base44-preview/sdk@0.8.58-beta.0-pr.366.dccfb00"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "@base44/sdk": "npm:@base44-preview/sdk@0.8.58-beta.0-pr.366.dccfb00"
  }
}

Preview published to npm registry — try new features instantly!

@github-actions github-actions Bot added the docs-draft PR has auto-drafted documentation suggestions label Nov 3, 2026
@naor-gal
naor-gal requested a review from guyofeck November 3, 2026 13:27
… charge twice

Once onApprove completes the checkout, clicks are ignored and setDisabled(false) no longer turns the button back on. With an on-click checkout, re-enabling it would have created and charged a second order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@guyofeck
guyofeck self-requested a review November 4, 2026 10:36
@naor-gal
naor-gal merged commit 8b1a4a2 into main Nov 4, 2026
9 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs-draft PR has auto-drafted documentation suggestions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants