Skip to main content

Payment forms

WordPress Payment Form Workflow: Submit, Pay, Confirm, Fulfill

Build a reliable WordPress payment form workflow with server-calculated amounts, pending submissions, verified webhooks, and one-time fulfillment.

A WordPress payment form must track more than whether the browser reached a thank-you page. The customer can close the tab, the redirect can fail, and some payment methods remain pending after checkout.

The reliable workflow saves a pending submission, creates the payment from server-trusted values, waits for the provider’s signed webhook, and fulfills the order exactly once.

The WordPress payment form state machine

WordPress payment form workflow from pending submission through verified payment to one-time fulfillment A return-page redirect is useful feedback, but the signed webhook is payment authority.

Use explicit states:

  • pending_payment: form accepted and payment created, but not confirmed;
  • paid: provider webhook verified a successful payment;
  • payment_failed: provider reported failure or cancellation;
  • refunded: a later provider event confirmed a refund.

Core Forms stores payment provider, payment ID, amount in minor units, currency, and status with the submission. Its payments overview documents provider setup and webhook handling.

Calculate the amount on the server

Do not trust an amount from a visible or hidden field. The browser can change it.

Send stable choices such as:

product_id=license_pro
quantity=2
coupon=LAUNCH20

Then the server should:

  1. load the product and current price;
  2. validate quantity and availability;
  3. validate the coupon and customer eligibility;
  4. calculate tax and final amount;
  5. create the provider checkout or order;
  6. store the exact currency and minor-unit amount.

The hidden fields guide explains why a browser-supplied price=49.00 cannot be payment authority.

Save before leaving for checkout

Store the form submission before redirecting to a hosted payment page. That gives the site a stable record to reconcile when the provider calls back.

Include only necessary provider metadata:

  • internal submission ID;
  • internal order or operation ID;
  • form ID;
  • customer reference when permitted.

Do not place the full form payload or sensitive answers in provider metadata.

Trust the signed webhook

The success URL can improve customer experience, but it cannot prove payment. A visitor can open it directly, and the provider may redirect before a delayed payment method settles.

On the webhook:

  1. read the raw request body;
  2. verify the provider signature;
  3. identify the event and payment;
  4. load the matching pending submission;
  5. compare expected currency and amount;
  6. transition the state;
  7. run fulfillment once;
  8. return a fast success response.

Stripe likewise recommends webhook-driven fulfillment because it is server-to-server and works even when the customer does not reach the landing page. See Stripe’s fulfillment guidance.

For custom endpoints, follow the webhook signature verification guide.

Make fulfillment idempotent

Payment webhooks can be repeated or delivered out of order. Fulfillment must recognize work already completed.

Examples:

  • issue a license only if no license reference is stored;
  • send the receipt only if receipt_sent_at is empty;
  • decrement stock through a conditional transaction;
  • create membership access by stable payment ID;
  • reject a second fulfillment for the same provider event.

Store the event ID and final result. The webhook retries guide provides the duplicate-control pattern.

Write honest customer states

On the return page, show the state you know:

  • Paid: “Payment received. Your receipt and access details are on their way.”
  • Pending: “We are confirming your payment. We will email you when it clears.”
  • Failed: “The payment was not completed. No fulfillment has been created. Try again or choose another method.”
  • Unknown: “We cannot confirm the payment yet. Reference CF-48219. Check your email before trying again.”

Do not encourage an immediate second payment while the first is still pending.

Reconcile and support the workflow

Operations need searchable references:

  • Core Forms submission ID;
  • provider payment or order ID;
  • amount and currency;
  • current payment state;
  • provider event IDs;
  • action and fulfillment logs;
  • refund reference;
  • customer email when authorized.

Run periodic reconciliation between pending submissions and the provider. Alert on paid-but-unfulfilled records, amount mismatches, repeated signature failures, and unusually old pending payments.

FAQ

Can a thank-you page confirm payment?

No. Use the payment provider’s signed server-to-server webhook as authority.

Should the form send the price to the server?

It can send a display value, but the server must calculate the trusted amount from product and pricing data.

When should the receipt email be sent?

After the verified webhook marks the payment paid, not merely after form submission.

Why are payment amounts stored in minor units?

Integer minor units avoid floating-point rounding errors and match common provider APIs.

What happens if the webhook arrives twice?

Record a stable event ID and make fulfillment idempotent so the second delivery produces no duplicate action.

Build the form. Stop reading.

Every note here came out of a real Core Forms setup. Use CFLAUNCH for 20% off either plan.