Compare commits
1 Commits
feat/renew
...
docs/payme
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f92f912be5 |
30
docs/architecture/adr-0001-payment-processor-selection.md
Normal file
30
docs/architecture/adr-0001-payment-processor-selection.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# ADR-0001: Use BTCPay Server as the primary payment processor
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
- The product requires crypto invoice checkout with manual subscription renewal.
|
||||||
|
- `merchant noKYC` is a hard requirement.
|
||||||
|
- `crypto-to-crypto noKYC` is desirable, but it does not replace the merchant-side requirement.
|
||||||
|
- Hosted processors can offer a usable API surface, but they also introduce AML/KYC escalation risk, payout holds, and custodial exposure.
|
||||||
|
- The product already targets operator-managed infrastructure, so an additional self-hosted payment component is operationally acceptable.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
Use `BTCPay Server` as the primary payment processor.
|
||||||
|
|
||||||
|
Keep the application payment adapter provider-agnostic, but treat hosted processors as non-default alternatives that require an explicit policy change.
|
||||||
|
|
||||||
|
## Rationale
|
||||||
|
- `BTCPay Server` is self-hosted and non-custodial, which fits the hard `merchant noKYC` requirement better than hosted processors.
|
||||||
|
- A self-custody path materially reduces the risk that a payment provider freezes merchant balances after receiving suspicious funds.
|
||||||
|
- The API and webhook model is sufficient for invoice creation, status reconciliation, and callback handling.
|
||||||
|
- The operational tradeoff is acceptable because the product already assumes server-managed infrastructure.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
- Deployment must account for a self-hosted BTCPay stack and its persistent data.
|
||||||
|
- Payment operations now include wallet, backup, and reconciliation responsibilities that a hosted processor would otherwise absorb.
|
||||||
|
- Later support for hosted processors remains possible through the shared payment adapter contract, but they are out of policy unless the `merchant noKYC` requirement changes.
|
||||||
|
|
||||||
|
## References
|
||||||
|
- [payment-provider-selection.md](/home/sirily/nroxy/docs/ops/payment-provider-selection.md)
|
||||||
@@ -16,6 +16,7 @@ Deploy on one VPS with Docker Compose.
|
|||||||
- `postgres`: primary database
|
- `postgres`: primary database
|
||||||
- `caddy`: TLS termination and reverse proxy
|
- `caddy`: TLS termination and reverse proxy
|
||||||
- optional `minio`: self-hosted object storage for single-server deployments
|
- optional `minio`: self-hosted object storage for single-server deployments
|
||||||
|
- `btcpay`: self-hosted payment stack for crypto invoice checkout
|
||||||
|
|
||||||
## Deployment notes
|
## Deployment notes
|
||||||
- Run one Compose project on a single server.
|
- Run one Compose project on a single server.
|
||||||
@@ -23,6 +24,8 @@ Deploy on one VPS with Docker Compose.
|
|||||||
- Keep secrets in server-side environment files or a secret manager.
|
- Keep secrets in server-side environment files or a secret manager.
|
||||||
- Back up PostgreSQL and object storage separately.
|
- Back up PostgreSQL and object storage separately.
|
||||||
- Prefer Telegram long polling to avoid an extra public webhook surface for the bot.
|
- Prefer Telegram long polling to avoid an extra public webhook surface for the bot.
|
||||||
|
- Keep BTCPay persistent data and wallet material isolated from app volumes and back them up separately.
|
||||||
|
- If BTCPay requires auxiliary services, treat them as part of the payment stack rather than as app-internal services.
|
||||||
|
|
||||||
## Upgrade strategy
|
## Upgrade strategy
|
||||||
- Build new images.
|
- Build new images.
|
||||||
@@ -42,7 +45,9 @@ Deploy on one VPS with Docker Compose.
|
|||||||
- provision DNS and TLS
|
- provision DNS and TLS
|
||||||
- provision PostgreSQL storage
|
- provision PostgreSQL storage
|
||||||
- provision S3-compatible storage or enable local MinIO
|
- provision S3-compatible storage or enable local MinIO
|
||||||
|
- provision BTCPay Server storage and wallet backup path
|
||||||
- create `.env`
|
- create `.env`
|
||||||
- deploy Compose stack
|
- deploy Compose stack
|
||||||
- run database migration job
|
- run database migration job
|
||||||
- verify web health, worker job loop, and bot polling
|
- verify web health, worker job loop, and bot polling
|
||||||
|
- verify BTCPay invoice creation, callback delivery, and payout/reconciliation procedures
|
||||||
|
|||||||
134
docs/ops/payment-provider-selection.md
Normal file
134
docs/ops/payment-provider-selection.md
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# Payment Provider Selection
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Working selection criteria for the product payment processor. Reviewed on 2026-03-10 against official provider materials.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Pick a crypto payment path that fits `nproxy`:
|
||||||
|
- monthly crypto subscription
|
||||||
|
- manual renewal only
|
||||||
|
- fixed-price invoice checkout
|
||||||
|
- single-VPS deployment
|
||||||
|
- safe callback or polling-based reconciliation
|
||||||
|
|
||||||
|
## Hard requirements
|
||||||
|
- Crypto invoice API for fixed-price checkout.
|
||||||
|
- Manual renewal flow. The provider must not force native recurring billing.
|
||||||
|
- Stable external invoice identifier for reconciliation.
|
||||||
|
- Clear invoice lifecycle that can be mapped to `pending`, `paid`, `expired`, and `canceled`.
|
||||||
|
- Webhook support or a reliable status polling API. Both is preferred.
|
||||||
|
- Idempotent event handling. Duplicate callbacks or repeated status checks must not cause repeated subscription activation.
|
||||||
|
- Metadata or reference fields so the app can correlate `userId`, local `invoiceId`, and `subscriptionId`.
|
||||||
|
- Test mode, sandbox, or another safe way to validate integration without real funds.
|
||||||
|
- Merchant documentation clear enough to implement and operate without reverse engineering.
|
||||||
|
- Fees and supported chains viable for small monthly subscription invoices.
|
||||||
|
|
||||||
|
## noKYC requirement
|
||||||
|
`noKYC` is a hard selection criterion for the product.
|
||||||
|
|
||||||
|
For this repository, `noKYC` means all of the following in the normal operating path:
|
||||||
|
- The merchant can start accepting payments without mandatory KYC or KYB review.
|
||||||
|
- The payer can complete checkout without mandatory identity verification.
|
||||||
|
- The provider does not require custody of merchant funds unless that is an explicit deployment choice.
|
||||||
|
|
||||||
|
Track `crypto-to-crypto noKYC` separately from merchant onboarding:
|
||||||
|
- `merchant noKYC` asks whether `nproxy` can start operating without provider-side KYC or KYB.
|
||||||
|
- `crypto-to-crypto noKYC` asks whether a payer can complete an on-chain crypto payment from a normal wallet without entering an identity-verification flow.
|
||||||
|
|
||||||
|
The first one is the hard gate. The second one is still valuable and should be recorded in the comparison.
|
||||||
|
|
||||||
|
Evaluation rule:
|
||||||
|
- `pass`: official materials support operating without mandatory KYC in the normal path.
|
||||||
|
- `borderline`: marketing or docs imply low-friction onboarding, but the provider reserves the right to require KYC, hold funds, or escalate compliance checks.
|
||||||
|
- `fail`: official docs explicitly require merchant verification, or the product is clearly compliance-gated.
|
||||||
|
|
||||||
|
## Comparison matrix
|
||||||
|
|
||||||
|
| Provider | Model | Merchant noKYC | Crypto-to-crypto noKYC | API / webhooks | Test mode | Product fit | Notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| BTCPay Server | Self-hosted, self-custody | pass | pass | pass | pass | strong | Best fit for strict `noKYC`. Higher ops cost because the merchant runs the payment stack. |
|
||||||
|
| NOWPayments | Hosted processor | borderline | borderline to pass | pass | unclear | medium | Closest hosted option. Normal crypto-to-crypto flow appears low-friction, but official support docs reserve the right to request verification and hold suspicious transactions. |
|
||||||
|
| Cryptomus | Hosted processor | fail | unclear | pass | unclear | weak | Official help center says merchants need to pass KYC to use the platform. Reviewed materials did not give a clean official `crypto-to-crypto noKYC` promise for payers. |
|
||||||
|
| Coinbase Commerce / Coinbase Business | Hosted processor | fail | unclear | pass | pass | weak | Strong API surface, but the reviewed official materials do not support a strict `noKYC` posture. |
|
||||||
|
|
||||||
|
## Provider notes
|
||||||
|
|
||||||
|
### BTCPay Server
|
||||||
|
- Official BTCPay materials describe it as self-hosted and non-custodial.
|
||||||
|
- Official integration copy explicitly positions it as avoiding complicated KYC and keeping merchants in control of funds.
|
||||||
|
- This is the cleanest fit if `noKYC` must be enforced as a hard requirement rather than a preference.
|
||||||
|
- Tradeoff: the team must operate the service, wallet integration, backups, and chain support.
|
||||||
|
|
||||||
|
### NOWPayments
|
||||||
|
- Official API materials cover invoice creation and payment-status callbacks.
|
||||||
|
- Official support materials say account verification is not required in general, but NOWPayments may still request KYC details and put transactions on hold in suspicious cases.
|
||||||
|
- For the payer side, direct crypto-to-crypto checkout looks closer to `noKYC` than card or custodial account flows, but the official materials reviewed still leave compliance-escalation risk.
|
||||||
|
- That means it does not cleanly satisfy a strict `noKYC` rule. It is only acceptable if the product can tolerate compliance escalation risk.
|
||||||
|
|
||||||
|
### Cryptomus
|
||||||
|
- Official merchant docs cover invoice APIs and callbacks.
|
||||||
|
- Official help materials state that a merchant must pass KYC verification to use the platform.
|
||||||
|
- That merchant-side requirement is enough to fail the current hard gate even if a payer-side crypto path is relatively low-friction.
|
||||||
|
- This makes it a direct mismatch for the current product requirement.
|
||||||
|
|
||||||
|
### Coinbase Commerce / Coinbase Business
|
||||||
|
- Official Coinbase Commerce docs cover charges, webhooks, and test integration paths.
|
||||||
|
- Official Coinbase legal materials state that identity verification is required for customers to use Coinbase services.
|
||||||
|
- The reviewed official materials did not give a clean promise that external-wallet crypto-to-crypto checkout remains `noKYC` end to end.
|
||||||
|
- This is operationally mature, but it is not compatible with a strict `noKYC` requirement.
|
||||||
|
|
||||||
|
## Recommendation
|
||||||
|
- If `noKYC` is truly hard, prefer `BTCPay Server`.
|
||||||
|
- If a hosted processor is still desired, treat `NOWPayments` as the only current shortlist candidate from this review, but mark it as `borderline`, not `pass`.
|
||||||
|
- If the team later relaxes the hard gate from `merchant noKYC` to only `crypto-to-crypto noKYC`, rerun the comparison because the shortlist may widen.
|
||||||
|
- Do not choose `Cryptomus` or `Coinbase` while `noKYC` remains a hard requirement.
|
||||||
|
|
||||||
|
## Merchant KYC / AML risk
|
||||||
|
This section answers the practical merchant-side risk question: can a payment path create a real loss or freeze scenario if a customer pays with suspicious or "dirty" crypto.
|
||||||
|
|
||||||
|
### Short answer
|
||||||
|
- With a hosted or custodial processor, yes, there is a real risk of payout holds, extra KYC/KYB review, delayed settlement, or account restrictions if the provider flags a payment as suspicious.
|
||||||
|
- With a self-hosted and non-custodial path such as `BTCPay Server`, the processor itself does not hold your funds, so it cannot directly freeze coins that have already landed in your wallet.
|
||||||
|
- Even with self-custody, the risk is not gone. It moves downstream to whatever exchange, custodian, OTC desk, or banking ramp you use later.
|
||||||
|
|
||||||
|
### Can you lose all the money?
|
||||||
|
- The official materials reviewed support a real hold and compliance-escalation risk for hosted processors, especially around suspicious transactions.
|
||||||
|
- They do not, by themselves, prove guaranteed confiscation of all funds.
|
||||||
|
- The practical risk is usually loss of access, payout freeze, account closure, or long investigation windows rather than an automatic irreversible seizure.
|
||||||
|
- If your operating balance sits inside a custodial processor or exchange account during that event, the business impact can still feel like "losing the money" for an operationally important period.
|
||||||
|
|
||||||
|
### Why this matters for provider choice
|
||||||
|
- `NOWPayments` explicitly says verification may be requested and suspicious transactions may be put on hold.
|
||||||
|
- `Coinbase` documents identity verification and account restrictions as part of its compliance posture.
|
||||||
|
- `BTCPay Server` is self-hosted and non-custodial, so the payment processor layer is structurally less exposed to merchant-balance freezes.
|
||||||
|
|
||||||
|
### Inference for this repository
|
||||||
|
This is an inference from the official sources above:
|
||||||
|
- If minimizing merchant-side AML/KYC freeze risk is a priority, self-custody is materially safer than a hosted custodial processor.
|
||||||
|
- Self-custody does not make tainted-funds risk disappear. It mainly removes one counterparty that could hold or block your balance before it reaches your own wallet.
|
||||||
|
- The remaining exposure shows up when funds are consolidated, swapped, or off-ramped through third parties.
|
||||||
|
|
||||||
|
### Operational mitigations
|
||||||
|
- Prefer a non-custodial payment path.
|
||||||
|
- Keep payment receipt wallets segregated from treasury and personal wallets.
|
||||||
|
- Avoid commingling funds from unrelated customers before reconciliation.
|
||||||
|
- Keep invoice-to-transaction mapping so suspicious deposits can be isolated quickly.
|
||||||
|
- Assume any later exchange or off-ramp may apply AML screening even if the incoming payment path does not.
|
||||||
|
|
||||||
|
## Implementation consequence
|
||||||
|
Before starting issue `#9` or a real provider integration, keep the payment adapter contract provider-agnostic:
|
||||||
|
- `createInvoice`
|
||||||
|
- `getInvoiceStatus`
|
||||||
|
- `verifyWebhook`
|
||||||
|
- `expireInvoice` or an explicit documented fallback when provider-side expiry is passive only
|
||||||
|
- correlation metadata round-trip
|
||||||
|
|
||||||
|
## Official sources used for this review
|
||||||
|
- BTCPay Server homepage: https://btcpayserver.org/
|
||||||
|
- BTCPay Server Greenfield API: https://docs.btcpayserver.org/API/Greenfield/v1/
|
||||||
|
- NOWPayments API docs: https://nowpayments.io/payment-integration
|
||||||
|
- NOWPayments support on verification: https://support.nowpayments.io/hc/en-us/articles/21395546303389-Verification
|
||||||
|
- Cryptomus merchant API docs: https://doc.cryptomus.com/
|
||||||
|
- Cryptomus KYC verification help: https://help.cryptomus.com/legal-and-security/kyc-verification
|
||||||
|
- Coinbase Commerce docs: https://docs.cdp.coinbase.com/commerce/docs/welcome
|
||||||
|
- Coinbase identity verification help: https://help.coinbase.com/en/coinbase/getting-started/verify-my-account/how-do-i-verify-my-identity-when-using-the-mobile-app
|
||||||
@@ -8,7 +8,7 @@ The service hides provider-key failures behind a routed key pool. A user request
|
|||||||
## Confirmed product decisions
|
## Confirmed product decisions
|
||||||
- One B2C website.
|
- One B2C website.
|
||||||
- One monthly subscription plan.
|
- One monthly subscription plan.
|
||||||
- Crypto checkout through a payment processor.
|
- Crypto checkout through self-hosted `BTCPay Server`.
|
||||||
- Manual renewal.
|
- Manual renewal.
|
||||||
- Text-to-image and image-to-image.
|
- Text-to-image and image-to-image.
|
||||||
- User-facing synchronous experience implemented with polling over background execution.
|
- User-facing synchronous experience implemented with polling over background execution.
|
||||||
@@ -93,6 +93,7 @@ Single VPS with Docker Compose, expected services:
|
|||||||
- `bot`
|
- `bot`
|
||||||
- `postgres`
|
- `postgres`
|
||||||
- `caddy` or `nginx`
|
- `caddy` or `nginx`
|
||||||
|
- `btcpay`
|
||||||
- optional `minio` when object storage is self-hosted
|
- optional `minio` when object storage is self-hosted
|
||||||
|
|
||||||
## Optional extensions
|
## Optional extensions
|
||||||
|
|||||||
Reference in New Issue
Block a user