Payments Module
Accept one-time payments and subscriptions through the app’s connected payment provider. Frontend access viabase44.payments; elevated operations via base44.asServiceRole.payments (backend only).
Contents
- Overview
- Providers
- Methods (
base44.payments) - Service Role Methods (
base44.asServiceRole.payments) - Error Handling
- Notes
- Type Definitions
Overview
The payments module provides:- Checkouts for one-time payments and subscriptions, on the provider’s hosted page (redirect) or embedded in the app
- Purchase lookup
- Refunds
- Subscription management: cancel, pause, resume
Checkouts are always created with the service role (
createCheckout) — only a backend function can create one. The result (or, for PayPal, an on-click spec) is then passed to base44.payments.mountCheckout() on the page, or the buyer is redirected to redirect_url.
Providers
Not every provider supports every operation:Methods (base44.payments)
Anonymous or user authentication.
preloadCheckout(provider)
Starts downloading Stripe.js or the PayPal JS SDK before a checkout is mounted. Call it when the checkout page or form opens, while the buyer is still filling it in.mountCheckout() loads the library itself if it wasn’t preloaded.
Never rejects — no need to await it or catch errors. If the library fails to load, mountCheckout() retries and rejects with the error. Requires a browser environment; skipped in the backend.
Returns:
Promise<void> — resolves once the library has loaded or failed to load.
mountCheckout(element, checkout, options?)
Renders an embedded checkout inside a page element.checkout is the result of base44.asServiceRole.payments.createCheckout() called with presentation: 'embedded' (create it in a backend function and return the result to the page — only the service role can create checkouts). For PayPal, you can instead pass a PayPalCheckoutOnClick spec so the button renders immediately and the checkout is created only when the buyer clicks (so visitors who don’t buy don’t leave unused checkouts behind).
Behavior by provider:
- PayPal: Renders a PayPal button. When the buyer approves, the SDK calls
completeCheckout()for you and thenonComplete. - Stripe: Mounts Stripe Embedded Checkout. After paying, the buyer returns to the checkout’s
success_path. Stripe allows one embedded checkout per page — mounting another destroys the previous one.
listPurchases() in a backend function).
Returns:
Promise<CheckoutMount> — resolves once the checkout renders. Has destroy() and setDisabled(disabled).
completeCheckout(checkoutId)
Completes a PayPal checkout after the buyer approves it.mountCheckout() calls this for you — call it directly only if you render your own PayPal button. Calling it again for the same checkout returns the same result. Only PayPal checkouts need completing; other providers reject with complete_not_supported.
Returns:
Promise<CompleteCheckoutResult> — { checkout_id, status: 'paid' | 'pending' }.
listPurchases(params?)
Lists the current user’s purchases (a purchase belongs to the user when it was made with the user’s email address). Rejects withforbidden for anonymous authentication.
PayPal can’t list purchases, so for PayPal apps pass checkout_id or subscription_id to look up that one purchase — without either, the call rejects with invalid_request.
To confirm a purchase in a backend function before granting access, or to look up any buyer’s purchases, use the service-role listPurchases() instead.
Returns:
Promise<ListPurchasesResult> — { items: Purchase[], next_cursor: string | null }.
Service Role Methods (base44.asServiceRole.payments)
Backend only. Call from backend functions using createClientFromRequest(req). Not every provider supports every operation — see Providers.
Refunds take a required idempotency_key, and checkouts take an optional one, so retrying doesn’t charge or refund twice. Repeating a subscription change returns the subscription’s current state.
createCheckout(params)
Creates a checkout — either a redirect checkout (buyer leaves the app for the provider’s hosted page) or an embedded checkout (renders inside the app), chosen withpresentation (defaults to 'redirect'). A checkout with a recurring item creates a subscription.
After creating: for a redirect checkout, send the buyer to redirect_url; for an embedded checkout, return the result to the page and pass it to base44.payments.mountCheckout().
Returns:
Promise<CreateCheckoutResult> — exactly one of redirect_url and embedded is set, depending on presentation.
Compute shipping fees in a backend function, never in the browser. If the fee depends on the address, collect the address in your app and pass it inshipping.address— PayPal then shows that address to the buyer locked. If the fee doesn’t depend on the address, pass onlyshipping.amountand let PayPal ask the buyer.
completeCheckout(checkoutId)
Same behavior as the frontend method, callable from a backend function — use it when you render your own PayPal button and itsonApprove handler sends the checkout ID to your backend.
Returns:
Promise<CompleteCheckoutResult>.
listPurchases(params?)
Unlikebase44.payments.listPurchases(), returns any buyer’s purchases and includes metadata. Same PayPal restriction: pass checkout_id or subscription_id for PayPal apps, or it rejects with invalid_request.
Returns:
Promise<ListPurchasesResult>.
refund(params)
Refunds all or part of a payment. Not supported for Base44 Payments. Retrying with the sameidempotency_key and amount returns the original refund instead of refunding twice — if the call rejects with refund_failed, the outcome is unknown, so retry with the same values.
Returns:
Promise<RefundResult>.
cancelSubscription(subscriptionId, options?)
Cancels a subscription, now or at the end of the current billing period. Not supported for Base44 Payments. PayPal supports canceling now only.
Returns:
Promise<SubscriptionResult>.
pauseSubscription(subscriptionId)
Pauses a subscription’s billing. Not supported for Base44 Payments.
Returns:
Promise<SubscriptionResult>.
resumeSubscription(subscriptionId)
Resumes a paused subscription’s billing. Not supported for Base44 Payments.
Returns:
Promise<SubscriptionResult>.
Error Handling
Payments methods reject with aBase44Error (error.status, error.code, error.message, error.originalError) whose code is a PaymentsErrorCode. Invalid arguments and mountCheckout() failures reject with a plain Error instead.
Notable codes:
The full
PaymentsErrorCode union also includes: forbidden, unauthenticated, not_found, conflict, payments_not_connected, invalid_request, invalid_items, amount_below_minimum, currency_mismatch, currency_required, invalid_metadata, idempotency_not_supported, idempotency_key_reused, multiple_subscription_items, recurring_option_not_supported, invalid_cursor, embedded_checkout_unavailable, checkout_not_found, checkout_not_approved, checkout_closed, provider_unavailable, payment_not_found, refund_rejected, refund_temporarily_unavailable, subscription_not_found, subscription_not_active.
Notes
- Checkouts can only be created with the service role — there is no frontend
createCheckout. Create it in a backend function and pass the result tomountCheckout(), or redirect the buyer toredirect_url. mountCheckout()andpreloadCheckout()require a browser environment (window/document) and are not usable in backend functions.Purchase.metadataandPurchase.shipping_addressare alwaysnullunless the call is made with the service role.Purchase.payment_idis the ID to pass torefund(). For a PayPal subscription it’s the latest charge, and it’s returned only with the service role.