Salta al contenuto

How to Connect Payora to a Custom PHP Website

Learn how to connect Payora to a custom PHP website with server-side order handling, redirects, and payment validation.

Payora12 min readEN · RU · UK · ES · DE
How to Connect Payora to a Custom PHP Website

If your site is a standalone PHP build, the job is straightforward: create a payment, send the customer out to Payora, then bring the result back into your own order system. No WooCommerce needed. No plugin maze either.

This guide focuses on how to connect Payora to a custom PHP website without turning your checkout into a science project. You will see the exact places where PHP should start the payment, where it should receive the return, and where your app should decide whether the order is paid, pending, or failed.

1. Confirm the integration pattern for a custom PHP site

Start with one decision: are you building a simple checkout link, a server-side payment request, or a full payment flow with order tracking? Those are not the same thing. A one-page donation site can get by with a payment link, while a store with 20 products usually needs server-side order creation before the customer leaves your site.

For a custom PHP website, the cleanest pattern is often: create the order locally, create the Payora payment from PHP, redirect the customer, then listen for the return and server confirmation. That gives you a record on your side before money moves. It also keeps your cart and invoice logic inside your app, where it belongs.

If your checkout is tiny, you may only need a redirect to a Payora-hosted payment page. If you need line items, customer notes, or order IDs, your PHP code should send that data before the redirect. Simple. Not simplistic.

A practical example helps. A digital agency selling a 3-step maintenance package can create the order in PHP, attach the client email, and send the customer to Payora with the invoice reference. A hobby project selling a single license key may only need the payment link and a return page. The difference is the amount of state you need to preserve, not the amount of code.

2. Map the exact pages, endpoints, and session flow

Before writing code, list the pages. You need at least three: a checkout page, a return page, and a server endpoint for payment confirmation. If you skip the mapping, you end up guessing which request changed the order. Guessing is expensive.

Use a normal PHP session for the browser flow, but do not trust the session alone. Session state can disappear if the customer switches devices, closes the tab, or comes back from Payora later. Keep the order ID in your database too, so your PHP code can find the transaction even if the browser session is gone.

A typical flow looks like this:

  • Checkout page collects product, email, and quantity.
  • PHP creates a local order with status pending.
  • PHP sends the customer to Payora.
  • Payora returns the browser to your return URL.
  • Your server checks the payment status before marking the order paid.

That flow keeps the browser return page and the server-side truth separate. Good. They should be separate. The browser can tell you what the customer saw; your server should decide what the order means.

One small habit saves hours later: store the Payora payment reference next to your order ID as soon as you create the payment. If you wait until after redirect, a network error or impatient refresh can leave you with an order and no Payora reference. Then you are playing detective in production.

3. Prepare a minimal PHP payment request layer

Keep payment code out of templates. A small PHP class or helper is enough. One method can build the payload, another can send the HTTP request, and a third can parse the response. That separation matters because payment logic changes more often than page markup.

For example, your helper can take an array with amount, currency, order_id, and return_url, then add your Payora credentials from environment variables. The checkout page should never know where the API token lives. It should only know which button was clicked.

Here is the shape of the code logic, not a full implementation:

  1. Read the order from your database.
  2. Build a Payora request array.
  3. Send the request with cURL or a similar HTTP client.
  4. Save the returned Payora payment reference.
  5. Redirect the customer to the Payora payment URL.

Keep that helper boring. Boring code is easier to test. Boring code breaks less often when you change a product price or add a second checkout form next month.

If you already have a payment abstraction in your app, use it. If not, create one file and name it clearly, such as PayoraClient.php. That file should contain credentials, API calls, and response parsing. Nothing else. Not HTML. Not CSS. Not a thank-you message.

4. Send the customer to Payora from your custom checkout

Once the local order exists, submit the Payora payment request and send the customer to the Payora payment page. The handoff should happen only after your server has saved the order, because the user may close the tab as soon as the redirect starts.

Pass the order details you actually need. That usually means order ID, amount, currency, and customer email. You may also send metadata such as product name or internal account ID, but do not dump every field from your database into the request just because it is available. Extra data can create confusion later when support staff compares records.

A custom checkout often uses a POST form with a “Pay now” button. That form submits to your PHP endpoint, the endpoint creates the Payora payment, then it responds with a redirect. The customer never sees the API response. They only see Payora.

One small caution: do not trust client-side totals. If your product page says $49 and your browser sends $39, your server must reject the mismatch. A payment request should be created from the server-side order total, not from the value hidden in the form. That rule matters every time.

If you want a broader picture of payment setup patterns, the crypto payment gateway for ecommerce guide gives useful context without repeating the PHP flow here.

