ChargeForms
Payments & Integrations

Payments

Accept Stripe and PayPal payments with server-verified, tamper-proof pricing.

Connecting Stripe

Go to ChargeForms → Global Settings → Payment Settings and add your Stripe publishable and secret keys (test or live mode). Keys are stored via the same chargeforms_settings_fields-scoped update mechanism every other setting uses — a settings save never silently blanks a field it didn't render.

Connecting PayPal

Add your PayPal REST app's Client ID and Secret in the same Payment Settings screen, and choose Sandbox or Live mode independently of your Stripe configuration — the two gateways don't share credentials or mode.

PayPal's flow is structurally different from Stripe's, not just a drop-in swap: instead of confirming a charge client-side against a PaymentIntent, the buyer approves an Order through a PayPal-hosted button, and the server only actually captures the charge afterward — capture is the verification step. Before an entry is created, ChargeForms recomputes the total server-side, confirms it matches what was actually captured, confirms the order's custom_id round-trips to this form, and checks the transaction ID hasn't been used on a previous entry — the same anti-tampering guarantees as Stripe, adapted to PayPal's own order/capture shape rather than PaymentIntents.

Subscriptions

A Payment Method field can be set to recurring billing (monthly or yearly, with an optional free trial) to create a real Stripe subscription on submission — Stripe only today; PayPal subscriptions aren't implemented yet, though the underlying subscriptions table is gateway-agnostic by design specifically so that can be added later without a schema change. Subscription status is kept in sync via Stripe webhooks and mirrors Stripe's own status set exactly (trialing, active, past_due, canceled, unpaid, paused, etc.), plus one local addition — expired — synthesized when a subscription ends because every payment retry failed, distinguishing that from a deliberate cancellation, a distinction Stripe's own canceled status otherwise collapses away.

Payment field types

  • Payment Item — a fixed-price line item.
  • Custom Amount — visitor-entered amount, with a configurable minimum.
  • Payment Method — the card element (Stripe) or approval button (PayPal), depending on which gateway the form uses.
  • Payment Summary — a running total of every payment field on the form.

Why the amount can't be tampered with

The total charged is always recalculated server-side from the form's own field configuration at submission time — a fixed Payment Item's price is never read from the request body, and a Custom Amount below its configured minimum is floored to that minimum server-side regardless of what the client sent.

Before an entry is created, ChargeForms also:

  1. Retrieves the PaymentIntent directly from Stripe's own API and confirms its status is succeeded.
  2. Confirms the PaymentIntent's metadata references this form — an intent created for a different form is rejected.
  3. Checks that this specific PaymentIntent ID hasn't already been used on a previous entry, preventing the same successful payment from being replayed into a second free entry.

Any of these checks failing stops the submission — the entry is never created without a verified, non-replayed, correctly-priced payment behind it.