{"id":199546,"date":"2025-10-02T15:44:31","date_gmt":"2025-10-02T13:44:31","guid":{"rendered":"https:\/\/fivemx.com\/?p=199546"},"modified":"2026-06-22T20:54:17","modified_gmt":"2026-06-22T18:54:17","slug":"monetizar-sem-conformidade-com-os-webhooks-do-tebex-stripe","status":"publish","type":"post","link":"https:\/\/fivemx.com\/pt\/monetize-without-tebex-stripe-webhooks-compliance\/","title":{"rendered":"Monetize Without Tebex: Self\u2011Hosted Store with Stripe\/W&amp;#&#8230;"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Read this before you start. If you run a FiveM\/RedM <strong>server<\/strong> and plan <a href=\"https:\/\/fivemx.com\/creating-subscription-tiers-that-players-actually-want\/\" data-type=\"post\" data-id=\"189278\">to sell in\u2011game perks<\/a>, <strong>you must use <a href=\"https:\/\/fivemx.com\/how-to-create-a-tebex-store\/\" data-type=\"post\" data-id=\"84361\">Tebex<\/a><\/strong>. Cfx.re\u2019s docs and PLA state that \u201cthe use of any other platform or payment provider is prohibited\u201d for server monetization. Self\u2011hosting Stripe is fine for <strong>off\u2011server<\/strong> sales (standalone scripts, MLOs, UI packs, services, courses). Don\u2019t attach those sales to in\u2011game perks on live servers.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">What you can monetize without Tebex<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Allowed (outside the server):<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Standalone scripts\/MLOs you license for self\u2011install.<\/li>\n\n\n\n<li>Texture packs, UI kits, sound packs.<\/li>\n\n\n\n<li>Consulting, custom dev work, installation services.<\/li>\n\n\n\n<li>Documentation, courses, templates.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Avoid (requires Tebex or breaks policy):<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In\u2011game currency, pay\u2011to\u2011win, loot boxes, NFTs.<\/li>\n\n\n\n<li>Priority queue, VIP roles, whitelist boosts tied to your live server.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Architecture at a glance<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Goal:<\/strong> a self\u2011hosted store that sells digital products (scripts\/MLOs) and delivers licenses automatically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Stack:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Frontend: Next.js (App Router), React.<\/li>\n\n\n\n<li>Payments: Stripe Checkout (simple) or Payment Element + Payment Intents (custom flow).<\/li>\n\n\n\n<li>Webhooks: Receive events, verify signatures, update orders, deliver files\/keys.<\/li>\n\n\n\n<li>Storage\/Delivery: S3\/R2 + signed URLs; or license server with rate\u2011limited downloads.<\/li>\n\n\n\n<li>Tax\/Invoices: Stripe Tax + Billing invoices for B2B.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Data flow:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create Product + Price in <a href=\"https:\/\/stripe.com\/\" target=\"_blank\" rel=\"noopener\">Stripe<\/a>.<\/li>\n\n\n\n<li>Start Checkout Session with metadata (productId, buyerId).<\/li>\n\n\n\n<li>On <code>checkout.session.completed<\/code> or <code>payment_intent.succeeded<\/code>, verify signature.<\/li>\n\n\n\n<li>Mark order paid; generate license; create signed download link; email the receipt and license.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Step\u2011by\u2011step setup<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1) Stripe account hygiene<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Complete onboarding and <strong>verify business<\/strong> (KYC).<\/li>\n\n\n\n<li>Set statement descriptor, support email, refund policy page URL.<\/li>\n\n\n\n<li>Enable <strong>Apple Pay \/ Google Pay<\/strong>; add bank account.<\/li>\n\n\n\n<li>Turn on <strong>Radar<\/strong> rules for basic fraud checks.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2) Products and pricing<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create one Stripe <strong>Product<\/strong> per script\/MLO.<\/li>\n\n\n\n<li>Use <strong>one\u2011time Prices<\/strong> in your buyer currency (EUR\/USD).<\/li>\n\n\n\n<li>Add metadata keys you will need later: <code>sku<\/code>, <code>product_slug<\/code>, <code>license_policy<\/code>.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3) Choose the payment flow<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/stripe.com\/\" target=\"_blank\" rel=\"noopener\">Stripe<\/a> Checkout<\/strong>: fastest and SCA\u2011ready. Handles wallets, 3DS, receipts. Recommended for most stores.<\/li>\n\n\n\n<li><strong>Payment Element + Payment Intents<\/strong>: more control; use if you need custom UI or extra methods.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4) Secure webhooks<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a <code>POST \/api\/stripe\/webhook<\/code> endpoint.<\/li>\n\n\n\n<li>Read the <strong>raw body<\/strong>; don\u2019t parse JSON before verification.<\/li>\n\n\n\n<li>Verify with the <strong>endpoint secret<\/strong>; reject if signature fails.<\/li>\n\n\n\n<li>Use <strong>idempotency<\/strong> for outbound tasks you trigger from webhooks (e.g., license creation) so retries don\u2019t duplicate orders.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5) Order + license fulfillment<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>After verified success:\n<ol class=\"wp-block-list\">\n<li>Create <code>orders<\/code> row with <code>status='paid'<\/code>.<\/li>\n\n\n\n<li>Generate a license key (UUID v4) or buyer\u2011bound unlock token.<\/li>\n\n\n\n<li>Store an <strong>immutable build<\/strong> of the zip (hash it).<\/li>\n\n\n\n<li>Issue a <strong>time\u2011limited signed URL<\/strong> (e.g., 24 hours, 3 downloads).<\/li>\n\n\n\n<li>Email the buyer: invoice link, license, download button.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li>Add a <strong>customer portal<\/strong> page with order history and re\u2011downloads.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">6) Taxes, invoices, and receipts<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Turn on <strong>Stripe Tax<\/strong>; mark items as <strong>digital goods<\/strong>.<\/li>\n\n\n\n<li>Collect buyer location (IP + billing address) and tax numbers (e.g., EU VAT ID).<\/li>\n\n\n\n<li>For EU B2C, charge destination VAT; for valid EU B2B VAT IDs, zero\u2011rate and record the ID.<\/li>\n\n\n\n<li>Store invoice PDFs with the order record.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">7) Compliance and policies<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Terms of Sale (license scope, no resale, anti\u2011cheat clause, DMCA takedown).<\/li>\n\n\n\n<li>Refunds: EU distance selling rules apply, but digital downloads lose the 14\u2011day right <strong>if<\/strong> the buyer expressly consents and acknowledges this before download. Show a checkbox and log consent.<\/li>\n\n\n\n<li>Privacy: keep a GDPR page; log webhook payloads without storing full card data.<\/li>\n\n\n\n<li>Security: rotate webhook secrets; least\u2011privilege API keys; encrypt license table at rest.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Minimal implementation (Next.js + Stripe Checkout)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Server action (create session):<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/api\/checkout\/route.ts\nimport Stripe from 'stripe';\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2024-06-20' });\n\nexport async function POST(req: Request) {\n  const { sku, successUrl, cancelUrl } = await req.json();\n  const priceId = await mapSkuToPriceId(sku);\n\n  const session = await stripe.checkout.sessions.create({\n    mode: 'payment',\n    line_items: [{ price: priceId, quantity: 1 }],\n    metadata: { sku },\n    success_url: successUrl,\n    cancel_url: cancelUrl,\n  });\n  return Response.json({ url: session.url });\n}\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Webhook route:<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ app\/api\/stripe\/webhook\/route.ts\nimport Stripe from 'stripe';\nimport { headers } from 'next\/headers';\n\nexport const config = { api: { bodyParser: false } } as any; \/\/ keep raw body\n\nfunction buffer(body: ReadableStream&lt;Uint8Array&gt;) {\n  const reader = body.getReader();\n  const chunks: Uint8Array[] = [];\n  return reader.read().then(function process({ done, value }): any {\n    if (done) return Buffer.concat(chunks);\n    chunks.push(Buffer.from(value));\n    return reader.read().then(process);\n  });\n}\n\nexport async function POST(req: Request) {\n  const sig = headers().get('stripe-signature')!;\n  const buf = await buffer(req.body!);\n  let event: Stripe.Event;\n  try {\n    event = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2024-06-20' })\n      .webhooks.constructEvent(buf, sig, process.env.STRIPE_WEBHOOK_SECRET!);\n  } catch {\n    return new Response('Bad signature', { status: 400 });\n  }\n\n  if (event.type === 'checkout.session.completed') {\n    const session = event.data.object as Stripe.Checkout.Session;\n    await fulfill(session); \/\/ create order, license, email\n  }\n  return new Response('OK', { status: 200 });\n}\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Idempotency tip:<\/strong> when your webhook triggers external work (e.g., emailing, license creation), wrap those calls with your own <code>Idempotency-Key<\/code> to prevent duplicates.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">License and file delivery<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Bind each license to buyer email + product SKU.<\/li>\n\n\n\n<li>Sign download URLs; limit by time + attempts; log IPs for abuse control.<\/li>\n\n\n\n<li>Include a small <strong>license validator<\/strong> snippet in your resource loader to check the key against your API (rate\u2011limited).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Risk and fraud controls<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Enable 3DS\/SCA via Checkout or Payment Intents.<\/li>\n\n\n\n<li>Block disposable emails and mismatched billing country for high\u2011risk orders.<\/li>\n\n\n\n<li>Keep dispute evidence templates: product description, license logs, download logs, consent to digital\u2011content waiver.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Don\u2019t break Cfx.re rules<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use Tebex for any perk that touches your running server (priority queue, VIP kits, cars, skins).<\/li>\n\n\n\n<li>Keep Stripe for off\u2011server digital products and services only.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Internal links (FiveMX)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Monetization policy overview \u2192 <a href=\"https:\/\/fivemx.com\/terms-conditions\">https:\/\/fivemx.com\/terms-conditions<\/a><\/li>\n\n\n\n<li>Refund &amp; Returns for digital goods \u2192 <a href=\"https:\/\/fivemx.com\/guarantee\">https:\/\/fivemx.com\/guarantee<\/a><\/li>\n\n\n\n<li>Script licensing template \u2192 <a href=\"https:\/\/fivemx.com\/terms-conditions\">https:\/\/fivemx.com\/terms-conditions<\/a><\/li>\n\n\n\n<li>DMCA takedown \u2192 <a href=\"https:\/\/fivemx.com\/dmca-request\">https:\/\/fivemx.com\/dmca-request<\/a><\/li>\n\n\n\n<li>Performance &amp; anti\u2011cheat notes \u2192 <a href=\"https:\/\/fivemx.com\/performance\">https:\/\/fivemx.com\/performance<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">External references<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Cfx.re PLA + Tebex\u2011only monetization and docs.<\/li>\n\n\n\n<li>Stripe webhooks and signature verification.<\/li>\n\n\n\n<li>Stripe idempotency keys and SCA.<\/li>\n\n\n\n<li>EU consumer law: digital content right of withdrawal exceptions.<\/li>\n\n\n\n<li>Stripe Tax: digital goods and OSS.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Ready\u2011to\u2011ship checklist<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Stripe account verified; business details complete.<\/li>\n\n\n\n<li>Products + Prices created; metadata set.<\/li>\n\n\n\n<li>Checkout session API live; success\/cancel routes.<\/li>\n\n\n\n<li>Webhook endpoint live; signature verified; retries tested.<\/li>\n\n\n\n<li>Fulfillment: license generator, signed download URL, email.<\/li>\n\n\n\n<li>Taxes on; invoice PDFs stored; VAT validation.<\/li>\n\n\n\n<li>Legal pages: Terms, Refunds, Privacy, License.<\/li>\n\n\n\n<li>Logs + dashboards: orders, errors, retries, disputes.<\/li>\n\n\n\n<li>Audit: no server\u2011perk sales outside Tebex.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ (short)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Can I sell VIP roles with Stripe?<\/strong> Yes, if you use Discord.<\/li>\n\n\n\n<li><strong>Can I sell my MLOs with Stripe?<\/strong> Yes, if delivery is off\u2011server and not tied to live perks.<\/li>\n\n\n\n<li><strong>Do buyers get 14\u2011day refunds?<\/strong> For EU, not after they consent to immediate digital delivery and start the download. Log consent.<\/li>\n\n\n\n<li><strong>Which Stripe flow is best?<\/strong> Checkout for speed; Payment Intents if you need heavy customization.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Read this before you start. If you run a FiveM\/RedM server and plan to sell in\u2011game perks, you must use Tebex. Cfx.re\u2019s docs and PLA state that \u201cthe use of any other platform or payment provider is prohibited\u201d for server monetization. Self\u2011hosting Stripe is fine for off\u2011server sales (standalone scripts, MLOs, UI packs, services, courses). [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":199547,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2888],"tags":[],"class_list":["post-199546","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-monetizing-servers"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/posts\/199546","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/comments?post=199546"}],"version-history":[{"count":1,"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/posts\/199546\/revisions"}],"predecessor-version":[{"id":207166,"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/posts\/199546\/revisions\/207166"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/media\/199547"}],"wp:attachment":[{"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/media?parent=199546"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/categories?post=199546"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemx.com\/pt\/wp-json\/wp\/v2\/tags?post=199546"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}