01Project overview
Payora is a crypto payment gateway that a business deploys on its own infrastructure and fully controls. Unlike conventional payment providers, Payora never sits between the buyer and the seller: funds go straight to the merchant's own addresses, and the gateway server holds no private keys and never controls the money. From this come the two defining properties spelled out in the product itself — self-hosted (it runs on the owner's infrastructure) and non-custodial (your keys, your funds).
The idea grew out of a simple observation: almost every online service that needs to accept crypto reinvents the same payment module. Some bolt on a third-party processor and pay fees both for transactions and for withdrawals; others write acceptance "by hand", with no webhooks, no amount reconciliation, and no proper handling of underpayments. Payora rolls this repeated work into one product: a single API, a ready payment screen (hosted checkout), and signed webhooks that tell the store a payment has happened.
We designed and built the product end to end — from infrastructure and architecture to the landing page, the merchant dashboard, and the documentation. Below we walk through the problem Payora solves, how it works inside, and the engineering decisions that made accepting crypto predictable and safe.
The context matters too. Payora was never meant to be a one-off payment widget but a shared payment layer for a whole set of projects: deploy it once, and you can accept crypto in any of your services by registering each as a separate merchant. This saves dozens of hours on every new product and eliminates the zoo of incompatible payment modules that usually spreads across sites over time. The more projects an owner runs, the higher the return on a single gateway: one place to update, one security model, one set of statuses across all of them.
02Context and the problem
Accepting a crypto payment is easy "technically" — the hard part is doing it reliably and repeatably. As we broke the task down, a whole set of pains surfaced that everyone accepting crypto on their own runs into:
- Custodial risk. Third-party processors hold the funds themselves: that means fees, limits, and the risk of a freeze or the service disappearing along with the money.
- Duplicated code. On every new site the payment module is rewritten from scratch — address generation, monitoring incoming transfers, amount reconciliation, invoice statuses.
- Unreliable notifications. The store must learn about a payment instantly and trust the source. Hand-rolled "pings" are easy to forge, and polling the blockchain by hand means load and delays.
- Matching a payment to an invoice. If everyone pays to a single address, figuring out who paid for what becomes a headache.
- Underpayments and overpayments. Rates float, users round the amount, the network takes a fee — you need logic for partial payments and acceptable deviation.
The brief was this: build a gateway that takes all of this routine off the store developer's plate, while not taking away control over the money. A merchant should be able to start accepting crypto in an evening, not a sprint, and still be sure the funds arrive directly to them.
A separate layer of the task is trust on the buyer's side. The payment screen must look reassuring enough that a person isn't afraid to send funds: a clear amount, a visible address, a QR code, and a timer counting down to invoice expiry. Any sloppiness here directly hurts payment completion, so we treated checkout not as a "technical screen" but as a full part of the sales funnel.
Finally, there was the infrastructure layer. The service handles money, which means it must live in a predictable, isolated environment with clear access controls, valid certificates, and perimeter protection. In fintech, any detail left "for later" turns into an incident, so we baked the environment requirements in from the very start rather than retrofitting them under load.
03Project goals
From the brief grew concrete product and engineering goals that we kept in mind at every stage:
- Simple integration. Connecting a site is one request to create an invoice and one webhook handler. Not a thousand-line SDK, but plain, readable REST.
- Non-custodial by default. Private keys never leave the owner's side. The gateway server runs read-only where the acceptance of funds is concerned.
- A ready payment screen. So the merchant doesn't have to design a payment UI — Payora serves a hosted checkout with the invoice, address, QR, and timer.
- Trusted notifications. Every webhook is signed; the store verifies the signature and can't be fooled by a fake "paid".
- Predictability. Clear invoice statuses, transparent logic for underpayments and expiry, idempotency.
- Self-hosting. Deployment on your own server with separate subdomains for the API, payments, and admin.
These goals were deliberately framed as constraints rather than wishes. Each of them ruled out unsuitable architectural options at the design stage. For example, the non-custodial requirement immediately removed from consideration any scheme where the server holds keys; the simple-integration requirement rejected heavy SDKs in favour of transparent HTTP; and the predictability requirement dictated a strict status model instead of "magic" behaviour. The result is a narrow, focused product — it does one thing, but does it reliably.
04What we built
Payora packages crypto acceptance into three clear building blocks that cover the entire payment lifecycle:
One API
Create an invoice, fetch its status, and obtain payment details through one predictable REST interface.
Hosted checkout
A ready payment page with the invoice, address, QR code, amount, and timer — no markup on the store's side.
Signed webhooks
Server-to-server notifications about invoice status changes, cryptographically signed and verified by the store.
Non-custodial core
Funds go straight to the merchant's addresses; the gateway only watches for incoming transfers and reports them.
On top of this core sits a landing page with clear positioning, a merchant dashboard for creating projects and viewing invoices, and documentation a developer can integrate against without any calls. All of it is deployed as a single product on dedicated infrastructure.
Crucially, these three blocks aren't disjointed — they form a closed loop: the API creates an invoice, the checkout shows it to the buyer, the webhook returns the result to the store. Each element knows exactly as much as it needs to and doesn't intrude into anyone else's area of responsibility. This cohesion is what separates a gateway from a pile of scripts: the integrator doesn't have to glue pieces together; they work with a finished flow of "invoice → payment → notification".
The product in one line: "One API, a ready checkout, and signed webhooks. Self-hosted and non-custodial: your keys, your funds. Stop rewriting the payment module on every site."
05Solution architecture
Payora is split across several subdomains — that way roles and loads are physically separated, and access is easier to lock down:
- payora.money — the landing page: positioning, developer documentation, entry points into the dashboard.
- api.payora.money — the programmatic interface: where stores call to create invoices and check their status.
- pay.payora.money — the hosted checkout: the payment page the buyer sees.
- admin.payora.money — the admin panel and merchant dashboard: projects, keys, invoice history, webhook settings.
This split is not cosmetic. It lets us give the payment screen and the API different caching and security policies, isolate the admin area, and scale or extract parts independently when needed. Under the hood is a server stack on PHP 8.3, deployed in a panel-managed environment, behind Cloudflare (DNS, TLS, perimeter protection).
Logically the system consists of four blocks: request intake (the API and validation), invoice accounting (state, statuses, amounts, and deadlines), blockchain watching (detecting transfers to invoice addresses), and notification (building and sending signed webhooks). Each block owns its slice of the payment lifecycle and talks to the others across clear boundaries.
The per-subdomain split also brings an operational advantage: the publicly available landing and checkout live separately from the admin area, whose access can be further restricted. If any block becomes a bottleneck in the future — say, blockchain watching as the number of invoices grows — it can be reinforced or extracted without touching the rest. The architecture was designed for extension from the start, not just for a one-time launch.
06How a payment flows
From the integrator's point of view the whole flow fits into a few steps, and most of them happen without the store's involvement:
- 1. Invoice creation. The store calls the API: amount, currency, order id, webhook address. In response — an invoice with unique details and a link to the hosted checkout.
- 2. Payment. The buyer lands on Payora's payment screen: they see the amount, address, QR code, and timer. They pay from any wallet.
- 3. Transfer detection. The gateway watches the invoice address and registers the incoming transfer, comparing the amount with the expected one and allowing for acceptable deviation.
- 4. Confirmation. After the required number of confirmations the invoice moves to the "paid" status.
- 5. Signed webhook. Payora sends the store a server-side notification with the status and a signature; the store verifies the signature and performs its action — releases the goods, tops up a balance, grants access.
A key detail is idempotency and trust. The store must never rely on a user redirect to a "thanks for paying" page: the single source of truth about money is the signed webhook from Payora. So the actual crediting is always tied to a verified notification, not to an action in the browser.
Why does this matter so much? A redirect is easy to forge or simply never arrives: the user may close the tab right after sending funds, lose connectivity, or open a "thank you page" manually without paying anything. If the store grants goods on a redirect, it is exposed to abuse and losses. The webhook, by contrast, arrives server-to-server, is signed with a secret, and reflects the real state of the invoice — which is why it, and only it, serves as the "release" command. We make this principle a requirement in the documentation, not a recommendation.
07Key capabilities
Let's look at what makes Payora not just "crypto acceptance" but a production-grade payment gateway.
One REST API
The entire integration is built around a small set of methods: create an invoice, check its status, get the payment details. Responses are predictable, errors are machine-readable. The developer doesn't have to keep the quirks of a particular network in their head — they work with the notion of an "invoice", and Payora takes care of the network details.
Hosted checkout
The ready payment page lifts a whole layer of work off the store. On it the buyer sees the amount, the address, a QR code for their wallet, and a timer to invoice expiry. It's both more convenient for the user and safer: the gateway itself generates and displays the details, and the store plays no part in showing the address.
Signed webhooks
Every notification about an invoice status change is signed with the merchant's secret. The store verifies the signature on its side and only then trusts the contents. That way "paid" can't be forged even if the handler address is known.
Amount and deadline logic
Rates float, users round, networks take a fee — so the gateway can work with an acceptable amount deviation, record partial payments, and correctly close invoices on expiry. This takes the most unpleasant manual work off the store.
Statuses and the invoice lifecycle
An invoice in Payora goes through a clear set of states — from "created" and "awaiting payment" to "paid", "underpaid", or "expired". The store doesn't have to guess what's going on: the status is always unambiguous, and transitions between states are deterministic. This simplifies both automation on the store's side and the resolution of disputes in support — for any invoice you can see which step it's on and why it ended up there.
Idempotency and reliable delivery
The network is unreliable, handlers crash, responses get lost — so notifications are designed so that repeated delivery doesn't break the store's logic. The same payment fact can be safely processed several times without crediting anything twice. For money this is essential: better to receive a notification twice and dedupe it correctly than to lose the only one and leave the customer without their goods.
08Security and non-custodial design
Payora's core principle is not to become a custodian. The buyer's money goes to addresses controlled by the business itself, while the gateway server, on the acceptance side, runs in "watch-only" mode: it can compute addresses for invoices and track incoming transfers, but holds no private keys that could be used to spend those funds.
This shifts the threat model in a favourable direction. Even in the worst case of a server compromise, the attacker has no access to the money — there's nothing to "walk off" with. Webhook signing protects stores from forged notifications, the subdomain split narrows the attack surface, and the perimeter is closed off by Cloudflare. For the business this means something simple: control over funds stays with them, not with an external service.
On top of that we applied the principle of least privilege at the infrastructure level: a dedicated system account for the whole service, role separation across subdomains, and signing secrets that only the merchant knows. The fewer rights and the less data each component has, the smaller the blast radius of any single mistake or leak — and the calmer it is to operate a product that handles money.
The key idea: security here isn't a "feature on top" but the very shape of the architecture. A server that physically has no acceptance private keys cannot lose them — and that is stronger than any perimeter defence.
09TON and USDT: unique addresses
Payora accepts TON and USDT on the TON network — fast, low-fee assets convenient for online payments. But supporting a currency is only half the job. The second, subtler half is how to match a specific payment to a specific invoice.
We took the path of a unique address per invoice: for a new invoice a separate receiving address is derived deterministically. When a transfer arrives there, the gateway knows exactly which order it belongs to — without memos, payment comments, or manual matching that are so easy to lose. Address derivation is implemented so that the server needs no private keys to accept: it computes addresses and watches them, staying read-only.
Deterministic derivation is also about recoverability. Each invoice's address can be recomputed from the original parameters, which means the system doesn't depend on a fragile "address ↔ order" store: the link is restored from the derivation logic itself. For accepting USDT-on-TON and native TON this is especially convenient — both currencies live in the same network, which simplifies watching and lowers fees compared with "heavier" chains.
Why it matters: "shared address + comment" is a frequent source of lost payments. A unique address per invoice turns matching into a reliable operation and removes a whole class of support errors.

