Skip to main content
This page is part of an AI coding agent skill and is written for agents, not humans. For the human-readable Base44 docs, see the developer documentation.

Payments Module

Accept one-time payments and subscriptions through the app’s connected payment provider. Frontend access via base44.payments; elevated operations via base44.asServiceRole.payments (backend only).

Contents


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
Each app connects exactly one payment provider: Stripe, PayPal, or Base44 Payments (powered by Wix). Two authentication modes expose different method sets: 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 then onComplete.
  • 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.
Requires a browser environment; cannot be used in the backend. Rejects when: the checkout isn’t embedded, an on-click PayPal checkout is mounted before the app’s PayPal can take payments, the payments config can’t be fetched or has no valid script URL, the provider’s library fails to load, or PayPal isn’t available for the checkout’s currency. Security: The checkout’s callbacks run in the buyer’s browser and can be faked. Grant access to what the buyer paid for only after your backend confirms the purchase (e.g. with the service-role 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 with forbidden 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 with presentation (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 in shipping.address — PayPal then shows that address to the buyer locked. If the fee doesn’t depend on the address, pass only shipping.amount and 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 its onApprove handler sends the checkout ID to your backend. Returns: Promise<CompleteCheckoutResult>.

listPurchases(params?)

Unlike base44.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 same idempotency_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 a Base44Error (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 to mountCheckout(), or redirect the buyer to redirect_url.
  • mountCheckout() and preloadCheckout() require a browser environment (window/document) and are not usable in backend functions.
  • Purchase.metadata and Purchase.shipping_address are always null unless the call is made with the service role.
  • Purchase.payment_id is the ID to pass to refund(). For a PayPal subscription it’s the latest charge, and it’s returned only with the service role.

Type Definitions