Fluxapay is a payment gateway on the Stellar blockchain that enables merchants to accept crypto payments and get settled in their local fiat currency.
FluxaPay bridges the gap between crypto payments and real-world commerce—making stablecoin payments as easy to integrate as Stripe.
Automated testing and deployment pipeline using GitHub Actions:
- CI: Runs tests, linting, and builds on every push/PR to main
- CD: Auto-deploys to development and staging on merge to main; production requires manual approval
- All tests must pass before deployment
cargo audit --deny warningscargo deny check bans licenses advisories
PROPTEST_CASES=64 cargo test -p fluxapay proptests:: --all-features -- --test-threads=1
Despite growing crypto adoption, everyday commerce remains largely fiat-based.
A major pain point is that crypto-native customers are forced to offramp every time they want to pay a merchant. This introduces:
• Extra fees from offramping and FX conversions
• Payment delays and failed transactions
• Poor checkout experience for crypto users
• Lost sales for merchants
At the same time, merchants want to accept crypto without holding volatile assets, managing wallets, or dealing with on-chain complexity.
Fluxapay solves this by enabling USDC-in → fiat-out payments with a merchant-friendly experience.
1. Merchant Creates a Charge
Merchant creates a payment request via API or Payment Link.
2. Customer Pays in USDC (Stellar)
Customer pays from any supported Stellar wallet.
3. Instant Verification
FluxaPay verifies the payment on-chain and updates the payment status in real-time.
4. Settlement to Merchant (Local Fiat)
FluxaPay converts and settles the value to the merchant’s preferred local currency via bank transfer or supported payout channels.
• Merchant API for Seamless Integration
- Create payments/charges
- Fetch payment status
- Issue refunds (where supported)
- Manage customers & metadata • Webhooks
- payment.created , payment.pending , payment.confirmed , payment.failed , payment.settled
• Payment Links
- Shareable links for quick checkout (social commerce, WhatsApp, Instagram, etc.) • Invoices
- Generate invoices with payment links and track payment status
- Perfect for freelancers, agencies, and B2B billing
• Merchant Dashboard & Analytics • Reconciliation Reports • Built for Emerging Markets
• Merchant calls FluxaPay API to create a payment • Customer completes payment via hosted checkout or embedded flow • Fluxapay sends webhook when confirmed • Merchant fulfills the order
• Merchant generates a payment link (amount, currency, description) • Customer pays using Stellar USDC • Merchant is notified via dashboard + webhook/email (optional)
• Blockchain: Stellar
• Stablecoin Rail: USDC on Stellar
• Backend: Node.js (TBD)
• Smart Contracts: Stellar Soroban
• Database: PostgreSQL
• APIs: REST + Webhooks
• Frontend: Next.js (Merchant Dashboard)
• FX & Settlement: On-chain liquidity + payout partners
• E-commerce stores and marketplaces • SaaS and subscription businesses • Freelancers & agencies (invoices + payment links) • Cross-border payments for global customers • Merchants in emerging markets accepting stablecoin payments
Make stablecoin payments simple, practical, and accessible so merchants can sell globally while customers pay directly with USDC, without offramping friction.
• [ ] Core payment gateway (USDC on Stellar) • [ ] Merchant dashboard • [ ] API for payments + webhooks • [ ] Payment links • [ ] Invoicing • [ ] SDKs • [ ] Fiat settlement integrations • [ ] Refunds & dispute tooling (where applicable) • [ ] Multi-currency support & expanded stablecoins
Contributions are welcome!
Open an issue or submit a PR to help build Fluxapay.
-
Environment Variables: Copy
.env.exampleto.envand populate with your testnet credentials (do not commit.env):cp .env.example .env # Edit .env with your Stellar testnet keys and contract IDs -
Local Contract Invocation: See docs/local-invoke.md for step-by-step recipes to test
create_payment,register_merchant, and other contract functions on testnet. -
Running Tests:
cd fluxapay && make test
-
Code Quality: Format, lint, and audit before submitting:
cd fluxapay && make fmt && cargo clippy --all-targets --all-features && cargo audit
Please refer to our Security Policy for information on reporting vulnerabilities and our current audit status.
FluxaPay supports both full and partial refunds on confirmed USDC payments via the RefundManager contract.
- A merchant (or authorized requester) calls
create_refundwith thepayment_id, the refund amount, and a reason. - The refund is created in
Pendingstatus and added to the payment's refund list. - A settlement operator calls
process_refundto execute the on-chain USDC transfer back to the requester (minus a 1% processing fee). - The refund status transitions to
Completed.
Constraints:
- The sum of all non-rejected refunds for a payment cannot exceed the original payment amount (
RefundExceedsPaymenterror #16). - Multiple partial refunds are supported — each is tracked independently in the
PaymentRefundslist. - Only
Confirmedpayments can be refunded. - Rejected refunds do not count toward the total, allowing replacement refunds.
stellar contract invoke \
--id <REFUND_MANAGER_CONTRACT_ID> \
--source <REQUESTER_SECRET_KEY> \
--network testnet \
-- create_refund \
--payment_id "payment_abc123" \
--refund_amount 500000000 \
--reason "Customer requested return" \
--requester <REQUESTER_ADDRESS>stellar contract invoke \
--id <REFUND_MANAGER_CONTRACT_ID> \
--source <OPERATOR_SECRET_KEY> \
--network testnet \
-- process_refund \
--operator <OPERATOR_ADDRESS> \
--refund_id "refund_1"// Register the payment first (done automatically when a payment is confirmed)
client.register_payment(&payment_id, &merchant_id, &1_000_000_000i128, &usdc_symbol);
// Issue three partial refunds totalling the full payment amount
let r1 = client.create_refund(&payment_id, &300_000_000i128, &reason, &requester);
let r2 = client.create_refund(&payment_id, &400_000_000i128, &reason, &requester);
let r3 = client.create_refund(&payment_id, &300_000_000i128, &reason, &requester);
// Process each refund (operator role required)
client.process_refund(&operator, &r1);
client.process_refund(&operator, &r2);
client.process_refund(&operator, &r3);# Get a single refund by ID
stellar contract invoke --id <CONTRACT_ID> --network testnet \
-- get_refund --refund_id "refund_1"
# Get all refunds for a payment
stellar contract invoke --id <CONTRACT_ID> --network testnet \
-- get_payment_refunds --payment_id "payment_abc123"FluxaPay emits the following on-chain events for refund lifecycle tracking:
| Event | Trigger |
|---|---|
REFUND/CREATED |
A new refund request is submitted |
REFUND/COMPLETED |
Refund is processed and USDC transferred |
REFUND/REJECTED |
Operator rejects the refund request |
REFUND/CANCELLED |
Requester or admin cancels a pending refund |