10Underpayments, overpayments, and deadlines
In crypto, "exactly the amount on the invoice" rarely arrives. The rate between the asset and the fiat price floats, wallets round, the network withholds a fee, and a user can be off by a fraction. So the gateway was designed from the start around the idea of acceptable deviation: a small difference between the expected and the actual amount counts as a correct payment, and the invoice closes cleanly.
Explicit underpayments and overpayments are trickier. If noticeably less arrives, the invoice gets the corresponding status and the store decides what to do: wait for a top-up, refund, or close partially. If more arrives, that fact is also recorded and surfaced to the store rather than silently swallowed. The logic is built so that no real transfer slips out of view and every one of them has a clear resolution.
A separate matter is deadlines. An invoice has a lifetime window during which it can be paid; on checkout this window is visible as a timer. Once it expires the invoice moves to the "expired" status, which matters for two reasons: first, the rate at payment time doesn't "drift" far from the one locked in; second, the store gets a clear signal that the order can be cancelled or recreated. All these transitions — underpayment, overpayment, expiry — are reflected in statuses and in the signed webhooks, so the integrator always has a machine-readable picture of what's happening.
Acceptable deviation
A small amount difference is treated as a correct payment — no false "underpayments".
Partial payment
An explicit underpayment gets its own status; the decision stays with the store.
Invoice expiry
The invoice lifetime is bounded by a timer; on expiry — the "expired" status and a signal to the store.
11Merchant dashboard and admin
For the product to stand on its own, an API alone isn't enough — you need an interface where the merchant manages their projects. In the admin area (admin.payora.money) the business creates projects, obtains keys and a secret for signing webhooks, configures the handler address and currencies, and sees the invoice history with statuses.
This covers everyday scenarios without involving the gateway developer: create a new project for a new site, reissue a key, check whether a particular payment arrived, investigate a disputed invoice. In essence, the dashboard is a "console" over everything the API does programmatically.
Each merchant project is isolated: it has its own keys, its own signing secret, its own set of currencies, and its own webhook address. Thanks to this, one owner can run several entirely different sites from a single dashboard without mixing up their payments or giving one project access to another's data. The invoice history with clear statuses turns the dashboard into a support tool: for any payment you can always see which step it's on, what amount was expected and arrived, and which webhook was sent.
12Integrations: battle-tested
Payora doesn't exist in a vacuum — it was built as a shared payment layer for a whole ecosystem of projects. One of the first real integrators is the freelance marketplace 24freelance: a user's balance top-up runs through Payora. The store creates an invoice, the user pays on the hosted checkout, and after confirmation Payora sends a signed webhook on which the balance is credited automatically.
This integration is a good real-world test of the architecture: it showed that a new project can be connected to the gateway quickly and that the chosen model (invoice → checkout → signed webhook → crediting) maps onto a real product without workarounds. Each connected service is registered as a separate merchant project with its own keys, which isolates them from one another.
The main value of the first integration is that it followed exactly the path baked into the product — no detours, no "temporary" hacks. A balance top-up is an excellent proving ground because reliability of crediting is critical here: an error would mean either lost user money or an unjustified balance credit. The fact that the whole flow ran on a binding to the signed webhook confirmed the key hypothesis: a gateway deployed once really does become a shared payment layer to which new projects connect as merchants, instead of being rewritten from scratch every time.
13Technology stack and infrastructure
For Payora we assembled a dedicated, isolated environment — with its own system user, subdomains, and policies. It's both cleaner from a security standpoint and easier to operate.
- Backend — PHP 8.3: the API, invoice accounting, building and sending webhooks, status logic.
- Blockchain layer — working with TON and USDT-on-TON: computing invoice addresses and watching for transfers in read-only mode.
- Infrastructure — a separate isolated account with api/pay/admin subdomains, behind Cloudflare (DNS, TLS, protection) and with valid Let's Encrypt certificates.
- Security — role separation across subdomains, signing secrets on the merchant's side, no acceptance private keys on the server.
The choice of PHP 8.3 here is pragmatic: a mature, fast platform on which it's convenient to host the API, the server-side rendering of checkout, and the admin area in one predictable environment. Cloudflare closes the perimeter and takes on TLS termination and basic protection, while Let's Encrypt provides valid certificates across all subdomains. The whole environment is meant to be self-hosted: the owner deploys it on their own infrastructure and keeps full control — which follows directly from the product's non-custodial nature.
14Design and UX
A fintech product sells trust, so we made Payora's interfaces calm and technical, free of visual noise. The landing page explains the value in a few seconds: what it is, who it's for, how it's different (self-hosted, non-custodial), and how to start. The documentation and entry points to the dashboard are a single click away.
Special attention went to the payment screen. This is the moment a user parts with money, and any ambiguity costs conversion. So on the hosted checkout everything is reduced to the essentials: the amount, the address, the QR code, the timer, and a clear status. The less clutter on this screen, the higher the rate of payments carried through to the end.
We treated checkout UX as part of the engineering problem, not as "styling". Every element on the payment screen solves a concrete trust problem: a visible address and QR remove the "where do I pay" fear, the timer dispels the "how long do I have" uncertainty, and a live invoice status answers the buyer's main question — "did my money arrive". Together this reduces the number of abandoned payments and support requests, which for a payment product is as important as technical reliability under the hood.
15How we worked
We ran the project in sequential stages, demonstrating a result at every step:
- Research. We mapped out crypto-acceptance scenarios, pain points, security requirements, and the "invoice → payment → notification" model.
- Architecture. We designed the subdomain split, the API format, the invoice status scheme, and the webhook signing mechanism.
- Core development. We built the API, invoice accounting, address derivation and transfer watching, the hosted checkout, and webhook delivery.
- Integration and run-in. We connected the first real project (the 24freelance balance top-up) and tested the whole flow in practice.
- Launch and infrastructure. We deployed the environment behind Cloudflare with subdomains and certificates, and produced the landing page and documentation.
This order isn't accidental: first we fixed the contract — the API format, the status scheme, and webhook signing — and only then built the implementation around it. This let us develop the core and the integration almost in parallel: while the server logic was being assembled, the contract was already stable enough to prepare the first integrator. The demos at each stage made it possible to spot mismatches early and fix them before they "set" in the code.
16The result
What we got is not a "crypto-acceptance script" but a self-contained payment gateway you can deploy yourself and connect to any number of projects.
- Crypto payment acceptance is connected in an evening — one request to create an invoice and one webhook handler.
- The business retains full control over funds: non-custodial and self-hosted.
- Signed webhooks and unique addresses remove entire classes of errors: forged notifications and lost payments.
- The architecture is proven by a real integration and is ready to scale to new projects.
But the main result isn't in individual numbers — it's in the shift of model. Before, every new site the owner built meant a new payment module from scratch; now it's simply one more merchant project in a shared gateway. Payment logic stopped being a one-off task and became a reusable asset that pays off all the more the more projects connect to it.
17Takeaways
Payora is an example of how engineering rigour turns a "trendy topic" into a working tool. The most valuable thing here isn't that the product "accepts crypto" but how it does it: without custodial risk, with trusted notifications, and with predictable invoice logic. It's exactly these unglamorous but critical details that separate a production-grade payment gateway from yet another hand-rolled acceptance.
For us this was a project at the intersection of fintech, blockchain, and infrastructure — precisely the kind of work where both product thinking and technical discipline matter. If you need payment acceptance, a blockchain integration, or a complex service with a clear API and a dashboard, we know how to carry that through to launch.
And one more, more methodological, takeaway. The best fintech solutions are almost always about what you can't see on the screen: about the threat model, about idempotency, about what counts as the single source of truth on money. These decisions are made once, at the start, and then protect the product from entire classes of problems for years. That's exactly how we approach the work — first the right boundaries and contracts, and only then everything else.
