Payments & Monetization β
TuneCamp supports a hybrid payment system combining traditional Fiat (via Stripe) and Web3 (Base Network) to provide a seamless monetization experience for artists.
1. Hybrid Payment Flows β
Stripe Checkout (Fiat) β
- Purpose: Allows users to buy tracks, albums, or store assets using credit/debit cards.
- Route:
POST /api/payments/stripe/create-session - Mechanism:
- Frontend requests a session for an
itemIdandtype(track/album/asset). - Backend calculates the price (converting ETH to USD if necessary via
price.ts). - Backend resolves the item's artist. For assets this is the asset's
artist_idif it was self-published by an artist; admin-created assets (noartist_id) have no resolvable artist. If the artist has a connected Stripe account (artists.stripe_account_id), the session is created as a Stripe Connect direct charge on that account, with the instance fee taken as anapplication_fee_amount. Otherwise the session is created on the instance's own Stripe account (single-artist / self-host fallback, or admin-managed assets β the operator already keeps 100%). - A Stripe Checkout session is created and the URL is returned to the client.
- Upon successful payment, Stripe sends a webhook to
/api/payments/stripe/webhook. For direct charges this arrives as a connected-account event (enable "Listen to events on connected accounts" on the endpoint). - Backend generates an Unlock Code and stores it in the database.
- Frontend requests a session for an
Crypto Onramp (Stripe & MoonPay) β
- Purpose: Enables users to buy USDC directly on the Base network to use for Web3 purchases.
- Providers: TuneCamp supports both Stripe Onramp and MoonPay.
- Route:
GET /api/payments/onramp-config - Mechanism:
- The server checks which providers are configured via API keys.
- For Stripe, it creates a session via
POST /api/payments/onramp-session. - For MoonPay, it provides the API key to the frontend to initialize the MoonPay SDK or widget.
- The preferred provider can be toggled in the Admin Settings (
onramp_provider).
Web3 On-chain Verification β
- Purpose: Unlocks content based on direct blockchain transactions.
- Route:
POST /api/payments/verify - Supported Methods:
- Direct ETH: Sending ETH directly to the artist's wallet.
- Direct USDC: Sending USDC (ERC-20) to the artist's wallet.
- Checkout Contract: Calling the
purchaseWithETHorpurchaseWithUSDCmethods on theTuneCampCheckoutsmart contract.
- Mechanism: Backend fetches the transaction and receipt from the Base RPC, parses the transaction data (using
ethers.js), and verifies the recipient and amount. - Note: Store assets have no on-chain verify endpoint yet β the crypto tab is hidden for asset checkouts, which are Stripe-only.
2. Unlock Codes β
When a payment is verified (either via Stripe Webhook or On-chain Verify), the system generates a unique 10-character alphanumeric code.
- Storage:
database.createUnlockCode(code, releaseId, trackId) - Download: Users can download the track via
GET /api/payments/download/:trackId?code=XXXXX.
3. Revenue Splits & Fees β
TuneCamp implements a universal fee split mechanism that applies to all payment methods, ensuring the platform remains sustainable regardless of how the user pays.
- Platform Policy: By default, the platform takes a percentage of every sale (e.g., 15%).
- Web3 Payments (On-chain): The split is enforced directly by the
TuneCampCheckoutsmart contract. Funds are distributed instantly: the artist's share goes to their wallet, and the platform's share goes to theadminTreasuryAddress. - Stripe Payments (Fiat): The split is enforced by Stripe Connect, mirroring the on-chain contract:
- Multi-artist instances (artist has a connected account): the charge is a direct charge on the artist's Stripe account β funds land in the artist's balance directly, never in the instance's account. The instance's cut is collected automatically as
application_fee_amount, using the sameadminFeePercentagesetting as the on-chain split so fiat and crypto take an identical percentage. No manual payout or custody. - Single-artist / self-hosted instances (no connected account): the charge stays on the instance's own Stripe account. The operator is the artist, so they already keep 100% (minus Stripe's processing fee) β Connect would only add onboarding friction.
- Cross-border guard: Stripe rejects application fees for direct charges in a few countries/currencies (e.g.
MX,BR/mxn,brl). For connected accounts based there, the fee is skipped so checkout never hard-fails β the artist simply receives the full amount.
- Multi-artist instances (artist has a connected account): the charge is a direct charge on the artist's Stripe account β funds land in the artist's balance directly, never in the instance's account. The instance's cut is collected automatically as
- Direct Verification: Even for direct txHash verification, the backend checks if the appropriate "Label Fee" has been sent to the treasury before generating an unlock code.
3.1 What an artist actually keeps (honest cost breakdown) β
TuneCamp's pitch is "no platform middleman fees", not "100% of revenue". Here is where the money actually goes on a β¬10 sale:
| Cost | Who charges it | Typical amount | Notes |
|---|---|---|---|
| Instance fee | The TuneCamp instance you publish on | 0β15% | Default split is 85/15. If you self-host your own instance, this is 0% β you are the platform. Pro artists on third-party instances keep 100% of the split. |
| Card processing | Stripe | ~2.9% + β¬0.30 | Unavoidable for fiat payments anywhere. TuneCamp adds nothing on top. |
| Network gas | Base (Ethereum L2) | a few cents | Only for on-chain (ETH/USDC/NFT) purchases. Paid by the buyer. |
| Hosting | Your VPS provider | ~β¬5β15/month | Fixed cost, independent of sales volume. |
Example β β¬10 album sold via Stripe on your own self-hosted instance: β¬10 β β¬0.59 Stripe β β¬9.41 to you (~94%). The same sale on Bandcamp: 10% revenue share + ~5% payment processing β β¬8.50. The difference compounds with volume, but be honest with yourself about the fixed hosting cost: below roughly β¬10β20/month in sales, a hosted platform may net you more.
On-chain payments: near-zero fees, with caveats. A buyer who already holds USDC on Base pays only gas (cents), and you receive ~100% β the best case of any payment path, beating Stripe's ~94%. Two caveats keep it from being the default recommendation: (1) buyers without crypto who use the onramp (MoonPay/Stripe Onramp) pay ~1β4.5% conversion fees plus extra UX friction, often worse than a plain card checkout; (2) you receive USDC/ETH, so cashing out to EUR has its own exchange/withdrawal costs, and holding ETH carries price risk until you convert (USDC largely avoids this). The instance fee split (85/15 default) applies on-chain too β it is enforced by the TuneCampCheckout contract itself.
3.2 Stripe Connect onboarding (artist accounts) β
For multi-artist instances, each artist connects their own Stripe (Express) account so card payments can be routed to them directly. This is admin-managed (the same gate as artist publishing):
POST /api/admin/artists/:id/stripe-connect/onboardβ creates (or reuses) the artist's Express account, stores its id inartists.stripe_account_id, and returns a hosted Stripe onboarding link. The artist completes KYC on Stripe's side.GET /api/admin/artists/:id/stripe-connect/statusβ reportsconnected,chargesEnabled,payoutsEnabled,detailsSubmitted, andcountry.DELETE /api/admin/artists/:id/stripe-connectβ unlinks the account from the artist (does not delete it on Stripe); their checkouts revert to the instance's own account.
No new environment variables are required β onboarding reuses the instance's stripe_secret_key. Until an artist completes onboarding (chargesEnabled = false), their fiat checkouts use the single-artist fallback (instance account).
4. Configuration β
Required Environment Variables:
STRIPE_SECRET_KEY: Stripe API secret.STRIPE_WEBHOOK_SECRET: Secret for verifying webhook signatures.TUNECAMP_RPC_URL: RPC endpoint for Base Network (e.g., Alchemy or Base public RPC).TUNECAMP_OWNER_ADDRESS: Default address for platform fees.MOONPAY_API_KEY: API Key for MoonPay Onramp integration.
Stripe webhook β "Listen to events on connected accounts" β
When at least one artist has a connected Stripe account, checkout sessions are created as direct charges on that account. Stripe dispatches the resulting checkout.session.completed event as a connected-account event (event.account is set). Your webhook endpoint must have "Listen to events on connected accounts" enabled in the Stripe Dashboard (Developers β Webhooks β your endpoint β Edit); otherwise these events are silently dropped and no unlock codes are generated for payments made on connected accounts.
The same STRIPE_WEBHOOK_SECRET covers both platform and connected-account events β no second secret is needed.