PayPal Payments

Accept PayPal payments alongside Stripe with no extra package β€” uses the PayPal Orders REST API v2 directly.

Last updated : April 19, 2026

Overview

When a client clicks "PayPal" on an invoice, BilloraX creates a PayPal order and redirects them to PayPal for approval.

After the client pays, PayPal redirects to /api/paypal/capture which captures the order, marks the invoice PAID, records the payment, and advances the service renewal date.

πŸ’‘
Unlike Stripe, PayPal uses a redirect-and-capture flow rather than webhooks. The capture endpoint is the authoritative payment step.

Setup

Create a PayPal application at developer.paypal.com and add the credentials to .env:

  • Use PAYPAL_ENV="sandbox" during development
  • Switch to PAYPAL_ENV="live" in production
  • In your PayPal app settings, add /api/paypal/capture as a return URL
PAYPAL_CLIENT_ID="your-client-id"
PAYPAL_CLIENT_SECRET="your-client-secret"
PAYPAL_ENV="sandbox"

Flow

  1. Client clicks "PayPal" on an unpaid invoice
  2. Server action calls the PayPal Orders API to create an order
  3. Client is redirected to the PayPal approval page
  4. After approval, PayPal redirects to /api/paypal/capture?token={orderId}&invoice={invoiceId}
  5. The capture route calls the PayPal Capture API, marks the invoice PAID, and redirects to the success page

Error handling

If the capture fails (e.g. PayPal error or network issue), the client is redirected back to the invoice page with ?paypal_error=1.

Idempotency is handled: if the invoice is already PAID when the capture route runs, it skips the update and redirects to the success page.