5. Receive and validate the payment result in your own app

The browser return URL is useful, but it is not the final word. It can tell you the payment page was visited, and it can carry a status value, but your PHP app should still treat that result as provisional until the server confirms it. Pending is not paid.

Design the return page to handle three cases: success, pending, and failure. If Payora says success, show a thank-you page and tell the user the order is being confirmed. If the status is pending, say exactly that. If it failed, invite the customer to try again without losing the order record. Clear wording reduces support tickets.

There is a useful rule here: the return page should never create the paid order by itself. It should only display the current state and perhaps offer a link back to the order page. Your database update happens after verification, not after a browser redirect. That difference protects you from accidental double updates.

Keep the return endpoint simple enough to read in one glance. If it receives a Payora payment reference, look it up. If the reference is missing, log the request and stop. If the order is already paid, show a friendly message and avoid changing anything. That is how idempotent flows stay calm under repeated refreshes.

For teams that also want a checkout-side comparison, the article on how to accept crypto payments has useful billing notes, especially if you sell services with recurring invoices or manual approvals.

6. Confirm the transaction on the server before marking the order paid

This is the safer step. Your PHP app should query Payora from the server side and confirm the transaction status before setting the order to paid. Browser redirects can lie by omission; server checks do not care whether the customer closed the tab, refreshed twice, or used a second device.

Use the Payora payment reference saved earlier, then request the current transaction state. Compare the returned status against the status you need for fulfillment. If the transaction is settled or confirmed, update the order. If it is pending, keep the order pending. If it is failed or canceled, leave the order untouched.

One aside: this is the point where many custom PHP sites get sloppy. They trust the return page because it is faster to code. Faster, yes. Safer, no. A 5-second verification step beats a support email thread later, every time.

If Payora provides a signed callback or a server-to-server confirmation mechanism, use it together with the status lookup. That gives you two checks: one from the customer flow and one from the server flow. If your implementation needs a step-by-step signature check, see how to test a crypto payment for the kind of validation discipline that pays off before launch.

Only mark the order paid after the server agrees. Not after the customer says so. Not after the browser says so. Your database should reflect the payment state that Payora confirms, because that is the state your fulfillment and accounting teams will trust later.

7. Save the payment record and handle duplicate submissions

Store the Payora transaction reference, the local order ID, the amount, currency, and the final status in your database. Do this in a single write if you can. Later, when a customer emails you with “I paid twice,” you will want a clean record, not three half-finished updates.

Duplicate submissions happen for ordinary reasons. The customer clicks twice. The back button gets used. The browser retries the request. Your PHP code should detect that the order already has a Payora reference and refuse to create a second payment for the same order unless the first one failed or expired. That is the core of idempotency.

A simple rule works well: one local order, one active Payora transaction. If a second request arrives for the same order while the first one is pending, show the existing Payora checkout link instead of creating a new one. If the order is already paid, do nothing. Quietly. That silence is a feature.

Make your database columns specific. For example, keep payora_reference, payment_status, paid_at, and last_checked_at. These fields help support, accounting, and debugging. If you later need to reconcile a payment, those four fields can answer most questions without searching logs for an hour.

If you are building a client invoice flow rather than a store checkout, the crypto payment gateway for freelancers article may also help with the same record-keeping logic, especially where invoice numbers matter more than carts.

8. Test the full flow on a staging copy of the site

Before going live, clone the site to staging and test the whole chain: order creation, Payora redirect, return page, server verification, and duplicate-click handling. If you only test the redirect, you have tested one-third of the problem.

Run at least these checks:

  • Create a new order and confirm the Payora payment request is generated.
  • Refresh the return page 2 times and confirm the order does not change again.
  • Submit the checkout form twice and verify only 1 active transaction exists.
  • Force a pending or failed result and confirm the order stays unpaid.
  • Check that the stored Payora reference matches the database record.

Test with the exact PHP version and server setup you plan to use live. A flow that works on a local laptop can fail on a production server with a stricter SSL configuration or a different cURL setting. That is not rare. It happens.

One final practical test: open the order in an incognito window, complete the payment, then open the same return URL from a second browser. Your app should not issue a second payment update. If it does, fix that before launch. No exceptions.

For teams selling USDC checkout paths alongside other payment methods, the notes in how to accept USDC payments can help you compare customer expectations before you commit the PHP flow to production.

That is the last thing to check: the same order should survive one redirect, one refresh, and one server confirmation without drifting out of sync. If it does, your custom PHP checkout is ready for the first live payment.

Comments

Ready to get started?

Create an account and have your first invoice running in under an hour.

Cosa risponde questa pagina