# Getting Started

Fungies.io lets you sell anything digital including Subscriptions, Digital Downloads and Games. We're a Merchant of Record so you won't have to worry about tax reporting and filing internationally.

First, welcome to Fungies! We're super happy you're here and would like to thank you for using our products.&#x20;

Here's a short Get Started video that will get you up-and-running!

{% embed url="<https://www.youtube.com/watch?t=6s&v=oZ1DM_-vq2s>" %}
Quickly get started with your Store
{% endembed %}

### You can start by building your Web Store right away, without signing up

Using our Storebuilder without logging in, you can see for yourself how easy it is to set up your digital storefront in minutes! Simply go [here ](https://app.fungies.io/builder)to start customizing!

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fe7TsFEXEN4yfTD43IeD3%2Fimage.png?alt=media&amp;token=7136473b-7f16-40b0-b1ed-a5429bad892e" alt=""><figcaption><p>You can start customizng your store without signing up from this link: <a href="https://app.fungies.io/builder">https://app.fungies.io/builder</a></p></figcaption></figure>

### Check out one of our samples of the Store!&#x20;

Here are some stores that we've prepared:

{% embed url="<https://gameguru.dev.fungies.net/>" %}

{% embed url="<https://mad-mimic.stage.fungies.net/>" %}

{% embed url="<https://simfabric.store/>" %}

{% embed url="<https://store.madmind-studio.com/>" %}

### Register with e-mail

[Register ](https://app.fungies.io/register)in a few short steps. Provide your email address and password or simply sign up using Google or Discord SSO.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FQGL6LNpKrKYpTyn6vvf1%2Fimage.png?alt=media&amp;token=4c830afa-2140-46cc-8761-759d2534aaf6" alt=""><figcaption></figcaption></figure>

### Verify e-mail (check Spam folder!)

Check verification e-mail has landed in your Spam folder! And then click "Verify"

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FlUHHPnCMzXETbM3I03O5%2Fimage.png?alt=media&amp;token=2269ecc6-c1ce-4874-95fe-e19de6079994" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F682OUSaKNH7ea7IcemwT%2Fimage.png?alt=media&amp;token=480727e0-ea1f-4ddb-a4be-6fbd21da3ce3" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FMQMUTM31SYbhvd88KOEQ%2Fimage.png?alt=media&amp;token=64926d28-1e38-4ae7-9e21-39ceb0a11650" alt=""><figcaption></figcaption></figure>

### Create your own subdomain and name your store or marketplace!

This is exciting! Now name your store or marketplace and let us handle your subdomain. You can always change the subdomain to your own domain later on in Settings!\
\
Once you've created your own Workspace, you'll get accesss to the Dashboard view:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fz5tTvD4nOHy12INrUyVe%2Fimage.png?alt=media&amp;token=a3c78d7d-1072-4d1d-ad72-e467fcf8d4d1" alt=""><figcaption><p>This is the view of the Dashboard after logging in for the first time.</p></figcaption></figure>

### Congratulations! You now have officially started your game's Web Store with us!&#x20;

### What's next? Dive into details and set up your store

Learn the fundamentals of Fungies.io to get a deeper understanding of our main features:

1. [Manage and customize your Store in Website Builder](/customize-your-online-store)
2. Add Game with essential details, price and [upload Steam keys](/add-game-keys)  or [Mobile In-Game Assets](/add-mobile-game-assets) for your title
3. Add [Subscription](/add-subscription-product) products
4. Embed [Overlay Checkout](/getting-paid/checkout-choice/overlay-checkout) to your website or app
5. Allow us to help you manage finances and taxes by adding your [Stripe ](/workspace-settings/connect-your-stripe-account)account&#x20;
6. [Publish ](/store-settings/publish-your-store)the store and keep track of the metrics!&#x20;
7. Selling your first Game, Subscription or [Digital Download](/add-digital-downloads)

{% content-ref url="/pages/D1UYqKJcg9qToo64YOsd" %}
[Publish your store](/store-settings/publish-your-store)
{% endcontent-ref %}


# Workspace Verification

### Why Fungies.io Verifies Your Business

Fungies.io is a **Merchant of Record (MoR)** platform — meaning we legally stand between you and your customers as the seller of record. When a buyer purchases your product, Fungies processes the payment, handles tax compliance, and takes on liability for the transaction. This is fundamentally different from a standard payment gateway.

Because of this responsibility, **every business must be verified before it can start selling.** Here's why:

* **Fraud prevention** — Unverified stores are the primary vector for payment fraud, money laundering, and card abuse. As your MoR, Fungies is liable for any fraudulent transactions that pass through our platform.
* **Card network compliance** — Visa, Mastercard, and other networks require MoRs to perform KYB (Know Your Business) checks on all merchants. Without this, we risk losing our ability to process payments entirely.
* **Chargeback protection** — Understanding your business model upfront lets us detect suspicious activity early and protect both you and your customers from disputes.
* **Tax and regulatory compliance** — As your MoR, we collect and remit taxes on your behalf globally. We need to understand what you're selling to apply the correct tax rules.

Once your activation request is submitted, **our team reviews and approves your store within 24 hours.**

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F3yYWnaY8G5rd7vnqGnGg%2Fimage.png?alt=media&amp;token=571c28d1-a341-4048-94da-c27492c6f7fa" alt=""><figcaption><p>By default - all workspaces are deactivated - you can't sell anything.</p></figcaption></figure>

### How to Complete the Store Activation Form

Navigate to **Settings → Store** and click **"Add Business Details"** to open the Store Activation Request form. Fill in each field as follows:

#### Full Name

Your legal full name as the business owner or authorized representative. This is used for identity verification and contract purposes.

#### Contact Email

The primary email address for your account. This is where Fungies will send activation status updates, compliance notices, and billing communications. Use a business email if possible.

#### Address

Your registered business address (or personal address if you're a sole trader/individual). This must match your official business registration documents.

#### City & Country

The city and country where your business is legally registered. This determines applicable tax rules and regulatory jurisdiction under which Fungies processes payments on your behalf.

#### Website URL

The URL of the website or product where you plan to sell. Our team will review this to confirm your product is live (or near-launch), understand your customer base, and verify that your business model complies with our acceptable use policy.

#### Social Media URL

A link to your business's social media profile (LinkedIn, Twitter/X, Facebook, etc.). This helps us verify your brand's legitimacy and online presence — an important signal in our fraud screening process.

#### Business Description

A concise overview of your company — what you do, who your customers are, and how long you've been operating. Think of this as your elevator pitch to our compliance team. Be clear and specific.

#### Products or Services

Describe exactly what you intend to sell through Fungies. Include product type (SaaS, digital goods, templates, plugins, etc.), pricing model (one-time, subscription, usage-based), and your target market. This information is critical for tax classification and risk assessment.

#### Purpose of Usage

Explain why you're using Fungies specifically as your MoR. For example: *"We need global payment processing with automatic tax handling for our SaaS product sold to customers in the US and EU."* This helps our team understand your use case and configure your account appropriately.

#### Do You Already Have Customers?

Select **Yes** or **No** to indicate whether you have an existing customer base. This helps us assess payment volume expectations and prioritize your review accordingly.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FWc7izfxnra2rHUHfB89j%2Fimage.png?alt=media&amp;token=f433a6d2-9887-4b73-b423-a53dba8a07a7" alt=""><figcaption><p>Fill out your business details in order to get activated.</p></figcaption></figure>

### What Happens After You Submit

1. **Submission** — Your request is logged and assigned to our compliance team immediately.
2. **Review** — We verify your business details, check your website, and screen against fraud and sanctions databases. This takes up to **24 hours**.
3. **Activation** — Once approved, your store is activated and you can begin accepting payments through Fungies.
4. **Rejection or Follow-up** — If we need more information or cannot approve your application, we'll reach out via your contact email with next steps.


# Customize your online store

Edit the look and feel of your online store. Add your logo, landing page sections, and fill up the footer.

How to do that? After logging into the Dashboard,. choose Website Builder and start customization!&#x20;

Fungies' Website Builder allows you to easily manage and build the perfect Store. <br>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FXxgP0vWmUOWdgexzkHNd%2Fimage.png?alt=media&amp;token=9a80e352-150f-47a3-b581-a996a96c1dc5" alt=""><figcaption><p>Access the Website Builder from the Dashboard</p></figcaption></figure>

1. Choose Template:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHDxd9KJR0BQ1m894d9iT%2Fimage.png?alt=media&amp;token=61693766-6d72-4959-8c82-eed87c5304d7" alt=""><figcaption><p>When accessing the Website Builder for the first time, you'll be asked to choose your Template.</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FRONezkirzs274EKtxYua%2Fimage.png?alt=media&amp;token=2e91a2b4-ec71-4fea-adc7-3b263bb07623" alt=""><figcaption><p>After choosing the right template, you can now freely add page sections, change font colors or add additional pages!</p></figcaption></figure>

2. Add page sections:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FcUeBhXoTNdrmVsLrxyff%2Fimage.png?alt=media&amp;token=3973ef29-2291-4f20-be15-87b27c91738b" alt=""><figcaption><p>Hover any page section and choose the right subsection to be included on that page.</p></figcaption></figure>

* Text Section
* Image Section
* Video Section
* Gallery Section
* Points Section
* Slider Section
* Recent Products Section

3. Preview your store on different devices:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F6VqV7UZH9yh2nzfnvAww%2Fimage.png?alt=media&amp;token=10786734-5fdd-40d0-9285-185e654382ea" alt=""><figcaption><p>Your Store is always Mobile-ready!</p></figcaption></figure>

3. Add New Pages
4. Customize Your Basic Store settings
5. Add [Digital Downloads](/add-digital-downloads), [Subscriptions](/add-subscription-product), [Game Keys](/add-game-keys) or [Game Assets](/add-mobile-game-assets) to sell!

**Variation and possibilities are endless, pick variations which work for your Store!**&#x20;

\
&#x20;:exclamation: Remember to SAVE CHANGES before leaving Website Builder so your progress won't be lost!&#x20;

4. After you have successfully customized your Game's storefront, remember to [Publish ](/store-settings/publish-your-store)it!


# General Settings

In this section, we'll explain how to change default settings of your Web Store

One of the first things to take care of on your new Web Store is the logo along with Page Description.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FEwFt48MzS3QvcvEG2ABz%2Fimage.png?alt=media&amp;token=fadf351a-6cc3-4bb9-a985-cdab5ebd6817" alt=""><figcaption><p>Access General Settings from the left pane in <a href="https://app.fungies.io/store-builder">Website Builder</a></p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F3lVSliJjPMebnWfEHSaf%2Fimage.png?alt=media&amp;token=b2b83056-42c9-4d50-876b-161b387bb76e" alt=""><figcaption><p>On the left side you'll see General Settings for your Web Store</p></figcaption></figure>

With these settings you can:

1. Change the Store Name that can be displayed in the header
2. Logo of the store
3. Favicon
4. Page settings like Title and Description - which will be visible in the browser

Now that you've uploaded your Company's or Game Studio's logo, you can edit default color settings for your entire Web Store.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fs9CSq0211zpBNO4G2n74%2Fimage.png?alt=media&amp;token=ab1715d9-4976-4bc4-9765-355e0f62c9d8" alt=""><figcaption><p>Go to Store Style to change default button colors and also background color</p></figcaption></figure>

Here in Store Style you can change:

* Background color for your entire store
* Default Button color
* Font
* Text theme (Dark or Light)

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F5ElQ4Gb7opq7DZFPc0bN%2Fimage.png?alt=media&amp;token=ddda929f-9a6d-465a-a1c3-0e97a698378d" alt=""><figcaption></figcaption></figure>


# Header

This is the settings section for Top Bar or Top Menu.

Top Bar is very important as it's the first thing user see on your website.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fa6OYLfBIoc4CrF2hPUEt%2Fimage.png?alt=media&amp;token=2b5782a0-140d-4c1c-8f10-53d7fb2c1077" alt=""><figcaption><p>Access the Header section from the Website Builder</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FknQj4AMtlvrSbshAjYOd%2Fimage.png?alt=media&amp;token=156362d1-5d3e-4a18-96c8-aa2631483e81" alt=""><figcaption><p>Header settings are shown on the left pane</p></figcaption></figure>

With these settings you can change the look and feel of the Top Bar navigation menu:

1. Add or edit Menu links like Home, Subpage - you can do that by clicking "Add New Page" and the new position will instantly appear in the Header
2. You can switch On/Off Sticky Navigation - the menu can slide with the user or just doesn't scroll
3. You can choose if certain features of the menu are visible:
   * Logo
   * Store Name
   * Search Bar
   * Sign In / Sign Up for the end-user
   * Cart
   * Explore button (which directs to Search)

You can also edit the Custom Style for the menu such as background or primary color.


# Footer

Change the footer of your Web Store here with links and Social Channels links.

You can add as menu footer links and columns as you want. Simply navigate to Footer in the left pane of the Website Builder and you'll be able to access it.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHwOqXrcqgec9G67gc5ar%2Fimage.png?alt=media&amp;token=d49a3176-e999-41a9-8db7-1d537cee51c4" alt=""><figcaption><p>You can edit your footer adding menu positions, links and columns</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FrMeifBoyc01xgQTB0JjW%2Fimage.png?alt=media&amp;token=830bfa9d-409a-4121-b39a-aeae0dd6a6e4" alt=""><figcaption><p>Add your Social Media links - the logos will appear automatically</p></figcaption></figure>

You can set up things like:

* Multiple columns and links in the footer
* Social Media links
* Terms and Privacy Policy are added by default


# Add New Page

In this section - you'll learn how to add a new Web Page to your Game's Web Store. A new page can contain anything - from your About Us, to Team page, or Refund Policy page.

Click Create New Page from the left pane in the main menu inside Website Builder.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FS05PLRDbOHIHmu4sN6mN%2Fimage.png?alt=media&amp;token=691054ab-2cfe-4b57-8a00-b65c4cab6895" alt=""><figcaption><p>Click Create New Page on the left pane</p></figcaption></figure>

Two tex fields will appear:

* Define the Page Title
* Slug: means the URL for the subpage

Once you do that, you'll be redirected to the new page and can start creating new Page Sections as you seem fit.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fvi0FFOXQ4E89hPNGq1dn%2Fimage.png?alt=media&amp;token=3989b5c2-f075-458f-b4d9-53e1d6a45e8d" alt=""><figcaption><p>Adding a new page will redirect you to a Blank page - now you can freely customize it by adding Page Sections</p></figcaption></figure>


# Add Page Section

You can create new Page Sections on built-in pages like Homepage or on any New Page that you manually add.

Page Sections are a way for you and your team to create new content on your Web Store or Website. Hover on any section or click New Section on the left. A popup menu will appear for you to choose which type of section can be added.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FlgyfiDaJxH8o9RqU6xeu%2FScreenshot%202024-04-11%20111300.png?alt=media&amp;token=c1a3722f-3f7b-463d-a427-2a6cd69f0dde" alt=""><figcaption><p>Hover on any Page Section on the Homepage and you'll see (+) buttons - click on the and a popup menu will appear</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FpwRoGsbAyScuTW81rpdb%2Fimage.png?alt=media&amp;token=261141f7-ad4b-40e2-9714-211d8cc4def5" alt=""><figcaption><p>Choose a new Page Section from this popup menu</p></figcaption></figure>


# Text Section

The Text section is pretty straightforward, you can add any text here - in one or two columns:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F7WOgfswE5SOarPogZfYL%2Fimage.png?alt=media&amp;token=6c8c2cff-c7d3-4cce-bcde-66dca2fbfb0f" alt=""><figcaption><p>Aside from setting up the section itself, you can also customize it with Custom Style: like adding background image</p></figcaption></figure>


# Image Section

In the Image Section, you can freely control how the image will be placed:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FvsTxhu76BszHBrsD8ZCZ%2Fimage.png?alt=media&amp;token=32e7d863-d39d-45bd-95cf-992ba01fe802" alt=""><figcaption><p>Editing Image Section</p></figcaption></figure>

Options to customize this section includes:

1. Choose the size of it, S, M, L, XL
2. Choose the image layout (top, bottom, left, right)
3. Choose the text alignment (left, center, right)
4. Choose if Image, Button, Text or Title should be visible
5. Upload the image itself

Of course, you can always customize it with [Custom Style](/customize-your-online-store/custom-style).


# Video Section

With the video section, you can add your Game's trailer:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fqk92DOMFCgwOK435G6x8%2Fimage.png?alt=media&amp;token=ebe765c0-2af2-47fe-9403-5045c6d462fe" alt=""><figcaption><p>Add Game trailer or gameplay with Video Section</p></figcaption></figure>

Customization options for this section includes:

1. Video positioning (only when size is smaller than XL)
2. Size of section from S to XL
3. Text alignment
4. Title visibility
5. Text visibility
6. URL for the YouTube video


# Gallery Section

This section is also straightforward, simply upload images for your Game's gallery:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F8zgRRPgDWHcPrgNrkSlW%2Fimage.png?alt=media&amp;token=f3fda138-9eee-4dab-a97f-ee1f66c72593" alt=""><figcaption><p>Add images to this simple gallery carousel</p></figcaption></figure>

The Gallery is in the Carousel format - freely accessible via Mobile Devices as well.


# Points Section

Points section can be used to list all the important things that your Game has, like features.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FVcXNRFhYnIzQT2131cFT%2Fimage.png?alt=media&amp;token=c05634c9-c874-42ee-b189-85f415c93a71" alt=""><figcaption><p>Points can be used to list the most important features of your game</p></figcaption></figure>

You can freely drag and drop the points in any order.


# Slider Section

One of the most important sections on any Web Store or Website: sliders. After adding your Slider Section, navigate to Edit button and you'll see the option to add a New Slide:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FOGmz3qEdTiJ8T9JP1WI7%2Fimage.png?alt=media&amp;token=e91616bc-ea04-4572-a2c7-a7d293cdb60a" alt=""><figcaption><p>You can have multiple slides for this section</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FdHzZVMpXEE8zkdybilip%2Fimage.png?alt=media&amp;token=d819a380-151a-4463-8d46-a57b845e3fe5" alt=""><figcaption><p>After clicking on certain slide - you can edit it with images, texts and buttons</p></figcaption></figure>

Here are the options to customize it:

1. Freely add any amount of slides, by clicking "Add new slide"
2. Clicking on a slide will open its Settings
3. Choose if any element can be visible: Title, Text, Button, Image
4. Choose the text and image alignment (left, center, right)


# Recent Products Section

After [Adding Products](/add-game-keys) or [Mobile's IAP](/add-mobile-game-assets) - all products will be shown in this section ordered by the creation date:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FlORZLlQboDWu4Eccpcu3%2Fimage.png?alt=media&amp;token=deb3f357-853f-44c6-b452-d2450083b948" alt=""><figcaption><p>Recent Products section show all recently added Products (Game Keys or Mobile In-Game Assets)</p></figcaption></figure>


# Custom Style

How to edit background, primary color or size of each individual page section.

Each page section can have different styles such as background image or primary color. Changing these custom styles will override global settings in your Store Style main settings.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FagsYOv7SDLn2OkO1ekCy%2Fimage.png?alt=media&amp;token=549f5653-8fe0-4e41-98b2-f981ef1cc115" alt=""><figcaption><p>Each section can be further customized with Custom Style</p></figcaption></figure>

To access the Custom Style for each section, simply click "Edit" when hovering the Page Section, and then continue to edit it.

With Custom Style, you can:

* Change the sizes of each section
* Background color or image
* Change primary colors of buttons


# Add Subscription Product

Here's a short video guide on how to add your subscription product:

{% embed url="<https://www.youtube.com/watch?v=eOWR6jDQuZ4>" %}
How to sell Subscriptions in your Web Store
{% endembed %}

Inside your Developer Dashboard, Go to Products -> Subscriptions to add a new Subscription product:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FyITh5mXNrfmxYoqWbyLm%2Fimage.png?alt=media&amp;token=ed2d36ce-f923-4b78-b0fb-2858cbb59124" alt=""><figcaption><p>Navigate to Products -> Subscriptions to add your first product</p></figcaption></figure>

Add basic information abour your Subscription product after clicking "Add Subscription"

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FGj35nN3uLapw3zFpZN8G%2Fimage.png?alt=media&amp;token=b043b33d-1bbb-4a58-9e52-eecc6a791651" alt=""><figcaption><p>Add necessary information about your SaaS product</p></figcaption></figure>

Remember to fill in:

* Name of the Product
* Description
* Logo
* YouTube / Vimeo / Twitch video for the product cover
* Gallery photo - screenshots of your SaaS app

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FRdcdkYQqaCi1KiKhxPew%2Fimage.png?alt=media&amp;token=c7845f87-15d8-49f0-9ebe-529f9278f5bf" alt=""><figcaption><p>You can add photos or screenshots of your Software in the Gallery section</p></figcaption></figure>

Variants can be used as Plans, examples:

* Starter Plan
* Professional Plan
* Enterprise

Offers are Prices, examples:

* Starter $19 / month
* Professional $299 / yearly

A Product can have multiple Variants. Each Variant can have multiple Offers (or Prices).

Congratulations! :tada: After you've successfully created your Subscription product, you should see it listed:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FfuUmLflk025Eg85GIyam%2Fimage.png?alt=media&amp;token=6a3fadfa-7322-42a4-bbc3-4c9720750dec" alt=""><figcaption><p>Your subscription product is now listed! <span data-gb-custom-inline data-tag="emoji" data-code="1f44f">👏</span></p></figcaption></figure>

In order to create Pricing Plans for your Product, click Create Offer (provided you've already [connected your Stripe account](/workspace-settings/connect-your-stripe-account)):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHfDKDidL7i01BOwPJkc0%2Fimage.png?alt=media&amp;token=2b79ebab-6f77-4d6e-aa72-67bd912cbc7f" alt=""><figcaption><p>Creating a $19/month Offer</p></figcaption></figure>

That's it! You've created a Subscription product that can now be purchased by your Customer. Our Subscription management stack includes:

* Automated payments every interval period you've defined in your Offer
* Transactional e-mails for every subscription payment
* Invoice generation for the customer - sent directly to his/her inbox
* Management Portal after logging into your Store
* Update Payment Methods
* Cancel Subscription Plan

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FKxN76faT8K0xM8US0oKm%2Fimage.png?alt=media&amp;token=a7941d35-c9ec-4078-be57-821d61675490" alt=""><figcaption><p>This is how your Customers see the Product page. Check out this <a href="https://subscription-testing.dev.fungies.net/product/saas-subscription-monthly-subscription-3d848193-8a61-4f40-b633-bae5d3aa6071">sample Subscription</a> product we've created.</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FxJggA9NBi9MzHafYzkRF%2Fimage.png?alt=media&amp;token=b38efe67-ad9a-4d9f-b2dd-cfeb13fb6e5d" alt=""><figcaption><p>This is a hosted checkout page whenever your Customer clicks on Subscribe button. Taxes are calculated and collected automatically.</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FWM7WFTqvkf1Dby2GEC8b%2Fimage.png?alt=media&amp;token=0bd635f8-6181-473f-84ed-551060b16ecc" alt=""><figcaption><p>This is how your Customers will be managing their Subscriptions - by logging in your Store (they'll have to reset their passwords if they weren't Signed Up)</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FzLSubL099NR3wQC0IXMr%2Fimage.png?alt=media&amp;token=8da945b7-6dd8-4ee1-bcf1-aa1b4696e29d" alt=""><figcaption><p>Customers can Update Payment Method or Cancel their Subscriptions. Invoices can viewed from here, too.</p></figcaption></figure>


# Add Digital Downloads

With our store builder, you can upload any digital file and start selling them through the shop or by sharing a simply "Buy Now" button or as we call it: [Overlay checkout](/getting-paid/checkout-choice/overlay-checkout).

Here's a video on how to start selling your digital goods:

{% embed url="<https://www.youtube.com/watch?v=Uo5UiwHYWZY>" %}
Step by step guide how to sell your digital downloads
{% endembed %}

Let's go over the process of adding a digital download for your customers to buy:&#x20;

1. Choose "Products" in the left pane of the dashboard and then click "Digital Downloads"

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FBtYhBd1erWrUaRK5lMA8%2Fimage.png?alt=media&amp;token=28c8b01e-4efe-4eaf-a9fc-b101c8991793" alt=""><figcaption><p>Head to Digital Downloads to upload your first digital file to sell</p></figcaption></figure>

2. Click "Add Digital Download" in the upper right corner and a drawer from the right will slide in. You'll need to fill out all important information about your digital download. In the example below we've uploaded information about a Wordpress Template file:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FP1fJnRdOLz5Io8JJJ6bR%2Fimage.png?alt=media&amp;token=65bf0890-0529-4a9a-8adf-a8e04dde2d9d" alt=""><figcaption><p>Fill in product name, description, gallery, YouTube video of the product</p></figcaption></figure>

3. Choose "Create Offer" to add pricing to the file. Offers are like prices, where you can add as many offers as you want. Each offer or price has to be binded to a product. Remember, "Product" entities are not the same as "Offers" - offers are the prices for the products. Product can have many offers or prices.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FPTqapb1DyUbtXIgVqDar%2Fimage.png?alt=media&amp;token=4491afc9-b5b9-40e2-bc30-d7828957c6bb" alt=""><figcaption><p>Create offer or price to add some more details to the product you've added.</p></figcaption></figure>

4. Now add the digital file associated with the "Offer". Remember to add the price for the file as well. <mark style="color:yellow;">You can upload up to 50 GB of any chosen filetypes: PDF, MP4, MP3, PPTX, XLSX, PNG, JPG, MOV and more</mark>. You can additionally indicate region restrictions or tags for the offer:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FXaaD8AhPgLEOXbdU5R1T%2Fimage.png?alt=media&amp;token=c750e75f-19e7-4ce6-9efc-400841ffb219" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FVAKUiWe55O8QzP6wfcUr%2Fimage.png?alt=media&amp;token=76a00cea-08e3-4ca5-8d38-d95a83580a81" alt=""><figcaption><p>If you've successfully added the file - a progress bar will show the upload status.</p></figcaption></figure>

5. Now that you've added your digital file - you can view the product page how it looks like by clicking "View" on top:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FItpjWdtgNeYjWn2ZfNfO%2Fimage.png?alt=media&amp;token=840c5606-20e0-4324-9815-4acbcc7253aa" alt=""><figcaption><p>To preview the product - click on View on the details of the product</p></figcaption></figure>

6. Preview the product page:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FYz7NXCt0Yc3s7wHYJgPY%2Fimage.png?alt=media&amp;token=668d935f-b082-4df3-8180-a902a9d43659" alt=""><figcaption><p>This is how your customers will see the Digital Product available for buying</p></figcaption></figure>


# Add Game Keys

Create Game and share your amazing project with the audience! No matter, if you want to show pre-launch content or start selling. Adding a Game Key to your Website is a great place to start.&#x20;

Here's also a short video explaining why you should sell Game Keys if you're a Publisher or Indie Developer:

{% embed url="<https://youtu.be/E4KmkOl8ZJk>" %}
Self-publishing your games in your own Web Store
{% endembed %}

Follow the steps below and let us help you with this process:&#x20;

1. Click on Game Keys on sidebar menu and then on **Add Game** button on right top corner

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FLkSVOfwk7AbNGrmMBKQZ%2Fimage.png?alt=media&amp;token=2f847d7a-6b56-4e7e-965c-b8ce423b2bc0" alt=""><figcaption><p>Click Add Game on top right corner to add Game Keys for your Game</p></figcaption></figure>

2. First, add the cover image for the game - this will show up in Search and Product Details page:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FrRTCy3BQsc2xmFd8nUv7%2Fimage.png?alt=media&amp;token=d6085095-d1ce-4636-917f-4747d6f2662e" alt=""><figcaption><p>Upload Cover Image for your game - this is important!</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F5FhbDSoW6Xrt3HHBSGcp%2Fimage.png?alt=media&amp;token=f2aec1eb-5984-438c-8119-deb4f16fa6bd" alt=""><figcaption><p>Cover Images will be shown in Product Lists, Search and also Product Game Details - so it's important to nail it right</p></figcaption></figure>

3. Add name of the game, include the complete name, edition and type of the game (like DLC), platform (like PC and Steam):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FizmYjqSKiGHWcR8uxNVA%2Fimage.png?alt=media&amp;token=3e2d6f8f-1746-47ee-95ae-e7c0c8a84b99" alt=""><figcaption><p>Remember to add in brackets (PC) and also name of the platform (Steam) and region (Global)</p></figcaption></figure>

4. Add Description, Trailer URL (YouTube only) and you can use the trailer to be your Cover Video on Product Details page:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FIIfwXD9Ls4mpdKNgFORl%2Fimage.png?alt=media&amp;token=e35391ed-bdf1-405c-b813-b16422206586" alt=""><figcaption><p>This is how the Product Page looks like when you turn on Use Trailer as Product Cover</p></figcaption></figure>

5. More details will be needed for your game - as this will help the end-user decide on buying the game from you.

Add Genre:

* Choose appropriate Genre
* You can add multiple Genres (like Action, Horror, Strategy)

Add Product Region:

* Global, Europe, LATAM, EMEA and countries
* This is important as Game Keys can be activated only in appropriate regions - so be careful with this

Add Tags:

* Tags will help users find your product
* This can also be used as a filter and you can link straight to Search with appropriate tags

Platform:

* Choose the platform for the key to be activated, like Steam, PSN, Xbox Live, Nintendo Switch and more
* Choosing the right platform is important for the user

Systems:

* Choose Windows, Playstation 4, 5 or others
* Remember to add System Requirements

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FtTvHhP3YC849DhtZY7V8%2Fimage.png?alt=media&amp;token=64a8ab02-1921-4bbd-b670-255cc2971181" alt=""><figcaption><p>Product Details are very important: it guides the end-user or customer how and where the game can be activated</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FTZHmrc4y5QhqU1DjCfRw%2Fimage.png?alt=media&amp;token=273166b2-207f-4c38-b413-a6f3dc3f3133" alt=""><figcaption><p>Remember to add System Requirements</p></figcaption></figure>

5. Set up Price. You can always go back to this step later or amend it when needed!&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FIgr1JnTZzM8u73wCKseZ%2Fimage.png?alt=media&amp;token=5dc831ee-f6c8-4242-bb38-bade66f461b0" alt=""><figcaption><p>Add Pricing for your game - we will add the possibility to differentiate prices and currencies depending on Region soon</p></figcaption></figure>

:star: *Note that the price of the Steam keys cannot be lower than the game price on the Steam platform*

6. Upload Game Keys (Steam, GOG, Epic Games, PSN, Xbox live and more). These are codes that can be activated in appropriate platforms.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FIVU6sUKo6d3s49n0MfeT%2Fimage.png?alt=media&amp;token=5b75f75a-a038-41cf-9f55-650cde07c8fb" alt=""><figcaption><p>Add Game Keys from Editing Details of game key</p></figcaption></figure>

CSV file to upload Game Keys should look like this (remember it has to be CSV only with 1 column):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FwL6Gb2WD7YpHKOAwdmo8%2Fimage.png?alt=media&amp;token=4dd8cda5-a4f1-44b6-86ad-2736a6da0dbe" alt=""><figcaption><p>CSV file structure - only 1 column, 1 first row is key, and the rest are the codes</p></figcaption></figure>

{% embed url="<https://www.youtube.com/watch?ab_channel=KeenGamer-MoreThanJustaGameSite&v=wsBkwmGo1Z4>" %}
A short guide on how to activate Steam game keys for end-users
{% endembed %}

\
:information\_source: *You can receive up to 5,000 game keys from Steam which can be sold on other platforms.*&#x20;

Not sure if selling your game's Steam keys are legit? Watch the video below:

{% embed url="<https://www.youtube.com/watch?ab_channel=SteamworksDevelopment&v=V0tRQgNiQMo>" %}


# Add Mobile Game Assets

You can sell your [Mobile IAP](https://docsend.com/view/gpy2iqvvrxep2rh5) (In-App Purchases) through the Web Store, and this could save you 30% commission from AppStores!

{% embed url="<https://www.youtube.com/watch?v=s0BCAwDgwww>" %}
Video guide how to create your Mobile Game's Web Store
{% endembed %}

This graph will show you how Players will be able to buy from the Web Store and receive it ingame - and also various ways for you to promote the Web Store outside of AppStores:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Ff1SUT7koN0WQXC5YbddX%2Fimage.png?alt=media&amp;token=767fd439-793f-4599-895b-4530d0a1576c" alt=""><figcaption><p>This simple flow shows how the Web Store is integrated with your Mobile Game's data</p></figcaption></figure>

Follow the steps below and let us help you with this process:&#x20;

1. First, add your Game -> click Add Project

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F4ZgI8iBr8fPEJzxeie7e%2Fimage.png?alt=media&amp;token=95c94f8a-d7c7-4ae2-8168-3b5fbb3fe7e7" alt=""><figcaption></figcaption></figure>

2. Then add Basic details of the Game: title,  description, image, genre and tags.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F4EK9CGB3cLXcdNkvO6wo%2Fimage.png?alt=media&amp;token=4db9dd81-51a8-438c-8f53-c0c7c4281621" alt=""><figcaption></figcaption></figure>

3. IMPORTANT! If you have to define which Player's data you'll need to pass into your Mobile Game's backend (read more about [Webhooks here](https://docs.fungies.io/introduction)). It can be:

* User\_ID
* Server\_ID

You can add such necessary data to be requested in the "Add Custom Fields" section:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FaxQS3IUpyG5Fo01re3na%2Fimage.png?alt=media&amp;token=a544bb91-5421-499d-8556-3f5b07920d11" alt=""><figcaption><p>Adding Custom Fields like User_ID and Server_ID will make them visible on the Product Page</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FpYMyVKVLweg0L4nA496Y%2Fimage.png?alt=media&amp;token=89ddc8f8-f8ec-4b2f-bf1a-ad0a9bb86993" alt=""><figcaption><p>Custom Fields let you define which data will be sent to your game's Back-end via Webhooks</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FpALZHCQKuIwptqOamTgP%2Fimage.png?alt=media&amp;token=016a3dc2-86a5-4763-9c3d-1adb84a8b2ca" alt=""><figcaption><p>Players will be able to fill in their data - which then can be forwarded to your game's backend</p></figcaption></figure>

3. Now click on the details of the game add navigate to "Add Asset"

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FETZk1s71ktblfEAKJISy%2Fimage.png?alt=media&amp;token=8378076f-9bc3-4443-baeb-ccc1300991ec" alt=""><figcaption><p>Add a new asset: Virtual Currency or Virtual Asset to the game</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FsntjDHvle4dDFoE1WnV8%2Fimage.png?alt=media&amp;token=b08d6d85-7829-4203-b484-a131e6eff660" alt=""><figcaption><p>Add Virtual Currency or Virtual Asset along with Variants</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FMuCvNHAlypsu9cLJjqVD%2Fimage.png?alt=media&amp;token=43b764a9-f5bd-4d23-b630-63c733f315f4" alt=""><figcaption><p>Add Variants for Virtual Currency or Asset</p></figcaption></figure>

What are Variants? Example:

* You can add Virtual Currency like Gold
* Variants are different options for that asset, such as: 5000 x Gold, 2500 x Gold, 125 x Gold and so on
* Each Variant can have its own prices

Here's how Variants will look like on the[ Product Page](https://gameguru.dev.fungies.net/product/packs-e4a8fd3d-14ad-4104-bc75-b1d8aaf8ef95):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FL7CwCs3uf1A1eUxtULQW%2Fimage.png?alt=media&amp;token=6af5a3e5-e81c-4463-a914-1d3f5b1c8ef1" alt=""><figcaption><p>Customers will be able to choose a Variant of Virtual Currency or Virtual Asset</p></figcaption></figure>

### How will players purchase Virtual Assets or Currencies?

Players will access your Web Store with any browser. Everything is mobile-responsive:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHwea13xa4VcSreBgTAsf%2Fimage.png?alt=media&amp;token=4a196233-b36a-4b68-ae06-ae4419cc806f" alt=""><figcaption><p>Players will be able to filter and search through your Mobile Game's Web Store</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FyDYQc5PHJJKynHnBivwn%2Fimage.png?alt=media&amp;token=4ba6975d-e75f-4c1e-8171-6050a139fe5d" alt=""><figcaption><p>When the player access the Product Page, he/she can then choose Variants of the Virtual Asset/Currency</p></figcaption></figure>


# Add One Time Payments

**1. Go to One-time Payments**Choose "Products" in the left pane of the dashboard and then click "One-time Payments".

**2. Click "Add One-time Payment"**&#x48;it the button in the upper right corner — a drawer will slide in from the right. Fill out all the important info about your product: name, description, cover image, cover video (YouTube, Vimeo, etc.), gallery images, and a feature list.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FTa6X55nFmyHbjlQs6uAg%2Fimage.png?alt=media&amp;token=b3b9975a-7e74-4e07-9b55-effba8edfc13" alt=""><figcaption><p>Add One-Time-Payment Products</p></figcaption></figure>

**3. Create an Offer**Click "Create Offer" to add pricing to your product. Offers are basically prices — you can add as many as you want to a single product. Think of it this way: the **Product** is what you're selling, and the **Offer** is how much it costs (and under what conditions). One product can have multiple offers.In the offer settings you can:

* Set the **currency** and **price**
* Mark it as **free**
* Enable **quantity change** (let customers buy more than one)
* Show a **discounted/original price**
* Restrict by **platform** or **region**
* Add a **SKU / internal ID**, **GTIN**, **warning text**, and **tags**

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F0XpNMxPTaMmz1zxUgQ8F%2Fimage.png?alt=media&amp;token=8ea0d99d-dc6a-4c9a-8055-db48ac204747" alt=""><figcaption><p>Create basic information about your Product</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FWm5CP8zg1k7MYSfnTDBN%2Fimage.png?alt=media&amp;token=ebdf6901-7f2a-4fb2-a7d1-8805974ae0a1" alt=""><figcaption><p>Preview product and then Add Offer</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FVlMaF2KEgPjEOjKKkpWX%2Fimage.png?alt=media&amp;token=017297bb-91f0-4050-9408-0c51dde84e2b" alt=""><figcaption><p>Create Offer for the Product with price</p></figcaption></figure>

### Pay What You Want — with the API

If you want to get creative with pricing, the [Fungies API](https://docs.fungies.io/api-reference/offers/create-a-new-offer) lets you create offers programmatically — which means you can build **"pay what you want"** products.

The way it works: when creating an offer via the API, you set the `price` field dynamically based on what the customer chose to pay.&#x20;

Leave the `recurringInterval` fields empty to keep it a one-time purchase.&#x20;

You can also set `mutableQuantity: true` to let buyers adjust quantity at checkout.This opens up use cases like:

* Donation pages
* "Name your price" products
* Tip jars
* Community-supported pricing

Check out the full API reference here: [Create a new offer →](https://docs.fungies.io/api-reference/offers/create-a-new-offer)


# Variants of the product

Whenever you create a "Product" - in order for your customers to buy it has to have a binded "Offer". Prices are always indicated inside Offers, not Products or Variants.

Variants are a way for you to add multiple options for the product you're selling. Examples:

* 5 editions of the game
* 3 versions of the same template
* 5 episodes to the same online course

Every Variant has its own "Offer" or "Price" - in terms of Digital Downloads or Games - each offer encompasses its own set of Files / Keys.

1. Creating a new variants is easy, simply go to the product details and click "Create variant":

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FVpTY7GIcV3ivKbRgYY8f%2Fimage.png?alt=media&amp;token=e8a73a0f-f0eb-4071-9df5-bf1620fecc2c" alt=""><figcaption><p>Creating a variant for the product</p></figcaption></figure>

2. Fill out necessary information about the variant:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FLnbI5HufYB46bauTRp1K%2Fimage.png?alt=media&amp;token=0c8e0a32-c2b7-4bb2-b316-504e4d138f44" alt=""><figcaption><p>Variants can have different cover images and descriptions.</p></figcaption></figure>

3. Now, create an Offer that's binded to that Variant:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FVfKiY4w34FVokdjzev0N%2Fimage.png?alt=media&amp;token=97b6b28f-a4c6-492d-942a-4d92c9a222b8" alt=""><figcaption><p>Each offer has its own Files or Keys </p></figcaption></figure>

4. When the customer visits the product page, he/she will have the option to choose between Variants as seen below:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FV8WM4EPnrMKZkHAexasb%2Fimage.png?alt=media&amp;token=c7f72e20-1b34-4105-abd4-b08ff5bfe5d2" alt=""><figcaption><p>Now the user can choose the Product Variant on the product page</p></figcaption></figure>


# Connect your Stripe account

In order to start receiving payments for your Games or In-Game Assets - create your own Stripe account that will be a submerchant account to ours.

To enable transactions on your Web Store please ensure that correct Stripe account is connected to Fungies platform. <br>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F3ePaL9DHWPtB3XxVHo59%2Fimage.png?alt=media&amp;token=714269b7-fa11-4ac4-a6a1-6d44006749b9" alt=""><figcaption><p>The flow of payment - from User's to Merchant's (or Game Developer/Publisher) Bank Account</p></figcaption></figure>

Thanks to Fungies, you do not need to bother about taxes we are Merchant of Records and handle all essential payouts and take care of smoothness of transactions!&#x20;

**1. Create New Stripe account or connect to existing one**

By creating a new account, we'll be able to pay you out in desired methods. Security, fraud detection, onboarding is all on Stripe's side. We rely on Stripe's long history of catering to the likes of Shopify to provide secure payments options. Access the [Payout ](https://app.fungies.io/payout)tab in Dashboard like below:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FnXY3aHnmSFlcox9y2lDt%2Fimage.png?alt=media&amp;token=7e9b15ca-a055-4614-aa67-10f13f63c702" alt=""><figcaption><p>Access Payout tab to start Stripe Onboarding process</p></figcaption></figure>

**2. Customers pay to Fungies, and then we distribute payments to your Stripe account**

We use Stripe Connect, which is a platform solution for merchants. End-users will pay to our Stripe account and then they'll get distributed automatically to your accounts.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FPz9xGchjqLMfts60PpCo%2Fimage.png?alt=media&amp;token=bb335bcf-8635-415f-b471-e5cf06120680" alt=""><figcaption><p>You will have access to your own Stripe Management Dashboard</p></figcaption></figure>

**3. You can execute payouts whenever you want**

Just log into the dashboard or go to your dedicated Stripe's payout dashboard.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FOF379SFbtanDxx7TT3Cd%2Fimage.png?alt=media&amp;token=83f853dc-2666-4d3c-b69f-1f3c6ba81f6c" alt=""><figcaption><p>You can initiate payout whenever you want or you can set automatic payouts every 24h to your Bank Account</p></figcaption></figure>


# Sandbox Mode

For now all Testing can be done using this URL: <https://app.stage.fungies.net/register>

Testing API is available here: <https://api.stage.fungies.net/v0/api-docs/>

Please note that all Products, Subscriptions, Stripe Payouts etc. are separate from Production (i.e. <https://app.fungies.io/>).

IMPORTANT: Although Sandbox mode of Dashboard works without any approval, Storefront/Checkout/Overlay need to ba approved. Send us an email [support@fungies.io](https://fungies.io/contact-us/) to get it approved and public.

Webhooks in Testing environment are also separate from Production.

List of Testing Cards are here: <https://docs.stripe.com/testing?testing-method=card-numbers>


# Team Management

You can invite your Team Members to the Workspace by choossing Settings -> Team in the Dashboard.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FZg7VEmTjL6MAt0cqoOCI%2Fimage.png?alt=media&amp;token=be2a8a46-5461-4df2-b200-ec939d9724ff" alt=""><figcaption><p>List of all members who have access to the workspace.</p></figcaption></figure>

You can add them by clicking Add Workspace Members. Upon clicking the button you'll get presented with all available options of access control. Choose between:

* Admin: controls all aspects of the Workspace including Payouts
* Manager
* Support: only sees Payments and Orders for Customer Support
* Developer
* Custom: Set up Read/Write access however you want

Invite members by typing their e-mails.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FZezuENH8ZPKjxLQlvxQR%2Fimage.png?alt=media&amp;token=afd825c0-4c1d-4ba9-b1ce-606d9969c5af" alt=""><figcaption><p>Choose how members will access the Workspace.</p></figcaption></figure>

See all pending invitations:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F9FRFWP5zLGC7pjkdZH4F%2Fimage.png?alt=media&amp;token=467a1ab7-1385-4fae-af68-8c0a23dafb30" alt=""><figcaption><p>Invitation statuses are shown in the 2nd Tab.</p></figcaption></figure>


# Email Notifications

You can switch On/Off email notifications for your customers or for your Workspace users in Settings -> Emails.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FfbuyMzIlLlZ5oC5uwNCZ%2FEmail%20Notifications.png?alt=media&amp;token=64157abf-2c03-42d6-b321-3621da2c807f" alt=""><figcaption></figcaption></figure>

### Default Notification Email

This setting allows you to specify a primary email address for receiving all workspace-related notifications. If you leave this field blank, all notifications will be sent to the email address of the workspace owner by default. This is useful for directing notifications to a specific inbox or team member responsible for monitoring your Fungies.io account activity.

### Transactional Emails

Fungies.io distinguishes between general transactional emails and critical account alerts to ensure you never miss important information.

#### All Transactional Emails

A master switch is available to enable or disable all payment and subscription notification emails at once. This provides a quick way to manage the bulk of your email notifications. However, it is important to note that critical alerts, such as password resets, email verifications, and security warnings, will always be sent regardless of this setting to ensure the security of your account.

#### Subscription Emails

You can fine-tune notifications for specific events throughout the subscription lifecycle. This allows you to stay informed about key customer activities and manage your subscriptions more effectively. The available toggles include:•Trial End Upcoming: Notifies customers before their free trial period expires.•Trial Ended: Informs customers that their trial period has concluded.•Subscription Canceled: Confirms that a customer's subscription has been successfully canceled.•Cancellation Requested: Alerts you when a customer has requested to cancel their subscription.•Subscription Updated: Notifies you or the customer when changes are made to a subscription plan.•Renewal Upcoming: Provides a reminder before a subscription is due for renewal.•Payment Action Required: Informs customers if any action is needed to process their payment.•Payment Succeeded: Confirms successful subscription payments.•Payment Failed: Notifies customers of failed subscription payments.

#### One-Time Payment Emails

For transactions that are not part of a recurring subscription, you can manage notifications for the following one-time payment events:•Payment Succeeded: Confirms that a one-time payment was successful.•Payment Failed: Notifies the customer if a one-time payment has failed.•Payment Refunded: Confirms that a refund has been processed for a one-time payment.By customizing these settings, you can tailor the email notifications from Fungies.io to best suit your workflow and communication preferences, ensuring that you and your customers receive the most relevant and timely information.


# Publish your store

Celebration time! Once you're ready to publish your store, head over to Settings -> General or to Website Builder -> Publish to Publish your Web Store!&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Foo00SvwQ2RoW0OpDHX2u%2Fimage.png?alt=media&amp;token=028b0092-3cc3-488e-a02a-f5d7659ae60c" alt=""><figcaption><p>Publish your Web Store from Website Builder, just click on the Green top-right button</p></figcaption></figure>

Now you Web Store will be visible to all the users on the World Wide Web!

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F5qpqbyP8P7CkTXj8DcAo%2Fimage.png?alt=media&amp;token=457e8542-7265-44f8-ad3d-c1902901edbb" alt=""><figcaption><p>Your Game's Web Store will now be publicly available!</p></figcaption></figure>


# Previewing The Store

If you want to limit the visibility of your store and do not want the public to access it, turn off "Public access" in Settings -> Store, like below:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FYbv2BxjxdXzSutVtoEcS%2Fimage.png?alt=media&amp;token=c1f7e383-4df8-483a-853b-bfaad1290cdb" alt=""><figcaption><p>Turn off Public Access if you don't wany anyone to see your store publicly</p></figcaption></figure>

Now if you want to see the store for yourself (without Public Access) - just click "Go To Store" at the top and you should be able to preview the store with special access token. The URL should contain "previewToken" inside the URL, like below:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FzJhKqUJGDTuwC8y6nwne%2Fimage.png?alt=media&amp;token=ef8ae934-4423-4831-8782-b65a08c7bbb7" alt=""><figcaption><p>Even you disable public access, you as the owner will still be able to access the store with special access token</p></figcaption></figure>

Now you can test out transactions and the look'n'feel of your store!


# Edit Explore / Search Page (Built-in)

Your store comes embedded with a fully-functioning Search feature:

* Search suggestion after typing in the Search Bar
* Filters by Tags / Genre / Platform / Type / Region
* Sorting by Price / Name
* Pagination of Search Results
* Quick "Add To Cart" on Product Thumbnails

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FH9Rku2KzHraiIChsOeFE%2Fimage.png?alt=media&amp;token=a45036cb-b865-4872-a682-9faa62b4fe01" alt=""><figcaption><p>Your store comes embedded with Search feature</p></figcaption></figure>

In order to Edit the filters on the left of Explore / Search, head to Store Builder and choose /Explore Built-in Page:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FabHdtQk03eVuWNDl7fDS%2Fimage.png?alt=media&amp;token=a4203dc7-44bd-4d8a-a225-5f7d8c3d2049" alt=""><figcaption><p>Choose Explore Built-in Page to Edit it in the Store Builder</p></figcaption></figure>

Now click "Edit" button in the Explore Page Filters section:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Frniz7MhG2ORvPbi3BTv5%2Fimage.png?alt=media&amp;token=a99882f2-0ac9-4bf1-96cd-4533961a80bc" alt=""><figcaption><p>Click "Edit" icon in the Page Filters Section</p></figcaption></figure>

Now you can freely edit this section of your Explore/Search pages:

* Drag and Drop filters to choose its position,
* Choose if the filters should be visible expanded or not,
* Turn on/off visibility of filters

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FfCkyYtrHcAanJwDKV1f0%2Fimage.png?alt=media&amp;token=f219da2f-cdac-4e68-8164-d94634e7362d" alt=""><figcaption><p>Edit how the filters will be have in your Explore/Search Built-in Page</p></figcaption></figure>


# Edit Product Page (Built-in)

Navigate to Product Page Built-in Page in the Store Builder to edit the default look of all Product Pages:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FJD7vWaqknFoPpXE8xmDj%2Fimage.png?alt=media&amp;token=4e4bfa55-d049-4c43-9391-cc976c501fcb" alt=""><figcaption><p>Choose Product Page from the list of Built-in Pages in Store Builder to edit it</p></figcaption></figure>

You can edit a few things here:

* You can turn On/Off Product Reviews - customers can write Reviews after logging into your store
* Turn On/Off Product Recommendation Engine - showing customers relevant products from your store
* Turn On/Off Ratings for your Product - the number of stars a product receives - these stars are compatible with Google Reviews and are visible on Search Engines

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FGJIdZBxIHUNPwvjVRWPF%2FScreenshot%202025-02-11%20162321.png?alt=media&amp;token=6b98e0bb-4b7a-4ec6-b22f-a26f19585639" alt=""><figcaption><p>Edit Sections of your Product Pages such as Recommended Products or Product Reviews</p></figcaption></figure>


# Customize Review Categories

Reviews are a great way to boost your sales. With our worldclass store builder, you can edit Review Categories for your Digital Products.

The Product Page that's visible to the end-users will show all reviews left by your logged-in customers.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FOGD22FwuAaR59fxheamB%2Fimage.png?alt=media&amp;token=3cdff471-97fb-43d6-9536-3564a28f5b33" alt=""><figcaption><p>Users that are have signed up to your store can leave reviews for your products</p></figcaption></figure>

If you want to edit the Review Categories, simly head to Store Builder in the Dashboard and navigate to Product Page (Built-In):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FWa6rcQf75XSoA5euvHAA%2Fimage.png?alt=media&amp;token=b9d04229-bd1b-4fc5-b25a-1bd871953e3c" alt=""><figcaption><p>Go to Product Page (Bult-In) inside the Store Builder</p></figcaption></figure>

Now choose Reviews Settings and pick from a pre-built list of categories. You can choose max. 5 categories for your Reviews.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fos7MoC8xtR71yPZCaSWw%2Fimage.png?alt=media&amp;token=d4fb61f6-033a-497d-9bb3-8b9653f1c8bf" alt=""><figcaption><p>Choose up to 5 categories for your Product Page reviews</p></figcaption></figure>


# Set up Custom Domain

You can publish your Web Store under your very own domain.

Go to Settings -> Domain on the left pane of the Dashboard:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FD4xcW3LIte4cWz3UHGjo%2Fimage.png?alt=media&amp;token=fb9a057a-5758-4776-9f92-2d172b74cf0e" alt=""><figcaption><p>You can set up your own custom domain in Domain settings</p></figcaption></figure>

You can set up your CNAME Records: just choose appropriate option and the settings will be shown.

AWS (our servers) sometimes have troubles with validating certificates.

If there is no CAA records then add new CAA record as on the images: with - **Only allow specific hostnames (instead od Name "pay" put in your subdomain or @** if it's root domain)**:**

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FkDv0Mo9ewF5VjdHeDS78%2Fimage.png?alt=media&amp;token=9ee4b1a5-c813-43cf-8628-c5f035281d4c" alt=""><figcaption></figcaption></figure>


# Migrating your domain to Cloudflare

From 14th October 2024 it will be mandatory for your domain to be moved to Cloudflare for anti-DDOS protection.

In order to use Custom Domain (with root domain like e.g. domain.com, yoursite.com, saasstartup.io etc.) you will have to move your entire DNS settings to Cloudfare.

1. First, set up an account with [Cloudflare](https://dash.cloudflare.com/sign-up):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FQVf6UT4kbFxIdsUQKiYm%2Fimage.png?alt=media&amp;token=cab79a24-0656-4c3b-9d91-d26da13c85d6" alt=""><figcaption><p>Sign up with Cloudflare</p></figcaption></figure>

2. Navigate to Websites and then Add Domain

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FeAGVXIK8SOwajMjZjPM1%2Fimage.png?alt=media&amp;token=51aa9f25-9f41-4dbb-b4da-5f3ca7ddebbf" alt=""><figcaption><p>Add or migrate your domain to Cloudflare</p></figcaption></figure>

3. Type or paste your root domain here (like e.g. mystartup.com or mywebsite.io)

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FOpoQYNn3qmCY33y4vSH7%2Fimage.png?alt=media&amp;token=39d9a3b5-591f-4d3a-bf74-f96510c2c6d5" alt=""><figcaption><p>Type or paste your root domain for Cloudflare to automatically detect DNS settings</p></figcaption></figure>

4. Select a FREE plan when prompted

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FdD9U5uaalg4yaOVkOP5u%2Fimage.png?alt=media&amp;token=9a0c7902-cf58-4e6e-a6e6-20010e8b568b" alt=""><figcaption><p>Choose FREE Plan for DDOS protection</p></figcaption></figure>

5. Continue set up after automatic DNS settings detection by Cloudflare

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FBtgxvE1nfbPBtxezd2iv%2Fimage.png?alt=media&amp;token=d1c17917-43a3-4571-9aa1-da864aa27151" alt=""><figcaption><p>Copy both these nameservers to your domain registrar (like GoDaddy.com)</p></figcaption></figure>

Copy these 2 nameservers to your domain registrar - you must REMOVE any other nameserver (NS) settings and just leave these 2 from Cloudfare

6. You will now see pending nameserver updates in the list of your websites

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FF5hEvg220G68ensK32yB%2Fimage.png?alt=media&amp;token=dd20d403-62f8-459f-b1a2-94568f77905c" alt=""><figcaption><p>Now you need to paste the nameservers in your registrar domain settings</p></figcaption></figure>

6. Add both Nameservers provided by Cloudflare above

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FGWMqlSFT1nd3bQPdJzDK%2Fimage.png?alt=media&amp;token=ada7ba54-64bb-4236-b948-f98615c9fb2d" alt=""><figcaption><p>Change the nameservers provided by CloudFlare</p></figcaption></figure>

7. Now you should wait for Cloudflare to propagate DNS settings for your domain:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FXY9Sgv8mJeJ51LvV3z5N%2Fimage.png?alt=media&amp;token=eec2377d-0a57-4da6-a0ef-d89551fa3bc6" alt=""><figcaption><p>Wait up to 24h for Cloudflare to propagate DNS settings for your Root domain</p></figcaption></figure>

8. Go back to Fungies.io Dashboard under Settings -> Domain

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FXXTOwPEjBSiq2snmBUnM%2Fimage.png?alt=media&amp;token=053b9d14-314f-4cab-8f77-53f195c4cfc4" alt=""><figcaption><p>Copy and paste these DNS settings to your CloudFlare DNS settings</p></figcaption></figure>

9. Copy Fungies DNS settings to your CloudFlare DNS settings

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FgUjVUckxOauABBCtVCPp%2Fimage.png?alt=media&amp;token=36f6545f-3229-463a-852e-d23d1148e48c" alt=""><figcaption><p>Finish up by pasting DNS records from Fungies.io Dashboard to CloudFlare DNS settings for the domain</p></figcaption></figure>


# Tax-inclusive Pricing

You can set Tax-inclusive prices for your entire Workspace. This means that ANY product you put in your store will now be inclusive of taxes - meaning that what you put in the price is what customers pay in the end.

Without Tax-inclusive pricing (Tax-excluded prices) - the price you put for your products are not final and will be recalculated at checkout to add Taxes on top of that price.

Your income: your payout / income

Subtotal: price without taxes

Total: price with taxes

Taxes: VAT/GST/IST the amount varies between countries and states inside the US

Fungies Fee: 5%+$0.5 per transaction

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FPPonqVgei14fXeHAj6cf%2Fimage.png?alt=media&amp;token=4ba3c256-fc57-447a-bcc9-86cfa8d7b243" alt=""><figcaption><p>Set up Tax-inclusive pricing in General Settings of your workspace</p></figcaption></figure>

In below Product Pages, one is set with Tax-inslusive pricing, the other is Tax-excluded.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FJKhS1hGWNpZ3u7QJTGow%2Fimage.png?alt=media&amp;token=71b59c12-e56e-473f-b034-e68585200c89" alt=""><figcaption><p>Product Page AFTER turning on Tax-inclusive Pricing</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FyaAjuHC5Q38MiCWIlizO%2Fimage.png?alt=media&amp;token=9f0f19e5-62f6-4128-9651-e3dcf40d137a" alt=""><figcaption><p>Product Page BEFORE turning on Tax-inclusive Pricing (this example shows Tax-excluded price). The price is not final.</p></figcaption></figure>

During checkout, depending on which option you set up in your settings, Taxes will be recalculated to reflect the setting.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FtLA8DZkKaR2dONI2ABOC%2Fimage.png?alt=media&amp;token=6bc5a4fe-acd0-4e66-a782-ab467eee2606" alt=""><figcaption><p>In this example, the store setting is set to Exclude taxes in the final price, so the VAT/GST/IST is added ON-TOP of product price.</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FVvV7kBQtEamycpMbYsPv%2Fimage.png?alt=media&amp;token=f6cb71f2-5b08-4d65-92dc-b09011bc5dd4" alt=""><figcaption><p>Tax-include Price: the price already includes VAT/GST tax - so the Product Price = the amount the customer pays. The VAT/GST/IST tax amount will be flexible depending on where your customer is located.</p></figcaption></figure>

You can then of course preview the amounts in Order Confirmation / Payment Details:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FD1jeySasorso1Cjk8OYD%2Fimage.png?alt=media&amp;token=c026b823-2e5d-4c0d-9b3e-73f5d901b62f" alt=""><figcaption><p>In Tax-excluded pricing, the Tax is added to the Subtotal to get the Total amount</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F3X0Dd70VSFaG1VCiIcrm%2Fimage.png?alt=media&amp;token=e0ac3643-1fe0-41b1-9288-49fed75ef675" alt=""><figcaption><p>In Tax-inclusive pricing, the Total is paid by the user and already includes VAT/GST/IST.</p></figcaption></figure>


# Test Payments

Simulate payments to test your integration.

Simulate payments to test your integration.

\
To confirm that your integration works correctly, simulate transactions without moving any money using special values in test mode.

Test cards let you simulate several scenarios:

* Successful payments by card brand or country
* Card errors due to declines, fraud, or invalid data
* Disputes and refunds
* Authentication with 3D Secure and PINs

Testing non-card payments works similarly. Each payment method has its own special values. Because of rate limits, we don’t recommend using test mode to load-test your integration. Instead, see our documentation on load testing.

### How to use test cards![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#use-test-cards" id="use-test-cards"></a>

Any time you work with a test card - it has to be used in Test Mode / Sandbox Mode. This is true whether you’re serving a payment form to test interactively or writing test code.

**Common mistake**

Don’t use real card details. Use your test API keys and the card numbers below.

#### Testing interactively![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#testing-interactively" id="testing-interactively"></a>

When testing interactively, use a card number, such as 4242 4242 4242 4242. Enter the card number in the Dashboard or in any payment form.

* Use a valid future date, such as **12/34**.
* Use any three-digit CVC (four digits for American Express cards).
* Use any value you like for other form fields.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FAa0ZXLA45WkNBlEcWBsX%2Ftest-card.c3f9b3d1a3e8caca3c9f4c9c481fd49c.jpg?alt=media&amp;token=1c989ec6-473e-464b-b284-d1611419cb02" alt=""><figcaption><p>Testing a form interactively with the test card number 4242 4242 4242 4242</p></figcaption></figure>

**Test code**

When writing test code, use a `PaymentMethod` such as [pm\_card\_visa](https://docs.stripe.com/testing?testing-method=payment-methods#visa) instead of a card number. We don’t recommend using card numbers directly in API calls or server-side code, even in test mode. If you do use them, your code might not be PCI-compliant when you go live. By default, a `PaymentMethod` isn’t attached to a [Customer](https://docs.stripe.com/api/customers).

Most integrations don’t use Tokens any more, but we make test Tokens such as [tok\_visa](https://docs.stripe.com/testing?testing-method=tokens#visa) available if you need them.

When you’re ready to take your integration live, replace your test publishable and secret [API keys](https://docs.stripe.com/keys) with live ones. You can’t process live payments if your integration is still using your test API keys.

### Cards by brand![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#cards" id="cards"></a>

To simulate a successful payment for a specific card brand, use test cards from the following list.

**Caution**

Cross-border fees are assessed based on the country of the card issuer. Cards where the issuer country isn’t the US (such as JCB and UnionPay) might be subject to a cross-border fee, even in test mode.

\
Card Numbers

{% tabs %}
{% tab title="Card numbers" %}

<table><thead><tr><th>BRAND</th><th width="284">NUMBER</th><th>CVC</th><th>DATE</th></tr></thead><tbody><tr><td>Visa</td><td>4242 4242 4242 4242</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Visa (debit)</td><td>4000 0566 5566 5556</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Mastercard</td><td>5555 5555 5555 4444</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Mastercard (2-series)</td><td>2223 0031 2200 3222</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Mastercard (debit)</td><td>5200 8282 8282 8210</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Mastercard (prepaid)</td><td>5105 1051 0510 5100</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>American Express</td><td>3782 822463 10005</td><td>Any 4 digits</td><td>Any future date</td></tr><tr><td>American Express</td><td>3714 496353 98431</td><td>Any 4 digits</td><td>Any future date</td></tr><tr><td>Discover</td><td>6011 1111 1111 1117</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Discover</td><td>6011 0009 9013 9424</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Discover (debit)</td><td>6011 9811 1111 1113</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Diners Club</td><td>3056 9300 0902 0004</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Diners Club (14-digit card)</td><td>3622 720627 1667</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>BCcard and DinaCard</td><td>6555 9000 0060 4105</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>JCB</td><td>3566 0020 2036 0505</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>UnionPay</td><td>6200 0000 0000 0005</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>UnionPay (debit)</td><td>6200 0000 0000 0047</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>UnionPay (19-digit card)</td><td>6205 5000 0000 0000 004</td><td>Any 3 digits</td><td>Any future date</td></tr></tbody></table>
{% endtab %}

{% tab title="PaymentMethods" %}

| BRAND                | PAYMENTMETHOD                 |
| -------------------- | ----------------------------- |
| Visa                 | pm\_card\_visa                |
| Visa (debit)         | pm\_card\_visa\_debit         |
| Mastercard           | pm\_card\_mastercard          |
| Mastercard (debit)   | pm\_card\_mastercard\_debit   |
| Mastercard (prepaid) | pm\_card\_mastercard\_prepaid |
| American Express     | pm\_card\_amex                |
| Discover             | pm\_card\_discover            |
| Diners Club          | pm\_card\_diners              |
| JCB                  | pm\_card\_jcb                 |
| UnionPay             | pm\_card\_unionpay            |

{% endtab %}

{% tab title="Tokens" %}

| BRAND                | TOKEN                    |
| -------------------- | ------------------------ |
| Visa                 | tok\_visa                |
| Visa (debit)         | tok\_visa\_debit         |
| Mastercard           | tok\_mastercard          |
| Mastercard (debit)   | tok\_mastercard\_debit   |
| Mastercard (prepaid) | tok\_mastercard\_prepaid |
| American Express     | tok\_amex                |
| Discover             | tok\_discover            |
| Diners Club          | tok\_diners              |
| JCB                  | tok\_jcb                 |
| UnionPay             | tok\_unionpay            |
| {% endtab %}         |                          |
| {% endtabs %}        |                          |

Most Cartes Bancaires and eftpos cards are co-branded with either Visa or Mastercard. The test cards in the following table simulate successful payments with co-branded cards.

{% tabs %}
{% tab title="Card numbers" %}

<table><thead><tr><th width="218">BRAND/CO-BRAND</th><th width="215">NUMBER</th><th>CVC</th><th>DATE</th></tr></thead><tbody><tr><td>Cartes Bancaires/Visa</td><td>4000 0025 0000 1001</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>Cartes Bancaires/Mastercard</td><td>5555 5525 0000 1001</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>eftpos Australia/Visa</td><td>4000 0503 6000 0001</td><td>Any 3 digits</td><td>Any future date</td></tr><tr><td>eftpos Australia/Mastercard</td><td>5555 0503 6000 0080</td><td>Any 3 digits</td><td>Any future date</td></tr></tbody></table>
{% endtab %}

{% tab title="PaymentMethods" %}

| BRAND                       | PAYMENTMETHOD                                  |
| --------------------------- | ---------------------------------------------- |
| Cartes Bancaires/Visa       | pm\_card\_visa\_cartesBancaires                |
| Cartes Bancaires/Mastercard | pm\_card\_mastercard\_cartesBancaires          |
| eftpos Australia/Visa       | pm\_card\_visa\_debit\_eftposAuCoBranded       |
| eftpos Australia/Mastercard | pm\_card\_mastercard\_debit\_eftposAuCoBranded |

{% endtab %}

{% tab title="Tokens" %}

| BRAND                       | TOKEN                                     |
| --------------------------- | ----------------------------------------- |
| Cartes Bancaires/Visa       | tok\_visa\_cartesBancaires                |
| Cartes Bancaires/Mastercard | tok\_mastercard\_cartesBancaires          |
| eftpos Australia/Visa       | tok\_visa\_debit\_eftposAuCoBranded       |
| eftpos Australia/Mastercard | tok\_mastercard\_debit\_eftposAuCoBranded |

{% endtab %}
{% endtabs %}

### Cards by Country

To simulate successful payments from specific countries, use test cards from the following sections.

{% tabs %}
{% tab title="Card numbers" %}
**AMERICAS**

| COUNTRY            | NUMBER              | BRAND  |
| ------------------ | ------------------- | ------ |
| United States (US) | 4242 4242 4242 4242 | Visa   |
| Argentina (AR)     | 4000 0003 2000 0021 | Visa   |
| Brazil (BR)        | 4000 0007 6000 0002 | Visa   |
| Canada (CA)        | 4000 0012 4000 0000 | Visa   |
| Chile (CL)         | 4000 0015 2000 0001 | Visa   |
| Colombia (CO)      | 4000 0017 0000 0003 | Visa   |
| Costa Rica (CR)    | 4000 0018 8000 0005 | Visa   |
| Ecuador (EC)       | 4000 0021 8000 0000 | Visa   |
| Mexico (MX)        | 4000 0048 4000 8001 | Visa   |
| Mexico (MX)        | 5062 2100 0000 0009 | Carnet |
| Panama (PA)        | 4000 0059 1000 0000 | Visa   |
| Paraguay (PY)      | 4000 0060 0000 0066 | Visa   |
| Peru (PE)          | 4000 0060 4000 0068 | Visa   |
| Uruguay (UY)       | 4000 0085 8000 0003 | Visa   |
| {% endtab %}       |                     |        |

{% tab title="PaymentMethods" %}
**AMERICAS**

<table data-full-width="false"><thead><tr><th>COUNTRY</th><th>PAYMENTMETHOD</th><th>BRAND</th></tr></thead><tbody><tr><td>United States (US)</td><td>pm_card_us</td><td>Visa</td></tr><tr><td>Argentina (AR)</td><td>pm_card_ar</td><td>Visa</td></tr><tr><td>Brazil (BR)</td><td>pm_card_br</td><td>Visa</td></tr><tr><td>Canada (CA)</td><td>pm_card_ca</td><td>Visa</td></tr><tr><td>Chile (CL)</td><td>pm_card_cl</td><td>Visa</td></tr><tr><td>Colombia (CO)</td><td>pm_card_co</td><td>Visa</td></tr><tr><td>Costa Rica (CR)</td><td>pm_card_cr</td><td>Visa</td></tr><tr><td>Ecuador (EC)</td><td>pm_card_ec</td><td>Visa</td></tr><tr><td>Mexico (MX)</td><td>pm_card_mx</td><td>Visa</td></tr><tr><td>Panama (PA)</td><td>pm_card_pa</td><td>Visa</td></tr><tr><td>Paraguay (PY)</td><td>pm_card_py</td><td>Visa</td></tr><tr><td>Peru (PE)</td><td>pm_card_pe</td><td>Visa</td></tr><tr><td>Uruguay (UY)</td><td>pm_card_uy</td><td>Visa</td></tr></tbody></table>

{% endtab %}

{% tab title="Tokens" %}
**AMERICAS**

| COUNTRY            | TOKEN   | BRAND |
| ------------------ | ------- | ----- |
| United States (US) | tok\_us | Visa  |
| Argentina (AR)     | tok\_ar | Visa  |
| Brazil (BR)        | tok\_br | Visa  |
| Canada (CA)        | tok\_ca | Visa  |
| Chile (CL)         | tok\_cl | Visa  |
| Colombia (CO)      | tok\_co | Visa  |
| Costa Rica (CR)    | tok\_cr | Visa  |
| Ecuador (EC)       | tok\_ec | Visa  |
| Mexico (MX)        | tok\_mx | Visa  |
| Panama (PA)        | tok\_pa | Visa  |
| Paraguay (PY)      | tok\_py | Visa  |
| Peru (PE)          | tok\_pe | Visa  |
| Uruguay (UY)       | tok\_uy | Visa  |
| {% endtab %}       |         |       |
| {% endtabs %}      |         |       |

{% tabs %}
{% tab title="Card numbers" %}
**EUROPE and MIDDLE EAST**

**Security tip**

Strong Customer Authentication regulations require 3D Secure authentication for online payments within the European Economic Area. The test cards in this section simulate a payment that succeeds without authentication. We recommend also testing scenarios that involve authentication, using 3D Secure test cards.

| United Arab Emirates (AE) | 4000 0078 4000 0001 | Visa         |
| ------------------------- | ------------------- | ------------ |
| United Arab Emirates (AE) | 5200 0078 4000 0022 | Mastercard   |
| Austria (AT)              | 4000 0004 0000 0008 | Visa         |
| Belgium (BE)              | 4000 0005 6000 0004 | Visa         |
| Bulgaria (BG)             | 4000 0010 0000 0000 | Visa         |
| Belarus (BY)              | 4000 0011 2000 0005 | Visa         |
| Croatia (HR)              | 4000 0019 1000 0009 | Visa         |
| Cyprus (CY)               | 4000 0019 6000 0008 | Visa         |
| Czech Republic (CZ)       | 4000 0020 3000 0002 | Visa         |
| Denmark (DK)              | 4000 0020 8000 0001 | Visa         |
| Estonia (EE)              | 4000 0023 3000 0009 | Visa         |
| Finland (FI)              | 4000 0024 6000 0001 | Visa         |
| France (FR)               | 4000 0025 0000 0003 | Visa         |
| Germany (DE)              | 4000 0027 6000 0016 | Visa         |
| Gibraltar (GI)            | 4000 0029 2000 0005 | Visa         |
| Greece (GR)               | 4000 0030 0000 0030 | Visa         |
| Hungary (HU)              | 4000 0034 8000 0005 | Visa         |
| Ireland (IE)              | 4000 0037 2000 0005 | Visa         |
| Italy (IT)                | 4000 0038 0000 0008 | Visa         |
| Latvia (LV)               | 4000 0042 8000 0005 | Visa         |
| Liechtenstein (LI)        | 4000 0043 8000 0004 | Visa         |
| Lithuania (LT)            | 4000 0044 0000 0000 | Visa         |
| Luxembourg (LU)           | 4000 0044 2000 0006 | Visa         |
| Malta (MT)                | 4000 0047 0000 0007 | Visa         |
| Netherlands (NL)          | 4000 0052 8000 0002 | Visa         |
| Norway (NO)               | 4000 0057 8000 0007 | Visa         |
| Poland (PL)               | 4000 0061 6000 0005 | Visa         |
| Portugal (PT)             | 4000 0062 0000 0007 | Visa         |
| Romania (RO)              | 4000 0064 2000 0001 | Visa         |
| Saudi Arabia (SA)         | 4000 0068 2000 0007 | Visa         |
| Slovenia (SI)             | 4000 0070 5000 0006 | Visa         |
| Slovakia (SK)             | 4000 0070 3000 0001 | Visa         |
| Spain (ES)                | 4000 0072 4000 0007 | Visa         |
| Sweden (SE)               | 4000 0075 2000 0008 | Visa         |
| Switzerland (CH)          | 4000 0075 6000 0009 | Visa         |
| United Kingdom (GB)       | 4000 0082 6000 0000 | Visa         |
| United Kingdom (GB)       | 4000 0582 6000 0005 | Visa (debit) |
| United Kingdom (GB)       | 5555 5582 6555 4449 | Mastercard   |
| {% endtab %}              |                     |              |

{% tab title="PaymentMethods" %}
**EUROPE and MIDDLE EAST**

**Security tip**

[Strong Customer Authentication](https://docs.stripe.com/strong-customer-authentication) regulations require [3D Secure](https://docs.stripe.com/payments/3d-secure) authentication for online payments within the [European Economic Area](https://en.wikipedia.org/wiki/European_Economic_Area). The test cards in this section simulate a payment that succeeds without authentication. We recommend also testing scenarios that involve authentication, using [3D Secure test cards](https://docs.stripe.com/testing#regulatory-cards).

| United Arab Emirates (AE) | pm\_card\_ae             | Visa         |
| ------------------------- | ------------------------ | ------------ |
| United Arab Emirates (AE) | pm\_card\_ae\_mastercard | Mastercard   |
| Austria (AT)              | pm\_card\_at             | Visa         |
| Belgium (BE)              | pm\_card\_be             | Visa         |
| Bulgaria (BG)             | pm\_card\_bg             | Visa         |
| Belarus (BY)              | pm\_card\_by             | Visa         |
| Croatia (HR)              | pm\_card\_hr             | Visa         |
| Cyprus (CY)               | pm\_card\_cy             | Visa         |
| Czech Republic (CZ)       | pm\_card\_cz             | Visa         |
| Denmark (DK)              | pm\_card\_dk             | Visa         |
| Estonia (EE)              | pm\_card\_ee             | Visa         |
| Finland (FI)              | pm\_card\_fi             | Visa         |
| France (FR)               | pm\_card\_fr             | Visa         |
| Germany (DE)              | pm\_card\_de             | Visa         |
| Gibraltar (GI)            | pm\_card\_gi             | Visa         |
| Greece (GR)               | pm\_card\_gr             | Visa         |
| Hungary (HU)              | pm\_card\_hu             | Visa         |
| Ireland (IE)              | pm\_card\_ie             | Visa         |
| Italy (IT)                | pm\_card\_it             | Visa         |
| Latvia (LV)               | pm\_card\_lv             | Visa         |
| Liechtenstein (LI)        | pm\_card\_li             | Visa         |
| Lithuania (LT)            | pm\_card\_lt             | Visa         |
| Luxembourg (LU)           | pm\_card\_lu             | Visa         |
| Malta (MT)                | pm\_card\_mt             | Visa         |
| Netherlands (NL)          | pm\_card\_nl             | Visa         |
| Norway (NO)               | pm\_card\_no             | Visa         |
| Poland (PL)               | pm\_card\_pl             | Visa         |
| Portugal (PT)             | pm\_card\_pt             | Visa         |
| Romania (RO)              | pm\_card\_ro             | Visa         |
| Slovenia (SI)             | pm\_card\_si             | Visa         |
| Slovakia (SK)             | pm\_card\_sk             | Visa         |
| Spain (ES)                | pm\_card\_es             | Visa         |
| Sweden (SE)               | pm\_card\_se             | Visa         |
| Switzerland (CH)          | pm\_card\_ch             | Visa         |
| United Kingdom (GB)       | pm\_card\_gb             | Visa         |
| United Kingdom (GB)       | pm\_card\_gb\_debit      | Visa (debit) |
| United Kingdom (GB)       | pm\_card\_gb\_mastercard | Mastercard   |
| {% endtab %}              |                          |              |

{% tab title="Tokens" %}
**EUROPE and MIDDLE EAST**

**Security tip**

[Strong Customer Authentication](https://docs.stripe.com/strong-customer-authentication) regulations require [3D Secure](https://docs.stripe.com/payments/3d-secure) authentication for online payments within the [European Economic Area](https://en.wikipedia.org/wiki/European_Economic_Area). The test cards in this section simulate a payment that succeeds without authentication. We recommend also testing scenarios that involve authentication, using [3D Secure test cards](https://docs.stripe.com/testing#regulatory-cards).

| United Arab Emirates (AE) | tok\_ae             | Visa         |
| ------------------------- | ------------------- | ------------ |
| United Arab Emirates (AE) | tok\_ae\_mastercard | Mastercard   |
| Austria (AT)              | tok\_at             | Visa         |
| Belgium (BE)              | tok\_be             | Visa         |
| Bulgaria (BG)             | tok\_bg             | Visa         |
| Belarus (BY)              | tok\_by             | Visa         |
| Croatia (HR)              | tok\_hr             | Visa         |
| Cyprus (CY)               | tok\_cy             | Visa         |
| Czech Republic (CZ)       | tok\_cz             | Visa         |
| Denmark (DK)              | tok\_dk             | Visa         |
| Estonia (EE)              | tok\_ee             | Visa         |
| Finland (FI)              | tok\_fi             | Visa         |
| France (FR)               | tok\_fr             | Visa         |
| Germany (DE)              | tok\_de             | Visa         |
| Gibraltar (GI)            | tok\_gi             | Visa         |
| Greece (GR)               | tok\_gr             | Visa         |
| Hungary (HU)              | tok\_hu             | Visa         |
| Ireland (IE)              | tok\_ie             | Visa         |
| Italy (IT)                | tok\_it             | Visa         |
| Latvia (LV)               | tok\_lv             | Visa         |
| Liechtenstein (LI)        | tok\_li             | Visa         |
| Lithuania (LT)            | tok\_lt             | Visa         |
| Luxembourg (LU)           | tok\_lu             | Visa         |
| Malta (MT)                | tok\_mt             | Visa         |
| Netherlands (NL)          | tok\_nl             | Visa         |
| Norway (NO)               | tok\_no             | Visa         |
| Poland (PL)               | tok\_pl             | Visa         |
| Portugal (PT)             | tok\_pt             | Visa         |
| Romania (RO)              | tok\_ro             | Visa         |
| Slovenia (SI)             | tok\_si             | Visa         |
| Slovakia (SK)             | tok\_sk             | Visa         |
| Spain (ES)                | tok\_es             | Visa         |
| Sweden (SE)               | tok\_se             | Visa         |
| Switzerland (CH)          | tok\_ch             | Visa         |
| United Kingdom (GB)       | tok\_gb             | Visa         |
| United Kingdom (GB)       | tok\_gb\_debit      | Visa (debit) |
| United Kingdom (GB)       | tok\_gb\_mastercard | Mastercard   |
| {% endtab %}              |                     |              |
| {% endtabs %}             |                     |              |

{% tabs %}
{% tab title="Card numbers" %}
**ASIA PACIFIC** ²

**Regional considerations | India**

To test subscriptions that require mandates and pre-debit notifications, see India recurring payments.

| Australia (AU)   | 4000 0003 6000 0006 | Visa          |
| ---------------- | ------------------- | ------------- |
| China (CN)       | 4000 0015 6000 0002 | Visa          |
| Hong Kong (HK)   | 4000 0034 4000 0004 | Visa          |
| India (IN)       | 4000 0035 6000 0008 | Visa          |
| Japan (JP)       | 4000 0039 2000 0003 | Visa          |
| Japan (JP)       | 3530 1113 3330 0000 | JCB           |
| Malaysia (my)    | 4000 0045 8000 0002 | Visa          |
| New Zealand (NZ) | 4000 0055 4000 0008 | Visa          |
| Singapore (SG)   | 4000 0070 2000 0003 | Visa          |
| Taiwan (TW)      | 4000 0015 8000 0008 | Visa          |
| Thailand (TH)    | 4000 0076 4000 0003 | Visa (credit) |
| Thailand (TH)    | 4000 0576 4000 0008 | Visa (debit)  |
| {% endtab %}     |                     |               |

{% tab title="PaymentMethods" %}
**ASIA PACIFIC** ²

**Regional considerations | India**

To test subscriptions that require mandates and pre-debit notifications, see [India recurring payments](https://docs.stripe.com/india-recurring-payments?integration=paymentIntents-setupIntents#testing).

| Australia (AU)   | pm\_card\_au         | Visa          |
| ---------------- | -------------------- | ------------- |
| China (CN)       | pm\_card\_cn         | Visa          |
| Hong Kong (HK)   | pm\_card\_hk         | Visa          |
| India (IN)       | pm\_card\_in         | Visa          |
| Japan (JP)       | pm\_card\_jp         | Visa          |
| Japan (JP)       | pm\_card\_jcb        | JCB           |
| Malaysia (my)    | pm\_card\_my         | Visa          |
| New Zealand (NZ) | pm\_card\_nz         | Visa          |
| Singapore (SG)   | pm\_card\_sg         | Visa          |
| Taiwan (TW)      | pm\_card\_tw         | Visa          |
| Thailand (TH)    | pm\_card\_th\_credit | Visa (credit) |
| Thailand (TH)    | pm\_card\_th\_debit  | Visa (debit)  |
| {% endtab %}     |                      |               |

{% tab title="Tokens" %}
**ASIA PACIFIC** ²

**Regional considerations | India**

To test subscriptions that require mandates and pre-debit notifications, see [India recurring payments](https://docs.stripe.com/india-recurring-payments?integration=paymentIntents-setupIntents#testing).

| Australia (AU)   | tok\_au         | Visa          |
| ---------------- | --------------- | ------------- |
| China (CN)       | tok\_cn         | Visa          |
| Hong Kong (HK)   | tok\_hk         | Visa          |
| India (IN)       | tok\_in         | Visa          |
| Japan (JP)       | tok\_jp         | Visa          |
| Japan (JP)       | tok\_jcb        | JCB           |
| Malaysia (my)    | tok\_my         | Visa          |
| New Zealand (NZ) | tok\_nz         | Visa          |
| Singapore (SG)   | tok\_sg         | Visa          |
| Taiwan (TW)      | tok\_tw         | Visa          |
| Thailand (TH)    | tok\_th\_credit | Visa (credit) |
| Thailand (TH)    | tok\_th\_debit  | Visa (debit)  |
| {% endtab %}     |                 |               |
| {% endtabs %}    |                 |               |

### Declined payments![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#declined-payments" id="declined-payments"></a>

To test your integration’s error-handling logic by simulating payments that the issuer declines for various reasons, use test cards from this section. Using one of these cards results in a [card error](https://docs.stripe.com/error-handling#payment-errors) with the given error code and decline code.

**Common mistake**

To simulate an incorrect CVC, you must provide one using any three-digit number. If you don’t provide a CVC, Stripe doesn’t perform the CVC check, so the check can’t fail.

{% tabs %}
{% tab title="Card numbers" %}

| DESCRIPTION                      | NUMBER              | ERROR CODE        | DECLINE CODE             |
| -------------------------------- | ------------------- | ----------------- | ------------------------ |
| Generic decline                  | 4000 0000 0000 0002 | card\_declined    | generic\_decline         |
| Insufficient funds decline       | 4000 0000 0000 9995 | card\_declined    | insufficient\_funds      |
| Lost card decline                | 4000 0000 0000 9987 | card\_declined    | lost\_card               |
| Stolen card decline              | 4000 0000 0000 9979 | card\_declined    | stolen\_card             |
| Expired card decline             | 4000 0000 0000 0069 | expired\_card     | n/a                      |
| Incorrect CVC decline            | 4000 0000 0000 0127 | incorrect\_cvc    | n/a                      |
| Processing error decline         | 4000 0000 0000 0119 | processing\_error | n/a                      |
| Incorrect number decline         | 4242 4242 4242 4241 | incorrect\_number | n/a                      |
| Exceeding velocity limit decline | 4000 0000 0000 6975 | card\_declined    | card\_velocity\_exceeded |

The cards in the previous table can’t be attached to a Customer object. To simulate a declined payment with a successfully attached card, use the next one.

| DESCRIPTION             | PAYMENTMETHOD       | DETAILS                                                                                                                               |
| ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Decline after attaching | 4000 0000 0000 0341 | Attaching this card to a [Customer](https://docs.stripe.com/api/customers) object succeeds, but attempts to charge the customer fail. |
| {% endtab %}            |                     |                                                                                                                                       |

{% tab title="Payment Method" %}

<table data-full-width="false"><thead><tr><th>DESCRIPTION</th><th width="316">NUMBER</th><th width="148">ERROR CODE</th><th>DECLINE CODE</th></tr></thead><tbody><tr><td>Generic decline</td><td>pm_card_visa_chargeDeclined</td><td>card_declined</td><td>generic_decline</td></tr><tr><td>Insufficient funds decline</td><td><p>pm_card_visa_</p><p>chargeDeclinedInsufficientFunds</p></td><td>card_declined</td><td>insufficient_funds</td></tr><tr><td>Lost card decline</td><td>pm_card_visa_chargeDeclinedLostCard</td><td>card_declined</td><td>lost_card</td></tr><tr><td>Stolen card decline</td><td>pm_card_visa_chargeDeclinedStolenCard</td><td>card_declined</td><td>stolen_card</td></tr><tr><td>Expired card decline</td><td>pm_card_chargeDeclinedExpiredCard</td><td>expired_card</td><td>n/a</td></tr><tr><td>Incorrect CVC decline</td><td>pm_card_chargeDeclinedIncorrectCvc</td><td>incorrect_cvc</td><td>n/a</td></tr><tr><td>Processing error decline</td><td>pm_card_chargeDeclinedProcessingError</td><td>processing_error</td><td>n/a</td></tr><tr><td>Exceeding velocity limit decline</td><td>pm_card_visa_chargeDeclinedVelocityLimitExceeded</td><td>card_declined</td><td>card_velocity_exceeded</td></tr></tbody></table>

The cards in the previous table can’t be attached to a Customer object. To simulate a declined payment with a successfully attached card, use the next one.

| DESCRIPTION             | NUMBER                                     | DETAILS                                                                                                                               |
| ----------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| Decline after attaching | <p>pm\_card\_</p><p>chargeCustomerFail</p> | Attaching this card to a [Customer](https://docs.stripe.com/api/customers) object succeeds, but attempts to charge the customer fail. |
| {% endtab %}            |                                            |                                                                                                                                       |

{% tab title="Tokens" %}

| DESCRIPTION                      | NUMBER                                                       | ERROR CODE        | DECLINE CODE             |
| -------------------------------- | ------------------------------------------------------------ | ----------------- | ------------------------ |
| Generic decline                  | tok\_visa\_chargeDeclined                                    | card\_declined    | generic\_decline         |
| Insufficient funds decline       | <p>tok\_visa\_</p><p>chargeDeclinedInsufficientFunds</p>     | card\_declined    | insufficient\_funds      |
| Lost card decline                | tok\_visa\_chargeDeclinedLostCard                            | card\_declined    | lost\_card               |
| Stolen card decline              | tok\_visa\_chargeDeclinedStolenCard                          | card\_declined    | stolen\_card             |
| Expired card decline             | tok\_chargeDeclinedExpiredCard                               | expired\_card     | n/a                      |
| Incorrect CVC decline            | tok\_chargeDeclinedIncorrectCvc                              | incorrect\_cvc    | n/a                      |
| Processing error decline         | tok\_chargeDeclinedProcessingError                           | processing\_error | n/a                      |
| Exceeding velocity limit decline | <p>tok\_visa\_</p><p>chargeDeclinedVelocityLimitExceeded</p> | card\_declined    | card\_velocity\_exceeded |

The cards in the previous table can’t be attached to a Customer object. To simulate a declined payment with a successfully attached card, use the next one.

| DESCRIPTION             | TOKEN                                 | DETAILS                                                                                                                               |
| ----------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Decline after attaching | <p>tok\_</p><p>chargeCustomerFail</p> | Attaching this card to a [Customer](https://docs.stripe.com/api/customers) object succeeds, but attempts to charge the customer fail. |
| {% endtab %}            |                                       |                                                                                                                                       |
| {% endtabs %}           |                                       |                                                                                                                                       |

### Fraud prevention![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#fraud-prevention" id="fraud-prevention"></a>

Stripe’s fraud prevention system, Radar, can block payments when they have a high risk level or fail verification checks. You can use the cards in this section to test your Radar settings. You can also use them to test how your integration responds to blocked payments.

Each card simulates specific risk factors. Your Radar settings determine which risk factors cause it to block a payment. Blocked payments result in card errors with an error code of fraud.

**Common mistake**

To simulate a failed CVC check, you must provide a CVC using any three-digit number. To simulate a failed postal code check, you must provide any valid postal code. If you don’t provide those values, Radar doesn’t perform the corresponding checks, so the checks can’t fail.

{% tabs %}
{% tab title="Card numbers" %}

| DESCRIPTION             | NUMBER              | DETAILS                                                                                                                                                |
| ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Always blocked          | 4100 0000 0000 0019 | <p>The charge has a risk level of “highest”</p><p>Our Antifraud System always blocks it.</p>                                                           |
| Highest risk            | 4000 0000 0000 4954 | <p>The charge has a risk level of “highest”</p><p>Our Antifraud Systemmight block it depending on your settings.</p>                                   |
| Elevated risk           | 4000 0000 0000 9235 | The charge has a risk level of “elevated”                                                                                                              |
| CVC check fails         | 4000 0000 0000 0101 | <p>If you provide a CVC number, the CVC check fails.</p><p>Our Antifraud System might block it depending on your settings.</p>                         |
| Postal code check fails | 4000 0000 0000 0036 | <p>If you provide a postal code, the postal code check fails.</p><p>Our Antifraud System might block it depending on your settings.</p>                |
| Line1 check fails       | 4000 0000 0000 0028 | <p>The address line 1 check fails.</p><p>The payment succeeds unless you block it with a custom Antifraud System rule.</p>                             |
| Address checks fail     | 4000 0000 0000 0010 | <p>The address postal code check and address line 1 check both fail.</p><p>Our Antifraud System might block it depending on your settings.</p>         |
| Address unavailable     | 40000 0000 0000044  | <p>The address postal code check and address line 1 check are both unavailable.</p><p>The payment succeeds unless you block it with a custom rule.</p> |

{% endtab %}

{% tab title="PaymentMethods" %}

| DESCRIPTION             | PAYMENTMETHOD               | DETAILS                                                                                                                                                                                                                                                 |
| ----------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Always blocked          | pm\_card\_radarBlock        | <p>The charge has a <a href="https://docs.stripe.com/radar/risk-evaluation#high-risk">risk level of “highest”</a></p><p>Radar always blocks it.</p>                                                                                                     |
| Highest risk            | pm\_card\_riskLevelHighest  | <p>The charge has a <a href="https://docs.stripe.com/radar/risk-evaluation#high-risk">risk level of “highest”</a></p><p>Radar might block it depending on your settings.</p>                                                                            |
| Elevated risk           | pm\_card\_riskLevelElevated | <p>The charge has a <a href="https://docs.stripe.com/radar/risk-evaluation#elevated-risk">risk level of “elevated”</a></p><p>If you use Radar for Fraud Teams, Radar might <a href="https://docs.stripe.com/radar/reviews">queue it for review</a>.</p> |
| CVC check fails         | pm\_card\_cvcCheckFail      | <p>If you provide a CVC number, the CVC check fails.</p><p>Radar might block it <a href="https://docs.stripe.com/radar/rules#traditional-bank-checks">depending on your settings.</a></p>                                                               |
| Postal code check fails | pm\_card\_avsZipFail        | <p>If you provide a postal code, the postal code check fails.</p><p>Radar might block it <a href="https://docs.stripe.com/radar/rules#traditional-bank-checks">depending on your settings.</a></p>                                                      |
| Line1 check fails       | pm\_card\_avsLine1Fail      | <p>The address line 1 check fails.</p><p>The payment succeeds unless you <a href="https://docs.stripe.com/radar/rules/reference#post-authorization-attributes">block it with a custom Radar rule</a>.</p>                                               |
| Address checks fail     | pm\_card\_avsFail           | <p>The address postal code check and address line 1 check both fail.</p><p>Radar might block it <a href="https://docs.stripe.com/radar/rules#traditional-bank-checks">depending on your settings.</a></p>                                               |
| Address unavailable     | pm\_card\_avsUnchecked      | <p>The address postal code check and address line 1 check are both unavailable.</p><p>The payment succeeds unless you <a href="https://docs.stripe.com/radar/rules/reference#post-authorization-attributes">block it with a custom Radar rule</a>.</p>  |

{% endtab %}

{% tab title="Tokens" %}

| DESCRIPTION             | TOKEN                  | DETAILS                                                                                                                                                                                                                                                 |
| ----------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Always blocked          | tok\_radarBlock        | <p>The charge has a <a href="https://docs.stripe.com/radar/risk-evaluation#high-risk">risk level of “highest”</a></p><p>Radar always blocks it.</p>                                                                                                     |
| Highest risk            | tok\_riskLevelHighest  | <p>The charge has a <a href="https://docs.stripe.com/radar/risk-evaluation#high-risk">risk level of “highest”</a></p><p>Radar might block it depending on your settings.</p>                                                                            |
| Elevated risk           | tok\_riskLevelElevated | <p>The charge has a <a href="https://docs.stripe.com/radar/risk-evaluation#elevated-risk">risk level of “elevated”</a></p><p>If you use Radar for Fraud Teams, Radar might <a href="https://docs.stripe.com/radar/reviews">queue it for review</a>.</p> |
| CVC check fails         | tok\_cvcCheckFail      | <p>If you provide a CVC number, the CVC check fails.</p><p>Radar might block it <a href="https://docs.stripe.com/radar/rules#traditional-bank-checks">depending on your settings.</a></p>                                                               |
| Postal code check fails | tok\_avsZipFail        | <p>If you provide a postal code, the postal code check fails.</p><p>Radar might block it <a href="https://docs.stripe.com/radar/rules#traditional-bank-checks">depending on your settings.</a></p>                                                      |
| Line1 check fails       | tok\_avsLine1Fail      | <p>The address line 1 check fails.</p><p>The payment succeeds unless you <a href="https://docs.stripe.com/radar/rules/reference#post-authorization-attributes">block it with a custom Radar rule</a>.</p>                                               |
| Address checks fail     | tok\_avsFail           | <p>The address postal code check and address line 1 check both fail.</p><p>Radar might block it <a href="https://docs.stripe.com/radar/rules#traditional-bank-checks">depending on your settings.</a></p>                                               |
| Address unavailable     | tok\_avsUnchecked      | <p>The address postal code check and address line 1 check are both unavailable.</p><p>The payment succeeds unless you <a href="https://docs.stripe.com/radar/rules/reference#post-authorization-attributes">block it with a custom Radar rule</a>.</p>  |
| {% endtab %}            |                        |                                                                                                                                                                                                                                                         |
| {% endtabs %}           |                        |                                                                                                                                                                                                                                                         |

### Invalid data![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#invalid-data" id="invalid-data"></a>

To test errors resulting from invalid data, provide invalid details. You don’t need a special test card for this. Any invalid value works. For instance:

* invalid\_expiry\_month: Use an invalid month, such as **13**.
* invalid\_expiry\_year: Use a year up to 50 years in the past, such as **95**.
* invalid\_cvc: Use a two-digit number, such as **99**.
* incorrect\_number: Use a card number that fails the Luhn check, such as 4242424242424241.

### Disputes![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#disputes" id="disputes"></a>

To simulate a disputed transaction, use the test cards in this section. Then, to simulate winning or losing the dispute, provide winning or losing evidence.

{% tabs %}
{% tab title="Card numbers" %}

| DESCRIPTION                  | NUMBER              | DETAILS                                                                                                                                                           |
| ---------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Fraudulent                   | 4000 0000 0000 0259 | With default account settings, charge succeeds, only to be disputed as fraudulent. This type of dispute is protected after 3D Secure authentication.              |
| Not received                 | 4000 0000 0000 2685 | With default account settings, charge succeeds, only to be disputed as product not received. This type of dispute isn’t protected after 3D Secure authentication. |
| Inquiry                      | 4000 0000 0000 1976 | With default account settings, charge succeeds, only to be disputed as an enquiry.                                                                                |
| Warning                      | 4000 0000 0000 5423 | With default account settings, charge succeeds, only to receive an early fraud warning.                                                                           |
| Multiple disputes            | 4000 0004 0400 0079 | With default account settings, charge succeeds, only to be disputed multiple times.                                                                               |
| Visa Compelling Evidence 3.0 | 4000 0004 0400 0038 | With default account settings, charge succeeds, only to be disputed as a Visa Compelling Evidence 3.0 eligible dispute.                                           |

{% endtab %}

{% tab title="PaymentMethods" %}

| DESCRIPTION                  | PAYMENTMETHOD                                           | DETAILS                                                                                                                                                                                                                                                                                              |
| ---------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Fraudulent                   | pm\_card\_createDispute                                 | With default account settings, charge succeeds, only to be disputed as [fraudulent](https://docs.stripe.com/disputes/categories). This type of dispute is [protected](https://docs.stripe.com/payments/3d-secure/authentication-flow#disputed-payments) after 3D Secure authentication.              |
| Not received                 | <p>pm\_card\_</p><p>createDisputeProductNotReceived</p> | With default account settings, charge succeeds, only to be disputed as [product not received](https://docs.stripe.com/disputes/categories). This type of dispute [isn’t protected](https://docs.stripe.com/payments/3d-secure/authentication-flow#disputed-payments) after 3D Secure authentication. |
| Inquiry                      | pm\_card\_createDisputeInquiry                          | With default account settings, charge succeeds, only to be disputed as [an enquiry](https://docs.stripe.com/disputes/how-disputes-work#inquiries).                                                                                                                                                   |
| Warning                      | pm\_card\_createIssuerFraudRecord                       | With default account settings, charge succeeds, only to receive [an early fraud warning](https://docs.stripe.com/disputes/how-disputes-work#early-fraud-warnings).                                                                                                                                   |
| Multiple disputes            | pm\_card\_createMultipleDisputes                        | With default account settings, charge succeeds, only to be disputed [multiple times](https://docs.stripe.com/disputes/how-disputes-work#multiple-disputes).                                                                                                                                          |
| Visa Compelling Evidence 3.0 | pm\_card\_createCe3EligibleDispute                      | With default account settings, charge succeeds, only to be disputed as a [Visa Compelling Evidence 3.0 eligible dispute](https://docs.stripe.com/disputes/api/visa-ce3#testing).                                                                                                                     |
| {% endtab %}                 |                                                         |                                                                                                                                                                                                                                                                                                      |

{% tab title="Tokens" %}

<table><thead><tr><th width="156">DESCRIPTION</th><th>TOKEN</th><th>DETAILS</th></tr></thead><tbody><tr><td>Fraudulent</td><td>tok_createDispute</td><td>With default account settings, charge succeeds, only to be disputed as <a href="https://docs.stripe.com/disputes/categories">fraudulent</a>. This type of dispute is <a href="https://docs.stripe.com/payments/3d-secure/authentication-flow#disputed-payments">protected</a> after 3D Secure authentication.</td></tr><tr><td>Not received</td><td>tok_createDisputeProductNotReceived</td><td>With default account settings, charge succeeds, only to be disputed as <a href="https://docs.stripe.com/disputes/categories">product not received</a>. This type of dispute <a href="https://docs.stripe.com/payments/3d-secure/authentication-flow#disputed-payments">isn’t protected</a> after 3D Secure authentication.</td></tr><tr><td>Inquiry</td><td>tok_createDisputeInquiry</td><td>With default account settings, charge succeeds, only to be disputed as <a href="https://docs.stripe.com/disputes/how-disputes-work#inquiries">an enquiry</a>.</td></tr><tr><td>Warning</td><td>tok_createIssuerFraudRecord</td><td>With default account settings, charge succeeds, only to receive <a href="https://docs.stripe.com/disputes/how-disputes-work#early-fraud-warnings">an early fraud warning</a>.</td></tr><tr><td>Multiple disputes</td><td>tok_createMultipleDisputes</td><td>With default account settings, charge succeeds, only to be disputed <a href="https://docs.stripe.com/disputes/how-disputes-work#multiple-disputes">multiple times</a>.</td></tr><tr><td>Visa Compelling Evidence 3.0</td><td>tok_createCe3EligibleDispute</td><td>With default account settings, charge succeeds, only to be disputed as a <a href="https://docs.stripe.com/disputes/api/visa-ce3#testing">Visa Compelling Evidence 3.0 eligible dispute</a>.</td></tr></tbody></table>

{% endtab %}
{% endtabs %}

### Evidence

To simulate winning or losing the dispute, respond with one of the evidence values from the table below.

* If you respond using the API, pass the value from the table as uncategorized\_text.
* If you respond in the Dashboard, enter the value from the table in the **Additional information** field. Then, click **Submit evidence**.

<table><thead><tr><th width="203">EVIDENCE</th><th>DESCRIPTION</th></tr></thead><tbody><tr><td>winning_evidence</td><td>The dispute is closed and marked as won. Your account is credited the amount of the charge and related fees.</td></tr><tr><td>losing_evidence</td><td>The dispute is closed and marked as lost. Your account isn’t credited.</td></tr></tbody></table>

### Refunds![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#refunds" id="refunds"></a>

In live mode, refunds are asynchronous: a refund can appear to succeed and later fail, or can appear as `pending` at first and later succeed. To simulate refunds with those behaviors, use the test cards in this section. (With all other test cards, refunds succeed immediately and don’t change status after that.)

{% tabs %}
{% tab title="Card numbers" %}

| DESCRIPTION          | NUMBER              | DETAILS                                                                                                                                                                   |
| -------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Asynchronous success | 4000 0000 0000 7726 | The charge succeeds. If you initiate a refund, its status begins as `pending`. Some time later, its status transitions to `succeeded` and sends a `refund.updated` event. |
| Asynchronous failure | 4000 0000 0000 5126 | The charge succeeds. If you initiate a refund, its status begins as `succeeded`. Some time later, its status transitions to `failed` and sends a `refund.failed` event.   |
| {% endtab %}         |                     |                                                                                                                                                                           |

{% tab title="PaymentMethods" %}

| DESCRIPTION          | PAYMENTMETHOD           | DETAILS                                                                                                                                                                                                                                                                                          |
| -------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Asynchronous success | pm\_card\_pendingRefund | The charge succeeds. If you initiate a refund, its status begins as `pending`. Some time later, its status transitions to `succeeded` and sends a `refund.updated` [event](https://docs.stripe.com/api/events/types#event_types-refund.updated).ailable balance, bypassing your pending balance. |
| Asynchronous failure | pm\_card\_refundFaill   | The charge succeeds. If you initiate a refund, its status begins as `succeeded`. Some time later, its status transitions to `failed` and sends a `refund.failed` [event](https://docs.stripe.com/api/events/types#event_types-refund.failed).                                                    |
| {% endtab %}         |                         |                                                                                                                                                                                                                                                                                                  |

{% tab title="Tokens" %}

| DESCRIPTION          | TOKEN              | DETAILS                                                                                                                                                                                                                                          |
| -------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Asynchronous success | tok\_pendingRefund | The charge succeeds. If you initiate a refund, its status begins as `pending`. Some time later, its status transitions to `succeeded` and sends a `refund.updated` [event](https://docs.stripe.com/api/events/types#event_types-refund.updated). |
| Asynchronous failure | tok\_refundFail    | The charge succeeds. If you initiate a refund, its status begins as `succeeded`. Some time later, its status transitions to `failed` and sends a `refund.failed` [event](https://docs.stripe.com/api/events/types#event_types-refund.failed).    |
| {% endtab %}         |                    |                                                                                                                                                                                                                                                  |
| {% endtabs %}        |                    |                                                                                                                                                                                                                                                  |

You can cancel a card refund only by using the Dashboard. In live mode, you can cancel a card refund within a short but nonspecific period of time. Test mode simulates that period by allowing you to cancel a card refund within 30 minutes.

### Available balance![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#available-balance" id="available-balance"></a>

To send the funds from a test transaction directly to your available balance, use the test cards in this section. Other test cards send funds from a successful payment to your pending balance.

{% tabs %}
{% tab title="Card Numbers" %}

| DESCRIPTION            | NUMBER              | DETAILS                                                                                                                |
| ---------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Bypass pending balance | 4000 0000 0000 0077 | The US charge succeeds. Funds are added directly to your available balance, bypassing your pending balance.            |
| Bypass pending balance | 4000 0037 2000 0278 | The international charge succeeds. Funds are added directly to your available balance, bypassing your pending balance. |
| {% endtab %}           |                     |                                                                                                                        |

{% tab title="PaymentMethods" %}

| DESCRIPTION            | PAYMENTMETHOD                        | DETAILS                                                                                                                |
| ---------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| Bypass pending balance | pm\_card\_bypassPending              | The US charge succeeds. Funds are added directly to your available balance, bypassing your pending balance.            |
| Bypass pending balance | pm\_card\_bypassPendingInternational | The international charge succeeds. Funds are added directly to your available balance, bypassing your pending balance. |
| {% endtab %}           |                                      |                                                                                                                        |

{% tab title="Tokens" %}

| DESCRIPTION            | TOKEN                           | DETAILS                                                                                                                |
| ---------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Bypass pending balance | tok\_bypassPending              | The US charge succeeds. Funds are added directly to your available balance, bypassing your pending balance.            |
| Bypass pending balance | tok\_bypassPendingInternational | The international charge succeeds. Funds are added directly to your available balance, bypassing your pending balance. |
| {% endtab %}           |                                 |                                                                                                                        |
| {% endtabs %}          |                                 |                                                                                                                        |

### 3D Secure authentication![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#regulatory-cards" id="regulatory-cards"></a>

3D Secure requires an additional layer of authentication for credit card transactions. The test cards in this section allow you to simulate triggering authentication in different payment flows.

Only cards in this section effectively test your 3D Secure integration by simulating defined 3DS behaviour, such as a challenge flow or an unsupported card. Other Stripe testing cards might still trigger 3DS, but we return `attempt_acknowledged` to bypass the additional steps since 3DS testing isn’t the objective for those cards.

**Dashboard not supported**

3D Secure redirects won’t occur for payments created directly in the Stripe Dashboard. Instead, use your integration’s own frontend or an API call.

**Authentication and setup**![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)

To simulate payment flows that include authentication, use the test cards in this section. Some of these cards can also be set up for future payments, or have already been.

{% tabs %}
{% tab title="Card numbers" %}

| DESCRIPTION                | NUMBER              | DETAILS                                                                                                                                                                                                                                                     |
| -------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Authenticate unless set up | 4000 0025 0000 3155 | This card requires authentication for off-session payments unless you set it up for future payments. After you set it up, off-session payments no longer require authentication. However, on-session payments with this card always require authentication. |
| Always authenticate        | 4000 0027 6000 3184 | This card requires authentication on all transactions, regardless of how the card is set up.                                                                                                                                                                |
| Already set up             | 4000 0038 0000 0446 | This card is already set up for off-session use. It requires authentication for one-off and other on-session payments. However, all off-session payments succeed as if the card has been previously set up.                                                 |
| Insufficient funds         | 4000 0082 6000 3178 | This card requires authentication for one-off payments. All payments are declined with an `insufficient_funds` failure code even after being successfully authenticated or previously set up.                                                               |
| {% endtab %}               |                     |                                                                                                                                                                                                                                                             |

{% tab title="PaymentMethods" %}

<table><thead><tr><th>DESCRIPTION</th><th width="279">PAYMENTMETHOD</th><th>DETAILS</th></tr></thead><tbody><tr><td>Authenticate unless set up</td><td>pm_card_authenticationRequiredOnSetup</td><td>This card requires authentication for every payment unless you <a href="https://docs.stripe.com/payments/save-and-reuse">set it up</a> for future payments. After you set it up, it no longer requires authentication.</td></tr><tr><td>Always authenticate</td><td>pm_card_authenticationRequired</td><td>This card requires authentication on all transactions, regardless of how the card is set up.</td></tr><tr><td>Already set up</td><td>pm_card_authenticationRequiredSetupForOffSession</td><td>This card is already set up for off-session use. It requires authentication for <a href="https://docs.stripe.com/payments/accept-a-payment?platform=web">one-off</a> and other <a href="https://docs.stripe.com/payments/save-during-payment#web-submit-payment">on-session</a> payments. However, all off-session payments succeed as if the card has been previously <a href="https://docs.stripe.com/payments/save-and-reuse">set up</a>.</td></tr><tr><td>Insufficient funds</td><td>pm_card_authenticationRequiredChargeDeclinedInsufficientFunds</td><td>This card requires authentication for <a href="https://docs.stripe.com/payments/accept-a-payment?platform=web">one-off payments</a>. All payments are declined with an <code>insufficient_funds</code> failure code even after being successfully authenticated or previously <a href="https://docs.stripe.com/payments/save-and-reuse">set up</a>.</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

#### Support and availability![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#three-ds-cards" id="three-ds-cards"></a>

We request authentication when required by regulation or when triggered by your Antifraud System rules or custom code. Even if authentication is requested, it can’t always be performed – for instance, the customer’s card might not be enrolled, or an error might occur. Use the test cards in this section to simulate various combinations of these factors.

**Note**

All 3DS references indicate 3D Secure 2.

{% tabs %}
{% tab title="Card numbers" %}

<table><thead><tr><th width="206">3D SECURE USAGE</th><th>OUTCOME</th><th>NUMBER</th><th>DETAILS</th></tr></thead><tbody><tr><td>3DS Required</td><td>OK</td><td>4000 0000 0000 3220</td><td>3D Secure authentication must be completed for the payment to be successful. By default, Our Antifraud System rules request 3D Secure authentication for this card.</td></tr><tr><td>3DS Required</td><td>Declined</td><td>4000 0084 0000 1629</td><td>3D Secure authentication is required, but payments are declined with a <code>card_declined</code> failure code after authentication. By default, Our Antifraud System rules request 3D Secure authentication for this card.</td></tr><tr><td>3DS Required</td><td>Error</td><td>4000 0084 0000 1280</td><td>3D Secure authentication is required, but the 3D Secure lookup request fails with a processing error. Payments are declined with a <code>card_declined</code> failure code. By default, Our Antifraud System rules request 3D Secure authentication for this card.</td></tr><tr><td>3DS Supported</td><td>OK</td><td>4000 0000 0000 3055</td><td>3D Secure authentication might still be performed, but isn’t required. By default, Our Antifraud System rules don’t request 3D Secure authentication for this card.</td></tr><tr><td>3DS Supported</td><td>Error</td><td>4000 0000 0000 3097</td><td>3D Secure authentication might still be performed, but isn’t required. However, attempts to perform 3D Secure result in a processing error. By default, Our Antifraud System rules don’t request 3D Secure authentication for this card.</td></tr><tr><td>3DS Supported</td><td>Unenrolled</td><td>4242 4242 4242 4242</td><td>3D Secure is supported for this card, but this card isn’t enrolled in 3D Secure. Even if Our Antifraud System  rules request 3D Secure, the customer won’t be prompted to authenticate. By default, Our Antifraud System rules don’t request 3D Secure authentication for this card.</td></tr><tr><td>3DS Not supported</td><td></td><td>3782 822463 10005</td><td>3D Secure isn’t supported on this card and can’t be invoked. The PaymentIntent or SetupIntent proceeds without performing authentication.</td></tr></tbody></table>
{% endtab %}

{% tab title="PaymentMethods" %}

<table><thead><tr><th width="194">3D SECURE USAGE</th><th>OUTCOME</th><th>PAYMENTMETHOD</th><th>DETAILS</th></tr></thead><tbody><tr><td>Required</td><td>OK</td><td>pm_card_threeDSecure2Required</td><td>3D Secure authentication must be completed for the payment to be successful. By default, your Radar rules request 3D Secure authentication for this card.</td></tr><tr><td>Required</td><td>Declined</td><td>pm_card_threeDSecureRequiredChargeDeclined</td><td>3D Secure authentication is required, but payments are declined with a <code>card_declined</code> failure code after authentication. By default, your Radar rules request 3D Secure authentication for this card.</td></tr><tr><td>Required</td><td>Error</td><td>pm_card_threeDSecureRequiredProcessingError</td><td>3D Secure authentication is required, but the 3D Secure lookup request fails with a processing error. Payments are declined with a <code>card_declined</code> failure code. By default, your Radar rules request 3D Secure authentication for this card.</td></tr><tr><td>Supported</td><td>OK</td><td>pm_card_threeDSecureOptional</td><td>3D Secure authentication might still be performed, but isn’t required. By default, your Radar rules don’t request 3D Secure authentication for this card.</td></tr><tr><td>Supported</td><td>Error</td><td>pm_card_threeDSecureOptionalProcessingError</td><td>3D Secure authentication might still be performed, but isn’t required. However, attempts to perform 3D Secure result in a processing error. By default, your Radar rules don’t request 3D Secure authentication for this card.</td></tr><tr><td>Supported</td><td>Unenrolled</td><td>pm_card_visa</td><td>3D Secure is supported for this card, but this card isn’t enrolled in 3D Secure. Even if your Radar rules request 3D Secure, the customer won’t be prompted to authenticate. By default, your Radar rules don’t request 3D Secure authentication for this card.</td></tr><tr><td>Not supported</td><td></td><td>pm_card_amex_threeDSecureNotSupported</td><td>3D Secure isn’t supported on this card and can’t be invoked. The PaymentIntent or SetupIntent proceeds without performing authentication.</td></tr></tbody></table>

{% endtab %}

{% tab title="Tokens" %}

| 3D SECURE USAGE | OUTCOME    | TOKEN                                    | DETAILS                                                                                                                                                                                                                                                         |
| --------------- | ---------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Required        | OK         | tok\_threeDSecure2Required               | 3D Secure authentication must be completed for the payment to be successful. By default, your Radar rules request 3D Secure authentication for this card.                                                                                                       |
| Required        | Declined   | tok\_threeDSecureRequiredChargeDeclined  | 3D Secure authentication is required, but payments are declined with a `card_declined` failure code after authentication. By default, your Radar rules request 3D Secure authentication for this card.                                                          |
| Required        | Error      | tok\_threeDSecureRequiredProcessingError | 3D Secure authentication is required, but the 3D Secure lookup request fails with a processing error. Payments are declined with a `card_declined` failure code. By default, your Radar rules request 3D Secure authentication for this card.                   |
| Supported       | OK         | tok\_threeDSecureOptional                | 3D Secure authentication might still be performed, but isn’t required. By default, your Radar rules don’t request 3D Secure authentication for this card.                                                                                                       |
| Supported       | Error      | tok\_threeDSecureOptionalProcessingError | 3D Secure authentication might still be performed, but isn’t required. However, attempts to perform 3D Secure result in a processing error. By default, your Radar rules don’t request 3D Secure authentication for this card.                                  |
| Supported       | Unenrolled | tok\_visa                                | 3D Secure is supported for this card, but this card isn’t enrolled in 3D Secure. Even if your Radar rules request 3D Secure, the customer won’t be prompted to authenticate. By default, your Radar rules don’t request 3D Secure authentication for this card. |
| Not supported   |            | tok\_amex\_threeDSecureNotSupported      | 3D Secure isn’t supported on this card and can’t be invoked. The PaymentIntent proceeds without performing authentication.                                                                                                                                      |

{% endtab %}
{% endtabs %}

#### 3D Secure mobile challenge flows![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#id-3d-secure-mobile-challenge-flows" id="id-3d-secure-mobile-challenge-flows"></a>

In a mobile payment, several challenge flows for authentication—where the customer has to interact with prompts in the UI—are available. Use the test cards in this section to trigger a specific challenge flow for test purposes. These cards aren’t useful in browser-based payment forms or in API calls. In those environments, they work but don’t trigger any special behavior. Because they’re not useful in API calls, we don’t provide any `PaymentMethod` or `Token` values to test with.

| CHALLENGE FLOW    | NUMBER              | DETAILS                                                                                                                  |
| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Out of band       | 4000 5826 0000 0094 | 3D Secure 2 authentication must be completed on all transactions. Triggers the challenge flow with Out of Band UI.       |
| One time passcode | 4000 5826 0000 0045 | 3D Secure 2 authentication must be completed on all transactions. Triggers the challenge flow with One Time Passcode UI. |
| Single select     | 4000 5826 0000 0102 | 3D Secure 2 authentication must be completed on all transactions. Triggers the challenge flow with single-select U       |
| Multi select      | 4000 5826 0000 0110 | D Secure 2 authentication must be completed on all transactions. Triggers the challenge flow with multi-select UI.       |

### Captcha challenge![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#captcha" id="captcha"></a>

To prevent fraud, Our Antifraud System  might display a captcha challenge to the user on the payment page. Use the test cards below to simulate this flow.

| DESCRIPTION       | NUMBER              | DETAILS                                                                  |
| ----------------- | ------------------- | ------------------------------------------------------------------------ |
| Captcha challenge | 4000 0000 0000 1208 | The charge succeeds if the user correctly answers the captcha challenge. |
| Captcha challenge | 4000 0000 0000 3725 | The charge succeeds if the user correctly answers the captcha challenge. |

### Rate limits![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#rate-limits" id="rate-limits"></a>

If your requests in test mode begin to receive `429` HTTP errors, make them less frequently. These errors come from our rate limiter, which is stricter in test mode than in live mode.

We don’t recommend load testing your integration using the API in test mode. Because the load limiter is stricter in test mode, you might see errors that you wouldn’t see in production. See load testing for an alternative approach.

### Non-card payments![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#non-card-payments" id="non-card-payments"></a>

Any time you use a test non-card payment method, use test API keys in all API calls. This is true whether you’re serving a payment form you can test interactively or writing test code.

Different payment methods have different test procedures:

{% tabs %}
{% tab title="ACH Direct Debit" %}

#### Send transaction emails in test mode![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#send-transaction-emails-in-test-mode" id="send-transaction-emails-in-test-mode"></a>

After you collect the bank account details and accept a mandate, send the mandate confirmation and microdeposit verification emails in test mode. To do this, provide an email in the `payment_method_data.billing_details[email]` field in the form of `{any-prefix}+test_email@{any_domain}` when you collect the payment method details.

#### Test account numbers![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#test-account-numbers" id="test-account-numbers"></a>

Stripe provides several test account numbers and corresponding tokens you can use to make sure your integration for manually-entered bank accounts is ready for production.

| ACCOUNT NUMBER | TOKEN                                  | ROUTING NUMBER | BEHAVIOR                                                                                               |
| -------------- | -------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------ |
| 000123456789   | pm\_usBankAccount\_success             | 110000000      | The payment succeeds.                                                                                  |
| 000111111113   | pm\_usBankAccount\_accountClosed       | 110000000      | The payment fails because the account is closed.                                                       |
| 000111111116   | pm\_usBankAccount\_noAccount           | 110000000      | The payment fails because no account is found.                                                         |
| 000222222227   | pm\_usBankAccount\_insufficientFunds   | 110000000      | The payment fails due to insufficient funds.                                                           |
| 000333333335   | pm\_usBankAccount\_debitNotAuthorized  | 110000000      | The payment fails because debits aren’t authorized.                                                    |
| 000444444440   | pm\_usBankAccount\_invalidCurrency     | 110000000      | The payment fails due to invalid currency.                                                             |
| 000666666661   | pm\_usBankAccount\_failMicrodeposits   | 110000000      | The payment fails to send microdeposits.                                                               |
| 000555555559   | pm\_usBankAccount\_dispute             | 110000000      | The payment triggers a dispute.                                                                        |
| 000000000009   | pm\_usBankAccount\_processing          | 110000000      | The payment stays in processing indefinitely. Useful for testing PaymentIntent cancellation.           |
| 000777777771   | pm\_usBankAccount\_weeklyLimitExceeded | 110000000      | The payment fails due to payment amount causing the account to exceed its weekly payment volume limit. |

Before test transactions can complete, you need to verify all test accounts that automatically succeed or fail the payment. To do so, use the test microdeposit amounts or descriptor codes below.

#### Test microdeposit amounts and descriptor codes![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#test-microdeposit-amounts-and-descriptor-codes" id="test-microdeposit-amounts-and-descriptor-codes"></a>

To mimic different scenarios, use these microdeposit amounts *or* 0.01 descriptor code values.

| MICRODEPOSIT VALUES | 0.01 DESCRIPTOR CODE VALUES | SCENARIO                                                         |
| ------------------- | --------------------------- | ---------------------------------------------------------------- |
| 32 and 45           | SM11AA                      | Simulates verifying the account.                                 |
| 10 and 11           | SM33CC                      | Simulates exceeding the number of allowed verification attempts. |
| 40 and 41           | SM44DD                      | Simulates a microdeposit timeout.                                |
| {% endtab %}        |                             |                                                                  |

{% tab title="SEPA debit" %}
Create a test `PaymentIntent` that either succeeds or fails by doing the following:

1. Create a test [PaymentMethod](https://docs.stripe.com/api/payment_methods) with a test account number.
2. Use the resulting `PaymentMethod` in a `confirmSepaDebitPayment` request to create the test charge.

**Austria**

| Account Number       | Description                                                                                                                                          |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| AT611904300234573201 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| AT321904300235473204 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| AT861904300235473202 | The PaymentIntent status transitions from `processing` to `requires_payment_method`                                                                  |
| AT051904300235473205 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| AT591904300235473203 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| AT981904300000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| AT601904300000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Belgium**

| Account Number   | Description                                                                                                                                          |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| BE62510007547061 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| BE78510007547064 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| BE68539007547034 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| BE51510007547065 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| BE08510007547063 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| BE90510000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| BE52510000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Croatia**

| Account Number        | Description                                                                                                                                          |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| HR7624020064583467589 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| HR6323600002337876649 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| HR2725000096983499248 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| HR6723600004878117427 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| HR8724840081455523553 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| HR7424020060000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| HR3624020060000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Estonia**

| Account Number       | Description                                                                                                                                          |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| EE382200221020145685 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| EE222200221020145682 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| EE762200221020145680 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| EE922200221020145683 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| EE492200221020145681 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| EE672200000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| EE292200000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Finland**

| Account Number     | Description                                                                                                                                          |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| FI2112345600000785 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| FI3712345600000788 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| FI9112345600000786 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| FI1012345600000789 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| FI6412345600000787 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| FI6712345600343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| FI2912345600121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**France**

| Account Number              | Description                                                                                                                                          |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| FR1420041010050500013M02606 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| FR3020041010050500013M02609 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| FR8420041010050500013M02607 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| FR7920041010050500013M02600 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| FR5720041010050500013M02608 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| FR9720041010050000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| FR5920041010050000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Germany**

| Account Number         | Description                                                                                                                                          |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| DE89370400440532013000 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| DE08370400440532013003 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| DE62370400440532013001 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| DE78370400440532013004 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| DE35370400440532013002 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| DE65370400440000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| DE27370400440000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Gibraltar**

| Account Number          | Description                                                                                                                                          |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| GI60MPFS599327643783385 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| GI08RRNW626436291644533 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| GI41SAFA461293238477751 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| GI50LROG772261344693297 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| GI26KJBC361883934534696 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| GI14NWBK000000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| GI73NWBK000000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Ireland**

| Account Number         | Description                                                                                                                                          |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| IE29AIBK93115212345678 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| IE24AIBK93115212345671 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| IE02AIBK93115212345679 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| IE94AIBK93115212345672 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| IE51AIBK93115212345670 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| IE10AIBK93115200343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| IE69AIBK93115200121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

Liechtenstein

| Account Number        | Description                                                                                                                                          |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| LI0508800636123378777 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| LI4408800387787111369 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| LI1208800143823175626 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| LI4908800356441975566 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| LI7708800125525347723 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| LI2408800000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| LI8308800000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

Lithania

| Account Number       | Description                                                                                                                                          |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| LT121000011101001000 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| LT281000011101001003 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| LT821000011101001001 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| LT981000011101001004 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| LT551000011101001002 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| LT591000000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| LT211000000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Luxembourg**

| Account Number       | Description                                                                                                                                          |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| LU280019400644750000 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| LU440019400644750003 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| LU980019400644750001 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| LU170019400644750004 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| LU710019400644750002 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| LU900010000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| LU520010000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Netherlands**

| Account Number     | Description                                                                                                                                          |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| NL39RABO0300065264 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| NL55RABO0300065267 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| NL91ABNA0417164300 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| NL28RABO0300065268 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| NL82RABO0300065266 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| NL27RABO0000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| NL86RABO0000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Norway**

| Account Number  |                                                                                                                                                      |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| NO9386011117947 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| NO8886011117940 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| NO6686011117948 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| NO6186011117941 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| NO3986011117949 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| NO0586010343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| NO0586010343434 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Portugal**

| Account Number            | Description                                                                                                                                          |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| PT50000201231234567890154 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| PT66000201231234567890157 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| PT23000201231234567890155 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| PT39000201231234567890158 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| PT93000201231234567890156 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| PT05000201230000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| PT64000201230000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Spain**

| Account Number           | Description                                                                                                                                          |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| ES0700120345030000067890 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| ES2300120345030000067893 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| ES9121000418450200051332 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| ES9300120345030000067894 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| ES5000120345030000067892 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| ES1700120345000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| ES7600120345000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Sweden**

| Account Number           | Description                                                                                                                                          |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| SE3550000000054910000003 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| SE5150000000054910000006 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| SE0850000000054910000004 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| SE2450000000054910000007 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| SE7850000000054910000005 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| SE2850000000000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| SE8750000000000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**Switzerland**

| Account Number        | Description                                                                                                                                          |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| CH9300762011623852957 | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| CH8656663438253651553 | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| CH5362200119938136497 | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| CH1843597160341964438 | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| CH1260378413965193069 | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| CH1800762000000343434 | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| CH7700762000000121212 | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |

**United Kingdom**

| Account Number          | Description                                                                                                                                          |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| GB82WEST12345698765432  | The PaymentIntent status transitions from `processing` to `succeeded`.                                                                               |
| GB98WEST12345698765435  | The PaymentIntent status transitions from `processing` to `succeeded` after at least three minutes.                                                  |
| GB55WEST12345698765433  | The PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                 |
| GB71WEST12345698765436  | The PaymentIntent status transitions from `processing` to `requires_payment_method` after at least three minutes.                                    |
| GB28WEST12345698765434  | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                         |
| GB70WEST12345600343434G | The payment fails with a `charge_exceeds_source_limit` failure code due to payment amount causing account to exceed its weekly payment volume limit. |
| GB32WEST12345600121212  | The payment fails with a `charge_exceeds_weekly_limit` failure code due to payment amount exceeding account's transaction volume limit.              |
| {% endtab %}            |                                                                                                                                                      |

{% tab title="Bacs debit" %}
There are several test bank account numbers you can use in [test mode](https://docs.stripe.com/keys#test-live-modes) to make sure this integration is ready.

| SORT CODE | ACCOUNT NUMBER | DESCRIPTION                                                                                                                                                                                                                                                 |
| --------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 108800    | 00012345       | The payment succeeds and the PaymentIntent transitions from `processing` to `succeeded`.                                                                                                                                                                    |
| 108800    | 90012345       | The payment succeeds after three minutes and the PaymentIntent transitions from `processing` to `succeeded`.                                                                                                                                                |
| 108800    | 33333335       | The payment is accepted but then immediately fails with a `debit_not_authorized` failure code and the PaymentIntent transitions from `processing` to `requires_payment_method`. The Mandate becomes `inactive` and the PaymentMethod can not be used again. |
| 108800    | 93333335       | The payment fails after three minutes with a `debit_not_authorized` failure code and the PaymentIntent transitions from `processing` to `requires_payment_method`. The Mandate becomes `inactive` and the PaymentMethod can not be used again.              |
| 108800    | 22222227       | The payment fails with an `insufficient_funds` failure code and the PaymentIntent transitions from `processing` to `requires_payment_method`. The Mandate remains `active` and the PaymentMethod can be used again.                                         |
| 108800    | 92222227       | The payment fails after three minutes with an `insufficient_funds` failure code and the PaymentIntent transitions from `processing` to `requires_payment_method`. The Mandate remains `active` and the PaymentMethod can be used again.                     |
| 108800    | 55555559       | The payment succeeds after three minutes and the PaymentIntent transitions from `processing` to `succeeded`, but a dispute is immediately created.                                                                                                          |
| 108800    | 00033333       | Payment Method creation succeeds, but the Mandate is refused by the customer’s bank and immediately transitions to inactive.                                                                                                                                |
| 108800    | 00044444       | The request to set up Bacs Direct Debit fails immediately due to an invalid account number and the customer is prompted to update their information before submitting. Payment details are not collected.                                                   |
| 108800    | 34343434       | The payment fails with a `charge_exceeds_source_limit` failure code due to the payment amount causing the account to exceed its weekly payment volume limit.                                                                                                |
| 108800    | 12121212       | The payment fails with a `charge_exceeds_weekly_limit` failure code due to the payment amount exceeding the account’s transaction volume limit.                                                                                                             |

You can test using any of the account numbers provided above. However, because Bacs Direct Debit payments take several days to process, use the test account numbers that operate on a three-minute delay to better simulate the behavior of live payments.

**Note**

By default, Stripe automatically sends [emails](https://docs.stripe.com/payments/payment-methods/bacs-debit#debit-notifications) to the customer when payment details are initially collected and each time a debit will be made on their account. These notifications aren’t sent in test mode.
{% endtab %}

{% tab title="BECS" %}
You can create a test `PaymentIntent` that either succeeds or fails by doing the following:

Create a test [PaymentMethod](https://docs.stripe.com/api/payment_methods) with the test `BSB 000-000` and a test account number from the list below. Use the resulting `PaymentMethod` in a `confirmAuBecsDebitPayment` request to create the test charge.

**Test account numbers**

| BSB NUMBER   | ACCOUNT NUMBER | DESCRIPTION                                                                                                                                                                                   |
| ------------ | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 000-000      | 000123456      | The PaymentIntent status transitions from `processing` to `succeeded`. The mandate status remains `active`.                                                                                   |
| 000-000      | 900123456      | The PaymentIntent status transitions from `processing` to `succeeded` (with a three-minute delay). The mandate status remains `active`.                                                       |
| 000-000      | 111111113      | The PaymentIntent status transitions from `processing` to `requires_payment_method` with an `account_closed` failure code. The mandate status becomes `inactive`.                             |
| 000-000      | 111111116      | The PaymentIntent status transitions from `processing` to `requires_payment_method` with a `no_account` failure code. The mandate status becomes `inactive`.                                  |
| 000-000      | 222222227      | The PaymentIntent status transitions from `processing` to `requires_payment_method` with a `refer_to_customer` failure code. The mandate status remains `active`.                             |
| 000-000      | 922222227      | The PaymentIntent status transitions from `processing` to `requires_payment_method` with a `refer_to_customer` failure code (with a three-minute delay). The mandate status remains `active`. |
| 000-000      | 333333335      | The PaymentIntent status transitions from `processing` to `requires_payment_method` with a `debit_not_authorized` failure code. The mandate status becomes `inactive`.                        |
| 000-000      | 666666660      | The PaymentIntent status transitions from `processing` to `succeeded`, but a dispute is immediately created.                                                                                  |
| 000-000      | 343434343      | The PaymentIntent fails with a `charge_exceeds_source_limit` error due to the payment amount causing the account to exceed its weekly payment volume limit.                                   |
| 000-000      | 121212121      | The PaymentIntent fails with a `charge_exceeds_transaction_limit` error due to the payment amount exceeding the account’s transaction volume limit.                                           |
| {% endtab %} |                |                                                                                                                                                                                               |

{% tab title="Others" %}
With other payment methods, testing information is included with the documentation. [Find your payment method](https://docs.stripe.com/payments/payment-methods/overview) and read the associated guide to accept and test payments
{% endtab %}
{% endtabs %}

### Link![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#link" id="link"></a>

**Caution**

Don’t store real user data in test mode Link accounts. Treat them as if they’re publicly available, because these test accounts are associated with your publishable key.

Currently, Link only works with credit cards, debit cards, and qualified US bank account purchases. Link requires domain registration.

You can create test mode accounts for Link using any valid email address. The following table shows the fixed one-time passcode values that we accept for authenticating test mode accounts:

| VALUE                               | OUTCOME                      |
| ----------------------------------- | ---------------------------- |
| Any other 6 digits not listed below | Success                      |
| 000001                              | Error, code invalid          |
| 000002                              | Error, code expired          |
| 000003                              | Error, max attempts exceeded |

#### Multiple funding sources![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg) <a href="#multiple-funding-sources" id="multiple-funding-sources"></a>

As we add additional funding source support, you don’t need to update your integration. We automatically support them with the same transaction settlement time and guarantees as card and bank account payments.


# Checkout Choice

We offer 2 Checkout Solutions:

* [Hosted Checkout ](/getting-paid/checkout-choice/hosted-checkout)- visible when you click Go To Store in the Top Menu of the Dashboard
* [Overlay Checkout](/getting-paid/checkout-choice/overlay-checkout) - a pop-up checkout that opens upon clicking a button placed anywhere in your App/Software
* [Embedded Checkout](/getting-paid/checkout-choice/embedded-checkout) - embeddable as an iframe inside existing Website or App

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fm4tVfvqmt3WsHmrYYp4D%2Fimage.png?alt=media&amp;token=22a76d77-1738-492e-953a-62e2102dcbe5" alt=""><figcaption><p>Check how your Checkout page looks like by going to the Store</p></figcaption></figure>

As we act as Merchant of Record - we need to collect Billing Information about the customers, hence we've introduced Billing Details as part of the checkout process.


# Hosted Checkout

In your Dashboard, navigate to Hosted Checkout to share a checkout link to your customers for any of your created products:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FyZCx9i8Y4YS6MhSYOwGJ%2Fimage.png?alt=media&amp;token=47d79f57-b429-4f71-8a50-e08a171ac047" alt=""><figcaption><p>Share Hosted Checkout link to instantly get paid with a simple URL</p></figcaption></figure>

Sharing this link will instantly give access to the checkout page with all available payment methods for that particular product you've shared:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FqeIhH44rBUKaikFSaop8%2Fimage.png?alt=media&amp;token=d6a78ea3-b21b-4344-948e-60e7a2bfa192" alt=""><figcaption><p>Checkout page with all available payment methods</p></figcaption></figure>


# Overlay Checkout

Overlay Checkout is a great way to embed checkout anywhere on your website or inside your app. This will open up a Pop-Up windows that will allow the customer to pay for the SaaS software you're offering.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FyVCsYmSOiyyXS01bEeIC%2Fimage.png?alt=media&amp;token=fda19a41-2ae1-49df-88a4-72d4fb2277de" alt=""><figcaption></figcaption></figure>

A short step by step guide is also available here:

{% embed url="<https://www.youtube.com/watch?v=BK2s_w9Ex_8>" %}
Step by step guide on how to add a Buy Button to your Website or Software to allow checkout
{% endembed %}

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FwohDpT1NUEFNxoLvOvyw%2Fimage.png?alt=media&amp;token=5a53034f-80a6-477e-b294-032b63ec48ef" alt=""><figcaption><p>A pop-up checkout that can be embedded anywhere on your website or inside your SaaS app</p></figcaption></figure>

You can access Overlay Settings in the Dashboard from the left menu:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FiGp03tRW4iaY2764Qyvx%2Fimage.png?alt=media&amp;token=63519842-0e4b-424c-b3d0-79f08fe742e7" alt=""><figcaption><p>Overlay settings can be accessed from the Left Pane in the Main Dashboard</p></figcaption></figure>

There will be 2 buttons on the top right: Customize Overlay which will take you to a builder from where you can change the Overlay's Primary Button colors along with Background color:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fbx7kf7gfZtUR1416Ansm%2Fimage.png?alt=media&amp;token=28c16839-9cfe-41e4-bf01-c1cb771b24e1" alt=""><figcaption><p>Customize your Overlay Checkout as you want in a simple builder view</p></figcaption></figure>

The 2nd buttom Share Overlay will open up a drawer for you to choose which product to be included in the Overlay Checkout. You can share as many Overlays as you want (as many Buy Buttons as you want). Each Overlay will link just to 1 specific product that you choose in the dropdown (you'll have to [Add Your Subscription Product ](/add-subscription-product)first to see the list).

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FqijfaW448su0cqgX6YNa%2Fimage.png?alt=media&amp;token=a26a72e5-c201-4e45-8514-c712d90c6604" alt=""><figcaption><p>Name the Overlay and choose which product will be visible in the Pop-up Checkout. Copy the HTML code anywhere you want.</p></figcaption></figure>

:tada: Congratulations! You've just created your first Overlay Checkout! Copy the HTML code (modify its CSS as you want) and embed it anywhere on your landing page or inside your SaaS Software to allow customers subscribe to your product.


# Embedded Checkout

Apart from [Hosted Checkout ](/getting-paid/checkout-choice/hosted-checkout)and [Overlay Checkout](/getting-paid/checkout-choice/overlay-checkout), you can also Embed the whole checkout flow directly inside your Software, Website or App.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FQWQivYCCoPxrNOIR9buT%2Fimage.png?alt=media&amp;token=a3c5b6a0-971c-4ed3-bb16-28ba33229234" alt=""><figcaption><p>Embedded checkout can be put directly on the Website or inside your App - this is not Overlay / Pop-up Checkout but has the same features</p></figcaption></figure>

In order to implement Embedded Checkout, simply navigate to Checkout Elements on the left of the Dashboard:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FvTewRksLnJ0ylNYbJB2l%2Fimage.png?alt=media&amp;token=10c09ed5-23d0-49ec-9ee8-1c67d57f856d" alt=""><figcaption><p>Access Checkout Elements to use Overlay or Embedded Checkouts</p></figcaption></figure>

You can now see a list of all Checkout Elements. Create a new one or edit previous ones:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fvo6RiqJJfwqpYkN9bfOI%2Fimage.png?alt=media&amp;token=b0c7348e-f78b-41e1-8a2d-e04794217a3f" alt=""><figcaption><p>Choose Embed tab to Copy the HTML code that you can put directly on your Website or inside your App</p></figcaption></figure>

That's it - no coding required. Only Copy and Paste the HTML code.&#x20;

This is an example HTML script that will be copied:

```
// Embedded Checkout HTML code
<div id="target-element-id" style="max-width: 800px; 
height: 900px;">
</div>

<script src='https://cdn.jsdelivr.net/npm/@fungies/fungies-js@0.0.6' 
defer data-auto-init data-auto-display-checkout 
data-fungies-checkout-url='https://aceedz.com/checkout-element/ef42a016-1e61-417d-9885-4b5bdde69349'  
data-fungies-mode='embed' data-fungies-frame-target='target-element-id'>
</script>
```

You can play around with the script like changing the Width and the Height of the code.


# Global Availability

Here's a list of all countries that can set up a Developer / Seller account using our platform and start accepting payments in different currencies from international customers:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FIOd3JRLvjnZQR9kMvFCo%2Fimage.png?alt=media&amp;token=ca1dcf75-ec65-446c-9604-3d7759b1d6ab" alt=""><figcaption><p>List of countries that we can onboard and handle payouts to</p></figcaption></figure>

Countries marked with an asterisk (\*) can only receive payouts in Euros, and those labeled as "Preview" may have payout restrictions or pauses.

There are minimum payout amounts and they're listed below:

| Country              | Amount   |
| -------------------- | -------- |
| Australia            | 0.01 AUD |
| Austria              | 1 EUR    |
| Belgium              | 1 EUR    |
| Brazil               | 0.01 BRL |
| Bulgaria             | 1 BGN    |
| Canada               | 0.01 CAD |
| Costa Rica           | 0.01 CRC |
| Croatia              | 1 EUR    |
| Cyprus               | 1 EUR    |
| Czech Republic       | 30 CZK   |
| Côte d’Ivoire        | 1 XOF    |
| Denmark              | 20 DKK   |
| Dominican Republic   | 0.01 DOP |
| Estonia              | 1 EUR    |
| Finland              | 1 EUR    |
| France               | 1 EUR    |
| Germany              | 1 EUR    |
| Gibraltar            | 1 GBP    |
| Greece               | 1 EUR    |
| Guatemala            | 1 GTQ    |
| Hong Kong            | 0.01 HKD |
| Hungary              | 360 HUF  |
| India                | 1 INR    |
| Indonesia            | 0.01 IDR |
| Ireland              | 1 EUR    |
| Italy                | 1 EUR    |
| Japan                | 1 JPY    |
| Latvia               | 1 EUR    |
| Liechtenstein        | 5 CHF    |
| Lithuania            | 1 EUR    |
| Luxembourg           | 1 EUR    |
| Malaysia             | 5 MYR    |
| Malta                | 1 EUR    |
| Mexico               | 10 MXN   |
| Netherlands          | 1 EUR    |
| New Zealand          | 0.01 NZD |
| Norway               | 20 NOK   |
| Peru                 | 0.01 PEN |
| Philippines          | 2 PHP    |
| Poland               | 5 PLN    |
| Portugal             | 1 EUR    |
| Romania              | 5 RON    |
| Senegal              | 1 XOF    |
| Singapore            | 1 SGD    |
| Slovakia             | 1 EUR    |
| Slovenia             | 1 EUR    |
| Spain                | 1 EUR    |
| Sweden               | 20 SEK   |
| Switzerland          | 5 CHF    |
| Thailand             | 0.01 THB |
| Trinidad & Tobago    | 0.01 TTD |
| United Arab Emirates | 2 AED    |
| United Kingdom       | 1 GBP    |
| United States        | 0.01 USD |
| Uruguay              | 0.01 UYU |

Some cross-border payouts may have restrictions. See the list below (not exhaustive):

Possible special requirements include:

#### Bangladesh <a href="#bangladesh" id="bangladesh"></a>

* Submitting a remittance form.
* Providing a receipt or invoice as proof that the recipient is legitimately receiving the payment.
* Paying additional fees.

#### Japan <a href="#japan" id="japan"></a>

* Visiting a bank location to submit a copy of their ID and additional paperwork, if they haven’t previously done so. Banks require a national ID card number (MyNumber) to be submitted and on file before they can receive or send international transfers.
* Providing a receipt or invoice as proof that the recipient is legitimately receiving the payment.
* Paying additional fees.
* Supporting payouts only to banks participating in the Foreign Exchange Yen Clearing System (FXYCS).

#### Serbia <a href="#serbia" id="serbia"></a>

* Providing additional information on the purpose of the payment.
* Providing a receipt or invoice as proof that the recipient is legitimately receiving the payment.
* Submitting a remittance form.

Once you set up an account with us - you can sell to customers anywhere in the world - without having to worry about being tax-compliant.


# Customer Payment Methods

All listed payment methods here are available depending on the customer's IP address and currency - different customers in different regions of the world will see different payment methods listed.

Here's a list of payment methods available to customers when you start integrating our Merchant of Record payments platform:

1. Cards

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FyhjRY2gjN7qqKGfEL1oa%2Fimage.png?alt=media&amp;token=9fa63e45-8179-40c2-badc-6a51d421110c" alt=""><figcaption><p>Payment flow for your customers</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FJ5QjZf3jeumbBoNQQtgl%2Fimage.png?alt=media&amp;token=0e4cfc67-14b9-4e70-91ab-18518ed18cd3" alt=""><figcaption><p>List of available Card payment methods</p></figcaption></figure>

2. Wallets

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fnu9yZFAohrQ8Yi9qOtE6%2Fimage.png?alt=media&amp;token=de89c6d1-c7c6-4e5b-b9ea-1200c17d0b69" alt=""><figcaption><p>Available Wallet payment methods for customers</p></figcaption></figure>

2. Bank Redirects

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FLEIlS7wpay5TlPWfizyf%2Fimage.png?alt=media&amp;token=110c10ae-991c-4d5f-8f77-1205a1c13dcc" alt=""><figcaption><p>All Bank Redirects if you use our Hosted Checkout solution (Przelewy24 is coming soon)</p></figcaption></figure>

4. Vouchers

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHeLYgmmUN8OrHFAWCu9x%2Fimage.png?alt=media&amp;token=ad369f7e-a548-4425-83f8-4a0e14def30d" alt=""><figcaption><p>Multibanco is supported</p></figcaption></figure>

5. Buy Now, Pay Later

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FuGCrSaKaOHpD2cIDhrjP%2Fimage.png?alt=media&amp;token=ebe6a049-c7c4-4176-859e-465d2a0ed00a" alt=""><figcaption><p>BNPL available methods</p></figcaption></figure>

6. Bank Debits

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F1qHHBNWWe6Z0bWBlL4yf%2Fimage.png?alt=media&amp;token=7da13a98-bf83-4e65-bbd1-3172573b939b" alt=""><figcaption><p>SEPA is available as a Payment Method for EU-based customers</p></figcaption></figure>

7. South Korean Payment Methods

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FRjTqjehA4BpxhQ2FSC3G%2Fimage.png?alt=media&amp;token=1589d084-4905-4e7f-bfa6-53fb7cd17651" alt=""><figcaption><p>South Korean customers will pay with Naver Pay, Kakao Pay, Samsung Pay and Payco</p></figcaption></figure>

8. PayPal

**Customer locations:**

Worldwide (any country)

**Presentment currency:**

EUR, GBP, USD, CHF, CZK, DKK, NOK, PLN, SEK, AUD, CAD, HKD, NZD, SGD

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FQN7knF4jusF2DTgYn9N8%2Fimage.png?alt=media&amp;token=a6c76284-32f9-46a0-a0e6-fe4754d8b334" alt=""><figcaption><p>PayPal payment flow at checkout</p></figcaption></figure>

9. Others (Off by Default + Action Required = You have to set this up for yourself in your own Stripe Dashboard Payment Methods settings):<br>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FVlqQkHuUpBaN8UvPmWru%2Fimage.png?alt=media&amp;token=b532993f-3fc6-45b1-9331-6ebf6e65107a" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FLn6ycEsJuoq7HwIImWqG%2Fimage.png?alt=media&amp;token=eb09d122-4803-4b23-9598-1edfdba8acb4" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FjT9nLSQJrLo12atjgkFZ%2Fimage.png?alt=media&amp;token=86a1af0d-a4bb-47d3-9f7c-d03d8a1524e1" alt=""><figcaption></figcaption></figure>


# Manage your own Payment Methods

As a connected account, you have full control over your payment methods. You can easily manage these settings directly in your own Stripe Dashboard that is connected to the Fungies Master Account.

Just log into your Stripe Dashboard, navigate to your payment settings, and turn on crypto payments if you meet the requirements above.


# Crypto and Stablecoins

Good news! If you're a connected account (merchant) on Fungies.io, you can now accept crypto payments from your customers.

### Who is eligible?

To turn on crypto payments, your business needs to be located in one of the following countries:

•United States

•Estonia

•France

•Hong Kong SAR China

•Mexico

•Poland

•Spain

•Sweden

You also need to make sure you've provided all the necessary business and identity information to Stripe (our Payment Service Provider) during onboarding.


# PayPal Settings

In order to start accepting PayPal payments, you just need to fill out these 2 fields in the Dashboard:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FBX5HlBNRv8xh7kVnWn6v%2Fimage.png?alt=media&amp;token=0d752f90-fce3-4df6-9dac-707569b73e9d" alt=""><figcaption><p>Fill in your PayPal e-mail along with Merchant ID to get PayPal payouts.</p></figcaption></figure>

You can find your PayPal Merchant ID in your PayPal Dashboard (under Account Settings):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F9Q3eeGHfrgpgr46Mbh7E%2Fimage.png?alt=media&amp;token=b9721492-b7c4-40b3-b0c7-5a3e3d400e9c" alt=""><figcaption><p>Find your PayPal Merchant ID in Account Settings.</p></figcaption></figure>

PayPal payouts are made weekly on Wednesdays.

This how a customer sees the PayPal checkout button:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fqs23MV1CpFDAnAzgzLfX%2Fimage.png?alt=media&amp;token=7919cc39-509e-4ba8-9334-371fcab119ed" alt=""><figcaption><p>PayPal button visible in the checkout process for the customer</p></figcaption></figure>


# Billing Details

As we're the Merchant of Record - Billing Details are needed from your customers.

We're the customer-facing company when issuing invoices - it's highly advised that you turn on Billing Info in the Store section of the Dashboard.

This will help us send correct invoices to your customers and thus helping them to correctly associate the transfer with accounting expenses.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FX2nVUPirslbIQlOYF2AI%2Fimage.png?alt=media&amp;token=90daebd5-14b0-4d0c-a2cd-31ad75063a9b" alt=""><figcaption><p>Turn on Billing Details step during checkout</p></figcaption></figure>

Once you turn that on, the "Billing information" step will appear right before Payment Methods choice screen during customer checkout process (both in Hosted and Overlay Checkout views).

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FiVzPzmuBZm2mZwj8LH00%2Fimage.png?alt=media&amp;token=d993b009-8a52-4c5b-b660-cf15ec5257e2" alt=""><figcaption><p>We will collect Billing Details information from the customer during the checkout process</p></figcaption></figure>

The customer will have the choice either to appear as an Individual on the invoice or as a Company. In the latter case, it means that they'll have to provide their Company Name along with their Tax ID.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F5NCwp2Naz4VyjXjEBQmM%2Fimage.png?alt=media&amp;token=1f92bbd4-a1c9-4839-864e-7a1b02d48ed2" alt=""><figcaption><p>Once the customer fills in Billing Details - Payment Methods will appear</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FEf5TXOfOaFmsdNE4lpaq%2Fimage.png?alt=media&amp;token=bce28d05-7057-44be-b4b4-c815f0806b7e" alt=""><figcaption><p>Customer Billing Information will appear on the invoices</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FZMe7pIyVhecArh7kstUc%2Fimage.png?alt=media&amp;token=095ec8d4-b6d4-4a13-a6ce-32717d94485c" alt=""><figcaption><p>Example Invoice sent by us with filled in Billing Information</p></figcaption></figure>

Once again, we highly advise all SaaS businesses that are using our solution to turn this on.


# Payouts

IMPORTANT: if you want to change the default automatic, daily payouts to manual payouts - please send us an email support\@fungies.io with the name of your Workspace and e-mail used during registration

With just one click you can find the information about the amount you've earned and how to pay it out. Go to Payout section and check your balance.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FjvhPgoM5IjDsXhCArxId%2Fimage.png?alt=media&amp;token=58aea357-053e-4e98-a41e-9efeef7cbeb6" alt=""><figcaption><p>You can manually request Payout to your Bank Account (defined during the Stripe onboarding process) or you can access your Stripe Dashboard</p></figcaption></figure>

Payouts are done automatically on daily basis. That is why the amount of Total balance may indicate 0 -> the funds are on their way to your bank account!&#x20;

For more details you can view Order history or check the data on Stripe.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fi4A2Ns33LsoCkSX0Ed28%2Fimage.png?alt=media&amp;token=8fda9e85-b000-45fa-a983-444d6220c282" alt=""><figcaption><p>After clicking on Manage Stripe account - you'll be redirected to your Stripe's Dashboard and see all past transactions along with Payout details (dates and amounts)</p></figcaption></figure>

You receive funds when Fungies makes payouts to your bank account. Payout availability varies depending on your industry and country of operation. When you start processing live payments, Fungies typically schedules your initial payout for 7-14 days after you successfully receive your first payment. Your first payout may take longer depending on your industry risk level and country of operation. Subsequent payouts follow your account’s payout schedule.

You can view a comprehensive list of your payouts and their expected deposit dates in your bank account from the Dashboard.

#### Add or update your bank account

You can update your account details or add a new bank account using the Payout settings in the Dashboard. Based on your bank’s location, Fungies might require different types of account details to activate your bank account. To modify your banking information, click the Edit button next to the desired bank account (in your Stripe Management Dashboard).

#### Supported accounts and settlement currencies

In most cases, bank accounts must be located in the country where the settlement currency is the official currency. For example, SEK bank accounts must be based in Sweden. Fungies also allows you to settle and pay out to banks in select alternative currencies, or to non-domestic bank accounts in local currency, for a fee. For more information about presenting and settling in alternative currencies, see Alternative currencies.

At times, Fungies supports international currencies that don’t incur fees. See the following table for a list of supported free currencies by country.

**Currencies and minimum payout amount, including countries supported:**

<table><thead><tr><th width="189">Country</th><th width="198">Minimum Payout Amount</th></tr></thead><tbody><tr><td>Albania</td><td>3000 ALL</td></tr><tr><td>Algeria</td><td>1 DZD</td></tr><tr><td>Angola</td><td>21000 AOA</td></tr><tr><td>Antigua &#x26; Barbuda</td><td>1 XCD</td></tr><tr><td>Argentina</td><td>4600 ARS</td></tr><tr><td>Armenia</td><td>12100 AMD</td></tr><tr><td>Australia</td><td>0 AUD</td></tr><tr><td>Austria</td><td>1 EUR</td></tr><tr><td>Azerbaijan</td><td>50 AZN</td></tr><tr><td>Bahamas</td><td>1 BSD</td></tr><tr><td>Bahrain</td><td>1 BHD</td></tr><tr><td>Bangladesh</td><td>20 BDT</td></tr><tr><td>Belgium</td><td>1 EUR</td></tr><tr><td>Benin</td><td>1 XOF</td></tr><tr><td>Bhutan</td><td>2500 BTN</td></tr><tr><td>Bolivia</td><td>200 BOB</td></tr><tr><td>Bosnia &#x26; Herzegovina</td><td>50 BAM</td></tr><tr><td>Botswana</td><td>1 BWP</td></tr><tr><td>Brunei</td><td>1 BND</td></tr><tr><td>Bulgaria</td><td>1 BGN</td></tr><tr><td>Cambodia</td><td>123000 KHR</td></tr><tr><td>Canada</td><td>0 CAD</td></tr><tr><td>Chile</td><td>23000 CLP</td></tr><tr><td>Colombia</td><td>4100 COP</td></tr><tr><td>Costa Rica</td><td>0 CRC</td></tr><tr><td>Croatia</td><td>1 EUR</td></tr><tr><td>Cyprus</td><td>1 EUR</td></tr><tr><td>Czech Republic</td><td>1 EUR</td></tr><tr><td>CÃ´te dâ€™Ivoire</td><td>1 XOF</td></tr><tr><td>Denmark</td><td>20 DKK</td></tr><tr><td>Dominican Republic</td><td>1 DOP</td></tr><tr><td>Ecuador</td><td>0 USD</td></tr><tr><td>Egypt</td><td>20 EGP</td></tr><tr><td>El Salvador</td><td>30 USD</td></tr><tr><td>Estonia</td><td>1 EUR</td></tr><tr><td>Ethiopia</td><td>1 ETB</td></tr><tr><td>Finland</td><td>1 EUR</td></tr><tr><td>France</td><td>1 EUR</td></tr><tr><td>Gabon</td><td>100 XAF</td></tr><tr><td>Gambia</td><td>1900 GMD</td></tr><tr><td>Germany</td><td>1 EUR</td></tr><tr><td>Ghana</td><td>1 GHS</td></tr><tr><td>Greece</td><td>1 EUR</td></tr><tr><td>Guatemala</td><td>1 GTQ</td></tr><tr><td>Guyana</td><td>6300 GYD</td></tr><tr><td>Hong Kong</td><td>0 HKD</td></tr><tr><td>Hungary</td><td>360 HUF</td></tr><tr><td>Iceland</td><td>1 EUR</td></tr><tr><td>India</td><td>1 INR</td></tr><tr><td>Indonesia</td><td>0 IDR</td></tr><tr><td>Ireland</td><td>1 EUR</td></tr><tr><td>Israel</td><td>0 ILS</td></tr><tr><td>Italy</td><td>1 EUR</td></tr><tr><td>Jamaica</td><td>1 JMD</td></tr><tr><td>Japan</td><td>1000 JPY</td></tr><tr><td>Jordan</td><td>1 JOD</td></tr><tr><td>Kazakhstan</td><td>1 KZT</td></tr><tr><td>Kenya</td><td>1 KES</td></tr><tr><td>Kuwait</td><td>1 KWD</td></tr><tr><td>Laos</td><td>516000 LAK</td></tr><tr><td>Latvia</td><td>1 EUR</td></tr><tr><td>Liechtenstein</td><td>1 EUR</td></tr><tr><td>Lithuania</td><td>1 EUR</td></tr><tr><td>Luxembourg</td><td>1 EUR</td></tr><tr><td>Macao SAR China</td><td>1 MOP</td></tr><tr><td>Madagascar</td><td>132300 MGA</td></tr><tr><td>Malaysia</td><td>133 MYR</td></tr><tr><td>Malta</td><td>1 EUR</td></tr><tr><td>Mauritius</td><td>1 MUR</td></tr><tr><td>Mexico</td><td>10 MXN</td></tr><tr><td>Moldova</td><td>500 MDL</td></tr><tr><td>Monaco</td><td>1 EUR</td></tr><tr><td>Mongolia</td><td>105000 MNT</td></tr><tr><td>Morocco</td><td>0 MAD</td></tr><tr><td>Mozambique</td><td>1700 MZN</td></tr><tr><td>Namibia</td><td>550 NAD</td></tr><tr><td>Netherlands</td><td>1 EUR</td></tr><tr><td>New Zealand</td><td>0 NZD</td></tr><tr><td>Niger</td><td>1 XOF</td></tr><tr><td>Nigeria</td><td>1 NGN</td></tr><tr><td>North Macedonia</td><td>1500 MKD</td></tr><tr><td>Norway</td><td>20 NOK</td></tr><tr><td>Oman</td><td>1 OMR</td></tr><tr><td>Pakistan</td><td>1 PKR</td></tr><tr><td>Panama</td><td>50 USD</td></tr><tr><td>Paraguay</td><td>210000 PYG</td></tr><tr><td>Peru</td><td>0 PEN</td></tr><tr><td>Philippines</td><td>20 PHP</td></tr><tr><td>Poland</td><td>5 PLN</td></tr><tr><td>Portugal</td><td>1 EUR</td></tr><tr><td>Qatar</td><td>1 QAR</td></tr><tr><td>Romania</td><td>5 RON</td></tr><tr><td>Rwanda</td><td>100 RWF</td></tr><tr><td>San Marino</td><td>1 EUR</td></tr><tr><td>Saudi Arabia</td><td>1 SAR</td></tr><tr><td>Senegal</td><td>1 XOF</td></tr><tr><td>Serbia</td><td>3000 RSD</td></tr><tr><td>Singapore</td><td>1 SGD</td></tr><tr><td>Slovakia</td><td>1 EUR</td></tr><tr><td>Slovenia</td><td>1 EUR</td></tr><tr><td>South Africa</td><td>100 ZAR</td></tr><tr><td>South Korea</td><td>40000 KRW</td></tr><tr><td>Spain</td><td>1 EUR</td></tr><tr><td>Sri Lanka</td><td>1 LKR</td></tr><tr><td>St. Lucia</td><td>1 XCD</td></tr><tr><td>Sweden</td><td>20 SEK</td></tr><tr><td>Switzerland</td><td>1 EUR</td></tr><tr><td>Taiwan</td><td>800 TWD</td></tr><tr><td>Tanzania</td><td>1 TZS</td></tr><tr><td>Thailand</td><td>600 THB</td></tr><tr><td>Trinidad &#x26; Tobago</td><td>0 TTD</td></tr><tr><td>Tunisia</td><td>0 TND</td></tr><tr><td>Turkey</td><td>5 TRY</td></tr><tr><td>United Arab Emirates</td><td>5 AED</td></tr><tr><td>United Kingdom</td><td>1 GBP</td></tr><tr><td>Uruguay</td><td>0 UYU</td></tr><tr><td>Uzbekistan</td><td>343000 UZS</td></tr><tr><td>Vietnam</td><td>1 VND</td></tr></tbody></table>

Acquiring fees, where applicable, are based on the settlement currency, and you can find these acquiring fees listed by currency on your country’s pricing page.

#### Multiple bank accounts for different settlement currencies

In some countries, Fungies users can add additional bank accounts to enable settlements and payouts in different currencies. You can add one bank account per supported settlement currency. If you use multiple bank accounts, you must select a default settlement currency, which can be changed at any time.

Charges presented in any enabled settlement currency settle without currency conversion. However, payments made in a currency for which you haven’t set up an additional bank account will automatically convert to your default currency.

For example, a Fungies user in the United Kingdom with both GBP and USD bank accounts, where GBP is the default currency, will have USD payments (where USD is the presentment currency) paid out to the USD bank account without conversion. Payments in other currencies will be converted to GBP.

You can manage your bank accounts and default settlement currency by visiting **Bank accounts and scheduling** in the Dashboard.

#### Payout schedule

**Time zone difference**:\
All payments and payouts are processed according to UTC time, except for Asia-Pacific (APAC) markets. As a result, the processed date may not be the same as your local time zone.

Your payout schedule determines how often Fungies sends money to your bank account.

In supported countries, your default payout schedule is daily automatic. You can change this in the Dashboard to weekly automatic, monthly automatic, or manual payouts. For weekly or monthly payouts, you can specify the day of the week or month when you want payouts to arrive in your bank account.

* **Monthly payout schedules**: If the selected payout arrival day extends beyond the last day of a particular month, the payout will automatically adjust to the last day of that month.
* **Weekly and monthly schedules**: If the chosen payout day is a non-business day, the payout will arrive on the next business day.

Selecting a payout schedule does not change how long it takes for your pending balance to become available. However, it gives you control over when payouts occur. For example, with a daily payout schedule and a 3-business-day payout speed, Fungies pays out funds daily from transactions captured 3 business days earlier.

**Country-specific restrictions on payout schedules**:

* In Brazil and India, payouts are always automatic and daily.
* In Japan, daily payouts are unavailable, with the default set to weekly (Fridays).

**Manual payouts**:\
If you turn off automatic payouts in the Dashboard, you can manually send funds to your bank account via the Dashboard or by creating payouts using the API. Manual payouts are available in most regions except Brazil and India, where payouts are always automatic and daily. Typically, manual payouts take 1-4 business days to arrive in your bank account after initiation.

#### Payout speed

While the payout schedule refers to when payouts occur, payout speed refers to how long it takes for your funds to become available. This varies by country and is often expressed as T+X days.

In Fungies, “T” refers to the time of the original transaction confirmation or capture. For example, with a T+3 payout speed and a manual payout schedule, your Fungies balance becomes available within three business days after payment capture. If you use a daily automatic payout schedule, payouts are made daily for transactions captured three business days prior.

**Accelerated payout speeds**:\
Fungies offers accelerated payout speeds in some regions (Europe, the UK, Mexico, and Canada) for accounts that meet specific risk and eligibility criteria. When eligible, funds become available within 3 business days. You can opt in or out of accelerated payout speeds via the Dashboard.

**Delay behavior by account country**:\
You can set delay\_days on connected accounts. The type of delay (business or calendar days) varies by country. For example, in the United States, delays apply in business days, while in most EU countries, delays apply in calendar days.

**Payout speed by country**:\
Use the following table to check the payout speed for your country. The initial payout speed applies until you meet the eligibility criteria for accelerated payouts.

#### Minimum payout amounts

Minimum payout amounts depend on the lowest threshold supported by Fungies’ banking partners. If your available balance is less than the minimum payout amount, it will remain in your Fungies account until more payments are received.

#### Negative payouts

Each payout reflects your available account balance. If your account balance is negative (e.g., from refunds), Fungies may debit your bank account for the shortfall. Ensure that your bank account supports both credit and debit transactions.

#### Payout failures

If a payout fails, the bank returns the funds to Fungies, which can take up to 5 business days. You’ll receive a notification in the Dashboard if this happens, and you may need to re-enter your bank details to resolve the issue.

#### Instant Payouts

With Instant Payouts, you can transfer funds to a supported debit card or bank account instantly. Instant Payouts are available 24/7, including weekends and holidays, with funds typically arriving within 30 minutes. New Fungies users may not be immediately eligible for Instant Payouts, but you can check your eligibility in the Dashboard.


# Editing Statement Descriptor

Whenever a customer is charged, he/she will see on the credit card history the company's name that was responsible for the amount charged.

You can now edit that information to include the name of your business next to Fungies, so that customers know what the payment was for or from whom he/she bought the digital product from. Bear in mind that FUNGIES will still appear as the first part of statement descriptor.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FfeQiAyEWLxWRkIEFfwlh%2Fimage.png?alt=media&amp;token=76213fd3-6482-4865-b499-39aedc2e356c" alt=""><figcaption><p>Edit Statement Descriptor in Settings -> General.</p></figcaption></figure>

After providing your business's name, future card charges will appear as:

FUNGIES \* YOUR\_BUSINESS\_NAME


# Transactions Reports

For accounting and reporting reasons - you might find downloading all historical payments a must-have feature.

Go to Reports in your Dashboard:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F4xdy79jpP9jTmvQyueAU%2Fimage.png?alt=media&amp;token=9515a678-1646-4cca-b84c-e75748e390f9" alt=""><figcaption><p>Access Reports from the Dashboard to generate lists of historical transactions in CSV format</p></figcaption></figure>

And choose your desired reporting period:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FNQXQA8ebLjzjOR0WTY62%2Fimage.png?alt=media&amp;token=1a197cc9-cf2d-4a4e-870e-aab932197bf8" alt=""><figcaption><p>Generate all transactions from chosen period</p></figcaption></figure>

Once the report is generated, simply download and view it (CSV file):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FF68ax6V0lghHa6v65waZ%2Fimage.png?alt=media&amp;token=f364c275-071e-4ad3-a27b-1daf6d0f005e" alt=""><figcaption><p>All transactions generated for a given period with detailed data such as Country, Tax Amounts and Payment Processing channel</p></figcaption></figure>


# Example React checkout

In this example, we have 4 payment plans - this code will ensure that when an user clicks a button on that plan, an Overlay Checkout will be shown with custom field user\_id prepopulated from the app.

```
import React, { useEffect } from "react";
import { Button } from "@/components/ui/button";
import { useChatContext } from "@/contexts/ChatContext";
import { Check } from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";

interface PlanProps {
  nameEn: string;
  namePl: string;
  price: string;
  descriptionEn: string;
  descriptionPl: string;
  features: string[];
  advantages: string[];
  popular?: boolean;
  onSelect: (plan: string) => void;
  currentPlan: string;
}

export const PlanCard: React.FC<PlanProps> = ({
  nameEn,
  namePl,
  price,
  descriptionEn,
  descriptionPl,
  features,
  advantages,
  popular = false,
  onSelect,
  currentPlan,
}) => {
  const { language } = useChatContext();
  const { user } = useAuth();
  const isPolish = language === "pl";
  const name = isPolish ? namePl : nameEn;
  const description = isPolish ? descriptionPl : descriptionEn;
  
  const isCurrentPlan = nameEn === currentPlan; // Keep plan name matching with English keys
  const popularText = isPolish ? "Popularne" : "Popular";
  const currentPlanText = isPolish ? "Aktualny Plan" : "Current Plan";
  const selectPlanText = isPolish ? "Wybierz Plan" : "Select Plan";
  const featuresTitle = isPolish ? "Funkcje" : "Features";
  const advantagesTitle = isPolish ? "Korzyści planu" : "Plan Benefits";
  
  // Get the user ID for checkout
  const userId = user?.id || '';
  
  // Define checkout URLs for each plan
  const checkoutUrls = {
    Basic: 'https://doktorek.app.fungies.io/checkout-element/bd36508e-bfff-48d7-bb15-234b7bf093b7',
    Standard: 'https://doktorek.app.fungies.io/checkout-element/5a4a85d6-0116-498e-b234-277f11373052',
    Premium: 'https://doktorek.app.fungies.io/checkout-element/5c195bd3-498e-4d7f-97c2-754f401163f9',
    Pro: 'https://doktorek.app.fungies.io/checkout-element/4ce11d81-2459-4ec7-967d-e74e0e18a795'
  };
  
  // Get the appropriate checkout URL for this plan
  const checkoutUrl = checkoutUrls[nameEn as keyof typeof checkoutUrls];
  
  // Generate the JSON-formatted custom fields string with the user ID
  const customFieldsJson = JSON.stringify({ user_id: userId });
  
  // Determine if this plan uses Fungies checkout (all plans now use it)
  const usesFungiesCheckout = checkoutUrl !== undefined;
  
  // Load Fungies checkout script dynamically
  useEffect(() => {
    if (usesFungiesCheckout) {
      const existingScript = document.getElementById('fungies-checkout-script');
      if (!existingScript) {
        const script = document.createElement('script');
        script.id = 'fungies-checkout-script';
        script.src = 'https://cdn.jsdelivr.net/npm/@fungies/fungies-js@0.0.6';
        script.defer = true;
        script.dataset.autoInit = "";
        document.body.appendChild(script);
      }
    }
  }, [usesFungiesCheckout]);
  
  return (
    <div className={`rounded-lg border ${popular ? 'border-green-500 shadow-md' : 'border-gray-200'} p-6 relative flex flex-col h-full`}>
      {popular && (
        <div className="absolute -top-3 left-1/2 transform -translate-x-1/2 bg-green-500 text-white text-xs font-semibold py-1 px-3 rounded-full">
          {popularText}
        </div>
      )}
      <h3 className="font-semibold text-lg">{name}</h3>
      <div className="mt-2 mb-4">
        <span className="text-2xl font-bold whitespace-nowrap">{price}</span>
      </div>
      <p className="text-gray-500 mb-4 text-sm">{description}</p>
      
      {/* Plan advantages */}
      {advantages && advantages.length > 0 && (
        <div className="mb-4">
          <h4 className="text-sm font-medium text-gray-700 mb-2">{advantagesTitle}</h4>
          <ul className="space-y-2">
            {advantages.map((advantage, index) => (
              <li key={`advantage-${index}`} className="flex items-center text-sm">
                <Check className="h-4 w-4 text-green-500 mr-2 flex-shrink-0" />
                <span className="text-gray-600 font-medium">{advantage}</span>
              </li>
            ))}
          </ul>
        </div>
      )}
      
      {/* Common features with lighter styling */}
      <div className="mb-4 mt-auto">
        <h4 className="text-xs font-medium text-gray-500 mb-2">{featuresTitle}</h4>
        <ul className="space-y-1">
          {features.map((feature, index) => (
            <li key={`feature-${index}`} className="flex items-center text-xs">
              <Check className="h-3 w-3 text-green-400 mr-1 flex-shrink-0" />
              <span className="text-gray-500">{feature}</span>
            </li>
          ))}
        </ul>
      </div>
      
      {usesFungiesCheckout ? (
        <button 
          className={`w-full mt-4 ${isCurrentPlan ? 'bg-gray-400 hover:bg-gray-500' : 'bg-green-600 hover:bg-green-700'} text-white py-2 px-4 rounded-md`}
          disabled={isCurrentPlan}
          data-fungies-checkout-url={checkoutUrl}
          data-fungies-custom-fields={customFieldsJson}
          data-fungies-mode='overlay'
        >
          {isCurrentPlan ? currentPlanText : selectPlanText}
        </button>
      ) : (
        <Button 
          className={`w-full mt-4 ${isCurrentPlan ? 'bg-gray-400 hover:bg-gray-500' : 'bg-green-600 hover:bg-green-700'} text-white`}
          onClick={() => onSelect(nameEn)}
          disabled={isCurrentPlan}
        >
          {isCurrentPlan ? currentPlanText : selectPlanText}
        </Button>
      )}
    </div>
  );
};
```


# Fungies CLI

The Fungies CLI lets you manage your entire store from the terminal — query orders, look up customers, manage subscriptions, export data, and automate workflows without opening the dashboard.

GitHub: <https://github.com/dukenukemall/fungies-cli>

### Requirements

* **Node.js 18 or higher** — [download here](https://nodejs.org/)
* A Fungies account — [register here](https://app.fungies.io/register)

***

### Step 1 — Install the CLI

Open your terminal and run:

```
npm install -g fungies
```

Verify the installation:

```
fungies --version
```

You should see something like `fungies/0.4.2 ...`

***

### Step 2 — Get your API Keys

Go to your [Fungies Dashboard](https://app.fungies.io/devs/api-keys) → **Developers → API Keys** and generate your keys.

You'll get two types:

| Key            | Prefix    | Used for                                   |
| -------------- | --------- | ------------------------------------------ |
| **Public Key** | `pub_...` | All read operations (list, get)            |
| **Secret Key** | `sec_...` | Write operations (create, update, archive) |

> ⚠️ Keep your Secret Key private. Never share it or commit it to version control.

***

### Step 3 — Authenticate

Run the following command and paste in your keys:

```
fungies auth set --public-key pub_YOUR_KEY_HERE --secret-key sec_YOUR_KEY_HERE
```

If you only need read access (no writes), you can omit the secret key:

```
fungies auth set --public-key pub_YOUR_KEY_HERE
```

#### First-run wizard

If this is your first time running any CLI command, you'll be guided through setup automatically:

```
  Welcome to Fungies CLI! 🍄
  Let's get you connected to your store.

  Get your API keys at: https://app.fungies.io/devs/api-keys

┌  Quick Setup
│
◆  Public Key
│  pub_...
│
◆  Secret Key (press Enter to skip)
│  sec_...
│
└  ✓ Connected! Run `fungies auth whoami` to verify
```

***

### Step 4 — Verify the connection

```
fungies auth whoami
```

Expected output:

```
✓ Connected | Public: pub_****abc= | Secret: sec_****xyz=
```

***

### Your first commands

#### List your orders

```
fungies orders list
```

#### List your payments

```
fungies payments list
```

#### Find a customer by email

```
fungies users list --search customer@example.com
```

#### View a customer's purchase history

```
fungies users inventory <user-id>
```

#### List active subscriptions

```
fungies subscriptions list --status active
```

#### List discount codes

```
fungies discounts list
```

***

### Output formats

All list commands support the `--format` flag for different output types:

```
fungies orders list --format table    # Default — human-readable table
fungies orders list --format json     # Raw JSON output
fungies orders list --format csv      # CSV — pipe to a file for export
```

**Export example:**

```
fungies payments list --limit 100 --format csv > payments.csv
```

***

### Available commands

| Area              | Commands                                                                                                                 |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **Auth**          | `auth set`, `auth whoami`, `auth clear`                                                                                  |
| **Orders**        | `orders list`, `orders get`, `orders cancel`                                                                             |
| **Payments**      | `payments list`, `payments get`                                                                                          |
| **Products**      | `products list`, `products get`, `products create`, `products update`, `products archive`, `products duplicate`          |
| **Offers**        | `offers list`, `offers get`, `offers create`, `offers update`, `offers archive`, `offers keys add`, `offers keys remove` |
| **Subscriptions** | `subscriptions list`, `subscriptions get`, `subscriptions cancel`, `subscriptions pause`, `subscriptions charge`         |
| **Discounts**     | `discounts list`, `discounts get`, `discounts create`, `discounts update`, `discounts archive`                           |
| **Users**         | `users list`, `users get`, `users create`, `users update`, `users archive`, `users unarchive`, `users inventory`         |
| **Elements**      | `elements list`, `elements create`, `elements open`                                                                      |

Run `fungies --help` to see all commands, or `fungies <command> --help` for details on a specific one.

***

### Managing keys

#### Update your keys

```
fungies auth set --public-key pub_NEW_KEY --secret-key sec_NEW_KEY
```

#### Remove saved keys

```
fungies auth clear
```

***

### Troubleshooting

#### `Not authenticated` error

Your keys aren't saved. Run:

```
fungies auth set --public-key pub_... --secret-key sec_...
```

#### `Authentication failed`

Double-check your keys in the [dashboard](https://app.fungies.io/devs/api-keys). Make sure you're using the correct prefix (`pub_` for public, `sec_` for secret).

#### `command not found: fungies`

Node.js global bin isn't in your PATH. Try:

```
npx fungies --version
```

Or reinstall with:

```
npm install -g fungies
```

***

### Need help?

* 📖 **API Reference:** [docs.fungies.io](https://docs.fungies.io/api-reference/introduction)
* 💬 **Discord:** [discord.gg/yfH5ZyTZH4](https://discord.gg/yfH5ZyTZH4)
* 🛠️ **Issues:** [github.com/dukenukemall/fungies-cli](https://github.com/dukenukemall/fungies-cli)


# Fungies MCP

### What you can do

Fungies MCP is the official [Model Context Protocol](https://modelcontextprotocol.io/) server for the [Fungies](https://fungies.io/) Merchant of Record platform. Once installed, your AI assistant can:

* **Browse your catalog** — list products, offers, and pricing tiers
* **Manage pricing** — create offers, update plans, set up subscriptions
* **Handle orders & refunds** — look up orders, cancel pending ones, review payment history
* **Manage customers** — find accounts, see what they've purchased, update billing details
* **Run promotions** — create coupon codes and automatic sale discounts
* **Ship game keys** — upload license-key inventory, track what's sold
* **Audit webhooks** — inspect delivery attempts, verify signatures locally
* **Grow subscriptions** — pause, resume, cancel, or charge usage-based extras

All of this happens through natural language — no API documentation required.


# Quick start

#### Step 1 — Get your Fungies API keys

1. Log in at [app.fungies.io](https://app.fungies.io/).
2. Go to **Developers → API Keys** ([direct link](https://app.fungies.io/devs/api-keys)).
3. Click **Create key pair** and name it something like `Cursor MCP` or `My AI assistant`.
4. You'll see two values:
   * A **public key** starting with `pub_...` — safe to show, used on every call.
   * A **secret key** starting with `sec_...` — **keep this private**, unlocks write operations.
5. Copy both into a password manager. You will paste them into your AI tool in Step 2.

> **Tip** — make a dedicated key pair just for the MCP. If something ever feels off, you can revoke it from the dashboard without breaking your other integrations.

#### Step 2 — Pick your AI tool and install

Two ways:

**Option A — One-click install page (easiest for Cursor)**

Open [**https://mcp.fungies.io/install**](https://mcp.fungies.io/install), paste your keys, and click **Install read-only** or **Install read + write**. Cursor opens and asks you to confirm. Done.

*Your keys never touch our servers — the install page assembles the config in your browser and hands it off to Cursor through a local deep link.*

**Option B — Manual config for your specific tool**

Follow the [tool-specific guide below](https://github.com/dukenukemall/fungies-mcp#pick-your-ai-tool).

#### Step 3 — Try it out

Ask your AI assistant:

> *"List my five most recent products on Fungies."*

If you see a list of products, you're done. If you hit an error, jump to [Troubleshooting](https://github.com/dukenukemall/fungies-mcp#troubleshooting).


# Cursor, Claude, VS Code integration

### Pick your AI tool

All configs use the same hosted endpoint: `https://mcp.fungies.io/mcp`. No local installation, no Node.js, no Docker.

#### Cursor

**Option A — One-click (recommended)**

Visit [mcp.fungies.io/install](https://mcp.fungies.io/install), paste your keys, click Install.

**Option B — Manual**

1. Open the Cursor settings JSON — press `Cmd/Ctrl + Shift + P`, search for **"Open MCP Settings"**, or edit `~/.cursor/mcp.json` directly.
2. Add this block:

```
{
  "mcpServers": {
    "fungies": {
      "url": "https://mcp.fungies.io/mcp",
      "headers": {
        "x-fngs-public-key": "pub_YOUR_PUBLIC_KEY",
        "x-fngs-secret-key": "sec_YOUR_SECRET_KEY"
      }
    }
  }
}
```

3. Restart Cursor. Open the Agent panel — you should see **"fungies"** in the tool list.

Omit `x-fngs-secret-key` for read-only mode (17 tools, no risk of accidental changes).

#### Claude Desktop

Claude Desktop supports remote MCP servers via its custom connectors UI.

1. Open Claude Desktop → **Settings → Connectors → Add custom connector**.
2. Fill in:
   * **Name**: `Fungies`
   * **Remote MCP server URL**: `https://mcp.fungies.io/mcp`
3. Under **Advanced → Custom headers**, add:
   * `x-fngs-public-key` → your `pub_...` key
   * `x-fngs-secret-key` → your `sec_...` key (optional)
4. Save. Start a new chat and Claude will offer Fungies tools.

> **Older Claude Desktop (no custom-connectors UI)** — use the [stdio fallback](https://github.com/dukenukemall/fungies-mcp#other-mcp-clients-stdio-fallback) at the bottom of this doc.

#### Claude Code (CLI)

Claude Code has native remote-MCP support via the `claude mcp add` command.

```
claude mcp add --transport http fungies https://mcp.fungies.io/mcp \
  --header "x-fngs-public-key: pub_YOUR_PUBLIC_KEY" \
  --header "x-fngs-secret-key: sec_YOUR_SECRET_KEY"
```

Verify with `claude mcp list` — you should see `fungies` listed. Start any chat and Claude Code will discover the tools automatically.

#### VS Code (GitHub Copilot Chat)

VS Code 1.95+ with GitHub Copilot Chat supports MCP servers.

1. Open the command palette — `Cmd/Ctrl + Shift + P`.
2. Run **"MCP: Add server → HTTP"**.
3. When prompted:
   * **URL**: `https://mcp.fungies.io/mcp`
   * **Name**: `fungies`
4. Open `~/.config/Code/User/mcp.json` (or `%APPDATA%\Code\User\mcp.json` on Windows) and add the headers:

```
{
  "servers": {
    "fungies": {
      "type": "http",
      "url": "https://mcp.fungies.io/mcp",
      "headers": {
        "x-fngs-public-key": "pub_YOUR_PUBLIC_KEY",
        "x-fngs-secret-key": "sec_YOUR_SECRET_KEY"
      }
    }
  }
}
```

5. Reload VS Code. Open Copilot Chat in **Agent** mode — Fungies tools appear in the tool picker.

#### Continue.dev

Edit `~/.continue/config.yaml` (or through Continue's settings UI):

```
mcpServers:
  - name: fungies
    type: http
    url: https://mcp.fungies.io/mcp
    requestOptions:
      headers:
        x-fngs-public-key: pub_YOUR_PUBLIC_KEY
        x-fngs-secret-key: sec_YOUR_SECRET_KEY
```

Restart Continue — Fungies tools show up in any agent session.

#### Windsurf

1. Open **Settings → Windsurf Settings → Cascade → MCP Servers → Add custom server**.
2. Paste:

```
{
  "mcpServers": {
    "fungies": {
      "serverUrl": "https://mcp.fungies.io/mcp",
      "headers": {
        "x-fngs-public-key": "pub_YOUR_PUBLIC_KEY",
        "x-fngs-secret-key": "sec_YOUR_SECRET_KEY"
      }
    }
  }
}
```

3. Save and refresh the server list. Fungies tools appear in Cascade.

#### OpenAI Codex CLI

Codex CLI supports remote MCP servers via `~/.codex/config.toml`:

```
[mcp_servers.fungies]
url = "https://mcp.fungies.io/mcp"

[mcp_servers.fungies.headers]
"x-fngs-public-key" = "pub_YOUR_PUBLIC_KEY"
"x-fngs-secret-key" = "sec_YOUR_SECRET_KEY"
```

Run `codex` in any terminal — it will pick up the config and expose Fungies tools to the session.

#### Zed

Zed 0.160+ ships MCP ("context servers") support. Add to `~/.config/zed/settings.json`:

```
{
  "context_servers": {
    "fungies": {
      "source": "custom",
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.fungies.io/mcp",
        "--header",
        "x-fngs-public-key:pub_YOUR_PUBLIC_KEY",
        "--header",
        "x-fngs-secret-key:sec_YOUR_SECRET_KEY"
      ]
    }
  }
}
```

Zed bridges to our HTTP endpoint through the [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) helper (ships via `npx`, no install needed).

#### Other MCP clients (stdio fallback)

If your MCP host only speaks stdio, use `mcp-remote` as a bridge. Replace the `command`/`args` in your host's config with:

```
{
  "command": "npx",
  "args": [
    "-y",
    "mcp-remote",
    "https://mcp.fungies.io/mcp",
    "--header",
    "x-fngs-public-key:pub_YOUR_PUBLIC_KEY",
    "--header",
    "x-fngs-secret-key:sec_YOUR_SECRET_KEY"
  ]
}
```

This works for any client that supports a local `command` + `args` style stdio server (older Claude Desktop builds, LibreChat, Goose, Sourcegraph Cody, etc.).


# MCP Capabilities

### Read-only vs full access

You choose the power level by which key you give the MCP.

| Mode            | Headers sent                                    | Tools exposed                                               | Good for                          |
| --------------- | ----------------------------------------------- | ----------------------------------------------------------- | --------------------------------- |
| **Read-only**   | `x-fngs-public-key` only                        | 17 (list/get/inventory/verify)                              | Analytics, reporting, exploration |
| **Full access** | `x-fngs-public-key` **and** `x-fngs-secret-key` | 40 (adds create / update / archive / cancel / refund flows) | Day-to-day store management       |

You can install Fungies twice with different names — e.g. `fungies-read` and `fungies-write` — to keep destructive tools behind an explicit switch.

All destructive tools (`*_archive`, `*_cancel`, `offers_keys_remove`) additionally require `confirm: true` in the call, so your AI cannot accidentally wipe things out.

***

### Full capabilities (40 tools)

All tools return structured JSON suitable for follow-up reasoning. Read-only tools are marked **R**, write tools **W**, destructive tools **D**.

#### Products — 6 tools

| Tool                 | Type | What it does                                                                     |
| -------------------- | ---- | -------------------------------------------------------------------------------- |
| `products_list`      | R    | Browse / search / count products in your catalog                                 |
| `products_get`       | R    | Full details of one product (variants, plans, status)                            |
| `products_duplicate` | W    | Clone a product as a starting point for a new one                                |
| `products_create`    | W    | Create a new product (`OneTimePayment`, `Subscription`, `Membership`, `GameKey`) |
| `products_update`    | W    | Rename, rewrite copy, change slug                                                |
| `products_archive`   | D    | Soft-delete a product (also archives its offers)                                 |

#### Offers & price points — 5 tools

| Tool             | Type | What it does                                                     |
| ---------------- | ---- | ---------------------------------------------------------------- |
| `offers_list`    | R    | Browse offers, filter by product                                 |
| `offers_get`     | R    | Details of a single offer (price, currency, interval, inventory) |
| `offers_create`  | W    | Add a price point to a product (one-off or recurring)            |
| `offers_update`  | W    | Rename an offer (price/currency are immutable)                   |
| `offers_archive` | D    | Retire an offer; active subscriptions keep running               |

#### Game keys / license keys — 2 tools

| Tool                 | Type | What it does                                           |
| -------------------- | ---- | ------------------------------------------------------ |
| `offers_keys_add`    | W    | Upload new license/game keys into an offer's inventory |
| `offers_keys_remove` | D    | Pull an unsold key back; sold keys are preserved       |

#### Orders — 3 tools

| Tool            | Type | What it does                                                 |
| --------------- | ---- | ------------------------------------------------------------ |
| `orders_list`   | R    | Filter orders by status, date, recency                       |
| `orders_get`    | R    | Full details by UUID or short order number (e.g. `9XMrb9Hk`) |
| `orders_cancel` | D    | Mark an order CANCELLED (does not auto-refund)               |

#### Subscriptions — 7 tools

| Tool                   | Type | What it does                                          |
| ---------------------- | ---- | ----------------------------------------------------- |
| `subscriptions_list`   | R    | Filter by status: active, canceled, paused, past\_due |
| `subscriptions_get`    | R    | Full details: offer, period, cancel date              |
| `subscriptions_create` | W    | Programmatic create (migration / backfill)            |
| `subscriptions_update` | W    | Upgrade/downgrade, change billing                     |
| `subscriptions_cancel` | D    | Cancel end-of-period or immediately, optional refund  |
| `subscriptions_pause`  | W    | Pause billing; access stays active                    |
| `subscriptions_charge` | W    | Charge a one-off extra (usage-based billing)          |

#### Customers — 7 tools

| Tool              | Type | What it does                                                 |
| ----------------- | ---- | ------------------------------------------------------------ |
| `users_list`      | R    | Search by email or username                                  |
| `users_get`       | R    | Full customer profile                                        |
| `users_inventory` | R    | Everything a customer owns (products, subscriptions, access) |
| `users_create`    | W    | Create a customer record (migration, manual entry)           |
| `users_update`    | W    | Edit email, username, billing details                        |
| `users_archive`   | D    | Soft-delete, reversible                                      |
| `users_unarchive` | W    | Restore a previously archived customer                       |

#### Discounts — 5 tools

| Tool                | Type | What it does                                        |
| ------------------- | ---- | --------------------------------------------------- |
| `discounts_list`    | R    | Active or archived coupons and sales                |
| `discounts_get`     | R    | Full details of a discount                          |
| `discounts_create`  | W    | Coupon (code-redeemable) or sale (auto), % or fixed |
| `discounts_update`  | W    | Rename, adjust validity window                      |
| `discounts_archive` | D    | Retire a discount                                   |

#### Payments — 2 tools

| Tool            | Type | What it does                                         |
| --------------- | ---- | ---------------------------------------------------- |
| `payments_list` | R    | All transactions, filter by PAID / FAILED / REFUNDED |
| `payments_get`  | R    | Single payment (fee, tax, invoice URL)               |

#### Checkout elements — 2 tools

| Tool              | Type | What it does                                          |
| ----------------- | ---- | ----------------------------------------------------- |
| `elements_list`   | R    | All embeddable checkout widgets in the store          |
| `elements_create` | W    | Bind a set of offers into a reusable checkout element |

#### Webhooks — 1 tool

| Tool              | Type | What it does                                                                                                                                                                                                                  |
| ----------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `webhooks_verify` | R    | Verify a Fungies webhook signature locally (HMAC-SHA256, timing-safe; no network call). Fungies does not expose a webhook delivery log over the API — use the Fungies dashboard → Developers → Webhooks for delivery history. |

***

### Example prompts

Paste any of these into your AI chat once the MCP is installed.

**Analytics**

> "How many paid orders did I have in the last 7 days? Break it down by product."

> "Show me my 10 biggest customers by lifetime spend."

> "Which subscription offers have the highest churn this quarter?"

**Catalog operations**

> "Duplicate 'Pro Plan' and call the copy 'Pro Plan — EUR'. Then create a €99 yearly offer for it."

> "Add these 500 Steam keys to the 'Indie Bundle' offer."

> "List every offer that's priced under $5."

**Customer support**

> "Find the customer with email `alice@example.com`, show me her inventory, and cancel any active subscriptions at period end."

> "What's the payment status of order 9XMrb9Hk?"

**Promotions**

> "Create a 25% off coupon code `WINTER25` that's valid from now until January 15th."

> "Archive all coupons whose validity window ended before this year."

**Webhooks**

> "Here's a webhook body and the `x-fngs-signature` header. Tell me if the signature is valid given my signing secret."

***

### Security & safety

Fungies MCP is built so your AI can be powerful without being dangerous.

* **No credential storage.** Keys live only in your AI tool's local config. Every request forwards them to `api.fungies.io` and the server forgets them.
* **Read-only install option.** If you only need analytics, use the public key alone — 23 write / destructive tools simply never appear.
* **Destructive confirm gate.** Archive / cancel / remove-key tools require the caller to pass `confirm: true`. Hosts that surface this to you (like Cursor's tool-call dialog) will ask before proceeding.
* **Tool annotations.** Every tool advertises `readOnlyHint` / `destructiveHint` / `idempotentHint` so your AI can reason about risk before calling.
* **Strict input validation.** Every tool input is a `.strict()` Zod object — unknown fields are rejected. All IDs must match `^[A-Za-z0-9_-]{1,64}$`, which blocks path traversal attacks against the upstream API.
* **Origin allowlist.** Browser `Origin` headers are checked against an allowlist (app schemes like `cursor://`, `vscode://` always pass; arbitrary websites are blocked with 403 — defeats DNS rebinding / CSRF).
* **Hard limits.** `/mcp` enforces a 256 KB body cap (413 `payload_too_large`) and a 300 req/min per-key rate limit (+ 120 req/min per IP on everything).
* **Nonce-based CSP on `/install`.** `default-src 'none'` with per-request nonces — no third-party scripts, no inline exec, no framing.
* **Log redaction + audit trail.** `pino` with strict redaction — your keys never show up in logs. Every write call records `{ tool, publicKey (masked), requestId }` with PII fields (email, billingDetails) replaced with `[REDACTED]`.
* **HTTPS-only upstream.** In production the server refuses to start if `FUNGIES_API_BASE` isn't `https://`.
* **Your data is yours.** The server never reads from or writes to a database; it is a pure passthrough to the Fungies API over TLS.
* **Revocation is one click.** Delete the key pair from the Fungies dashboard and the MCP becomes inert immediately.

If you spot a security issue, please report it privately via [help.fungies.io](https://help.fungies.io/).

***

### Troubleshooting

**"missing\_or\_invalid\_public\_key" (HTTP 401)** Your `x-fngs-public-key` header is missing or not in the `pub_...` shape. Recheck the value in your MCP config.

**"invalid\_secret\_key" (HTTP 401)** Your `x-fngs-secret-key` header is present but doesn't match the `sec_...` shape. Either fix it or remove the header to fall back to read-only mode.

**Tools list is empty in my AI tool**

1. Confirm your AI tool says the server is **connected** (not "starting" / "error").
2. Hit `https://mcp.fungies.io/healthz` in a browser — you should see `{"ok":true, ...}`.
3. Restart your AI tool after editing config — MCP clients only read it on startup.

**"Forbidden" errors on write tools** You installed with the public key only. Re-install with both keys (or add `x-fngs-secret-key` to the existing config) and restart.

**"Rate limited" messages** The upstream Fungies API is throttling. The server automatically retries GET/PATCH/DELETE on 429/5xx, but POST is not retried. Try again in a minute.

**Tool call hangs / times out** Default per-request timeout is 15 s. Long-running list queries? Narrow with `skip` / `take` or a `termOrId` filter.

Still stuck? Open an issue on [GitHub](https://github.com/dukenukemall/fungies-mcp/issues) or ping us in [Discord](https://discord.gg/yfH5ZyTZH4).

***

### Self-host

Want to run the MCP on your own infrastructure? It's a single container.

```
docker build -t fungies-mcp .
docker run -p 3000:3000 \
  -e PORT=3000 \
  -e NODE_ENV=production \
  -e LOG_LEVEL=info \
  -e FUNGIES_API_BASE=https://api.fungies.io \
  -e MCP_PUBLIC_URL=https://your-domain.example.com \
  fungies-mcp
```

| Env var                  | Default                                    | Notes                                                                                                                |
| ------------------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `PORT`                   | `3000`                                     | HTTP listen port                                                                                                     |
| `NODE_ENV`               | `development`                              | Set to `production` in prod                                                                                          |
| `LOG_LEVEL`              | `info`                                     | `trace` / `debug` / `info` / `warn` / `error`                                                                        |
| `FUNGIES_API_BASE`       | `https://api.fungies.io`                   | Change for staging environments                                                                                      |
| `MCP_PUBLIC_URL`         | `https://mcp.fungies.io`                   | Baked into the `/install` page                                                                                       |
| `FUNGIES_TIMEOUT_MS`     | `15000`                                    | Upstream request timeout                                                                                             |
| `FUNGIES_MAX_RETRIES`    | `2`                                        | Retries for GET / PATCH / DELETE on 429 / 5xx                                                                        |
| `MCP_ALLOWED_ORIGINS`    | `mcp.fungies.io,app.fungies.io,fungies.io` | Comma list of https hosts allowed via `Origin` header (app schemes like `cursor://`, `vscode://` are always allowed) |
| `MCP_MAX_BODY_BYTES`     | `262144`                                   | Max JSON-RPC request size (256 KB)                                                                                   |
| `RATE_LIMIT_IP_PER_MIN`  | `120`                                      | Per-IP request cap across the whole server                                                                           |
| `RATE_LIMIT_KEY_PER_MIN` | `300`                                      | Per-public-key request cap on `/mcp`                                                                                 |

The container runs as a non-root user, ships a health endpoint at `/healthz`, and exposes a clickable onboarding UI at `/install`.


# Hosted Checkout (more payment methods)

While Overlay checkout is great for embedding inside your software or apps - Hosted Checkout offers more Bank Redirect payment methods (especially important in Europe). The reason is the redirect of these methods rather than having all the actions happening inside the Overlay.&#x20;

Examples of Wallet payment methods include:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FWYK4VtCSx4UXdqOFf8zM%2Fimage.png?alt=media&amp;token=87ae2353-dcb2-41cf-be53-9c43ecc73cd6" alt=""><figcaption><p>Bank Redirect payment methods available for Hosted Checkouts</p></figcaption></figure>

So if your Software primarily serves European customers - we advise to put the Currency in EUR and implement Hosted Checkout (as a redirect link / opened as a New Tab).

To check your URL for Hosted Checkout for certain items or subscriptions - you can either navigate to Subscriptions -> Offers and Copy the Payment Link or access your Store and go from there.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F77TczcEgJkP0KC8XOxew%2Fimage.png?alt=media&amp;token=fc160c5c-1001-4c9b-b252-55dccdf12c32" alt=""><figcaption><p>Copy this payment link for Hosted Checkout solution</p></figcaption></figure>

The 2nd option is to navigate to Subscription product and click View:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FdVksv8TSQ01GEWzhATOt%2Fimage.png?alt=media&amp;token=1f222cb1-bf26-45d0-96e2-42f0ef323c37" alt=""><figcaption><p>Click View Product</p></figcaption></figure>

You'll be redirected to your Product's Page:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FdNPvOYwAJUeLsVqWJ3Ux%2Fimage.png?alt=media&amp;token=01dcd4b0-787f-45d1-ac40-f363afecdfc8" alt=""><figcaption><p>You can now preview the Product Page</p></figcaption></figure>

Clicking Subscribe redirects you to your Hosted Checkout layout for the product, you can Copy the URL and share it inside your App/Software.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FFjihyz3oBjXEdjMOt5dE%2Fimage.png?alt=media&amp;token=b1a3d5b8-558a-4fe3-96b8-3a25485a3dc4" alt=""><figcaption><p>Hosted Checkout for Subscription Product</p></figcaption></figure>

To change the default currency for all your products, navigate to Settings -> General -> Currency drop-down:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fh69LTHqMwnForOlifjfn%2Fimage.png?alt=media&amp;token=95d1d8ad-5ce1-4a1c-b52a-a0b8c9c072e7" alt=""><figcaption><p>Change your default currency here</p></figcaption></figure>


# Editing and Pausing Subscriptions

Once you have customers (yay!) subscribing to your product - you can easily edit them in the Dashboard. Simply navigate to Transactions -> Subscriptions and you'll see a list of all active customers that are subscribed to your product:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FJLEiyJnET9SZo6QeSPfV%2Fimage.png?alt=media&amp;token=0e826f70-b3e4-45ee-af56-d1e1f561a963" alt=""><figcaption><p>List of all subscribers</p></figcaption></figure>

You can easily change the number of Seats (Quantity) and Amount (Price) of the Subscription - simply click Edit and a drawer will appear:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FX8CptXUX4FkSknRNYqkA%2Fimage.png?alt=media&amp;token=a00f2af2-4b48-47e5-aef4-9a83f8eb34ab" alt=""><figcaption><p>Editing Subscription with number of seats and amount per seat</p></figcaption></figure>

You can also Pause payment collection (NOTE: this does not affect the subscription periods, only Payment Collection will be paused):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F8leYHaMUj0J6Ab1tPx6P%2Fimage.png?alt=media&amp;token=a6bd9baf-0e59-40b8-8fb9-c09dacbc624f" alt=""><figcaption><p>You'll be presented with a few choices for Payment Collection Pausing</p></figcaption></figure>


# Downgrading / Upgrading Subscriptions

You have the ability to Downgrade or Upgrade subscriptions if you've created different plans for your product.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FASua36COx0zjqqD9Pp1y%2Fimage.png?alt=media&amp;token=391d897e-95c2-4eaf-bb4d-2165db92af67" alt=""><figcaption><p>Edit Customer Subscription to Upgrade or Downgrade it.</p></figcaption></figure>

In order to do it, you need to have offers with the same Interval Periods (Days/Weeks/Months):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FH6PPnzWL1SfJAGZeEPuz%2Fimage.png?alt=media&amp;token=38dfc3e6-82e4-407a-8e31-f4005ce7e7de" alt=""><figcaption><p>Plans have to have the same intervals to Downgrade/Upgrade Plans.</p></figcaption></figure>

After Downgrading or Upgrading Subscriptions - your customers will get an e-mail with updated terms and will be charged accordingly (including proration amount if Upgraded, and deducted amount for next invoice if Downgraded).


# Creating Plans

You can create as many plans as you want in the Dashboard (after creating Subscription product):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FJ1Eu5aOtzZ3qQMqlmvxO%2Fimage.png?alt=media&amp;token=0dd7924c-ffac-4549-b5e5-ddac487e606a" alt=""><figcaption><p>Create as many plans as you want</p></figcaption></figure>

This will mean 2 things:

* You and the customer will be able to downgrade/upgrade their plans in the Dashboard/Management Portal
* During checkout, customers will be able to switch to other plans if they were to decide to subscribe to an alternative variant

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FMCBDB7Rz695axBeTR71d%2Fimage.png?alt=media&amp;token=f91bb16f-fcb4-4713-b65d-26baf886da34" alt=""><figcaption><p>When deciding to pay for the product, customers can switch between plans</p></figcaption></figure>


# Free Trials and Custom Intervals

You can set up your own charge invervals for Subscription products as well as set up a Free Trial period. The way Free Trial works:

* From the moment Free Trial begins to the end of it - customers pay nothing but have to provide Payment Details for automatic payments,
* Once the Trial ends - they will get e-mail communications indicating that the Trial has ended,
* Immediately at the time the Trial ends, their preferred payment method will be charged.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fzk5kbmfnC3b6Oa7x3Ujt%2Fimage.png?alt=media&amp;token=7a2d1903-c5ce-413d-8724-5c3a935c108b" alt=""><figcaption><p>You can set up your own charge intervals as well as Free Trial periods</p></figcaption></figure>

The product page will indicate how much time does the Trial period lasts along with necessary information about future charges:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FwaYuEKdIftiBNtSx3yCh%2Fimage.png?alt=media&amp;token=cb084bea-def7-476d-a7cb-af224452e2aa" alt=""><figcaption><p>Information will be provided on Product Page</p></figcaption></figure>

During the checkout process customers will also have more information on the Free Trial:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FmWeRA9rUs3Hl4xT80X9c%2Fimage.png?alt=media&amp;token=1eaf057b-e0ef-4547-9b92-d01f19977671" alt=""><figcaption><p>Customers will see information about when the Free Trial ends and when he/she will be billed</p></figcaption></figure>

Once customers begin their Trial Periods, you'll see them in the list of your active Subscriptions:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FWNjc48302tu9nPyY3SEw%2Fimage.png?alt=media&amp;token=e50996bb-d18c-4704-b2ad-4fffe819059c" alt=""><figcaption><p>See Trials in your active Subscriptions tab</p></figcaption></figure>


# Redirecting After Purchase

This set up is intended for developers who wish to customize Redirect URL with Custom Parameters after successful purchase from the customer.

## How to Configure Instant Redirects After Successful Subscription Purchase

This guide explains how to set up an instant redirect URL after a successful subscription purchase, including adding query parameters to provide additional information during the redirection process.

### Instant Redirect URL Setup

When a user successfully completes a subscription purchase, you can redirect them automatically to a specific URL. This URL can be set to a page on your website, such as a welcome or thank-you page, for example: <https://example.com/subscription-success>.

You also have the option to include query parameters in the redirect URL to pass important information related to the subscription, such as product IDs or order details.

#### Step-by-Step Configuration

1. Enter the Instant Redirect URL: Specify the URL where users will be redirected after they complete their subscription purchase. For instance, you can use:

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXehxV83YAme3Z0CqR4Kd5wJY1JtsSDsD6bqEA4L18gexm67g9LYLcKZNe7MF6H7xdtw2upncNZrNQaB1Mwc2I9n1aAOolep7D1iOOyjoP8SI6_e-rN9xFdzqX4_riyALq4h_DzUUQ?key=_bILNrdy2PtnUdmc87ezFKTQ)\
This URL will act as the landing page after a successful transaction.

Access it here: <https://app.fungies.io/settings/store> - under Checkout Tab:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FXJnIu9uTb2JwCAHIHW1f%2Fimage.png?alt=media&amp;token=3965fba4-30b0-47c4-bf5d-33d6d55527ec" alt=""><figcaption><p>Access Checkout tab in Settings -> Store</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fy2potW3YIy5zLhPNluzY%2Fimage.png?alt=media&amp;token=30ffb3e4-2212-414e-b857-e9cd2bbaf20f" alt=""><figcaption><p>Scroll down to see the Redirect URL field</p></figcaption></figure>

2. Select URL Parameters: You can select parameters that will be automatically added to the redirect URL from a predefined list. These parameters will be populated dynamically during the redirection process.\
   For example, if you select fngs-product-internal-id from the available parameters, the final URL might look like this:

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXcIGvYCLi4MmniPkUSk1cSEuyzUGWRExJx1s9RR4J7p7ouSWj7rFNRz9cc8qHUhPPhmG2f_2NtKtlbBgOjgzU9We1ZKT7C5THXQvuo92Zh-fkZiPEX9mexNoYGyvvGt__foNxbPrw?key=_bILNrdy2PtnUdmc87ezFKTQ)

\
This allows you to pass relevant information such as the product or order ID to the destination page, which can be useful for tracking or displaying personalized messages.

3. Add Custom Query Parameters: You may also add your own custom query parameters directly within the URL. For custom parameters, you must make sure to manually or programmatically assign values. For example:

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfqmrWuyF8b2LIymtm2nL5yiv9qn5sZhPM7H0uwnQoyL9Kofo8C313IGwySxm3uJ23htTm9eMoMIU7m-Q9CjjXJMjPhcph8eskhgQCxMGK0m1Iw5hvje66xmg10Obqp2wpZihOO?key=_bILNrdy2PtnUdmc87ezFKTQ)\
Here, the user and campaign parameters are added manually, allowing you to track specific user information or marketing campaign details.

4. Combining Predefined and Custom Parameters: You can combine predefined parameters from the system and your own custom parameters to construct a more detailed redirect URL. For example:

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeA4WETSo5hlh_fXQfXKjRot8j5IaExeFvKIy62olfKVYbjlGFbbFqmWyLodPEUh2eBczVyAEhoV5sbnlQapPm_4HI8zpW6UYQjL6GwlXyqTqfLcxNFp_F8avkCOaCsPzBec5cOhw?key=_bILNrdy2PtnUdmc87ezFKTQ)\
Ensure that each parameter has a corresponding value, either provided by the platform or manually defined, to ensure smooth redirection without errors.

### Available System Query Parameters

All system-generated query parameters are prefixed with fngs to avoid conflicts with user-defined custom parameters. Below is a list of all the available system parameters that you can use:

* fngs-product-id: The unique identifier of the product purchased.
* fngs-order-id: The unique identifier of the order.
* fngs-order-number: The human-readable order number for tracking purposes.
* fngs-subscription-id: The unique identifier of the subscription.
* fngs-variant-id: The identifier for the product variant purchased.
* fngs-offer-id: The identifier for the offer linked to the purchase.
* fngs-product-internal-id: The internal identifier used for the product.
* fngs-variant-internal-id: The internal identifier for the variant.
* fngs-offer-internal-id: The internal identifier for the offer.
* fngs-quantity: The quantity of items purchased.
* fngs-user-id: The unique identifier for the user making the purchase.
* fngs-user-email: The email address of the user.
* fngs-total-value: The total value of the purchase.
* fngs-total-items: The total number of items in the order.
* fngs-country: The country from where the purchase was made.
* fngs-currency: The currency used for the transaction.

These parameters can be selected and added to your redirect URL to pass relevant details automatically, providing a richer user experience and more detailed tracking.

### Summary

* Enter the Redirect URL: Define where users are directed post-purchase.
* Select Predefined Parameters: Choose from system-generated parameters like product or order IDs.
* Add Custom Parameters: Include additional information for personalization or tracking.
* Combine Parameters: Use both predefined and custom parameters to create a comprehensive redirect URL.
* System Parameter Prefix: All system parameters are prefixed with fngs to avoid conflicts with custom parameters.


# Using Webhooks

To initiate webhook events using Fungies’s platform, whether you're a seasoned developer or a business owner with limited technical knowledge, this article is designed to help you understand webhooks.

## Common Use Cases

**Billing Notifications:** Automatically notify your accounting system when a payment is processed. This can help streamline financial operations and ensure your records are always up-to-date.

**Customer Management:** Update your CRM system with new customer information whenever a subscription is created or modified. This keeps your customer data consistent and current across all platforms.

**Inventory Management:** Synchronize your inventory system with customer orders. When a new order is placed, the webhook can trigger updates to your inventory, helping you manage stock levels more efficiently.

**Analytics and Reporting:** Send event data to your analytics platform to track important metrics such as subscription renewals, cancellations, and other key performance indicators. This enables more accurate reporting and deeper insights into your business’s performance.

## Preparing Your Software for Webhook Integration

Before implementing Fungies webhooks, you must prepare your software environment. This involves setting up an endpoint to receive the webhook data, ensuring your system can process the data, and configuring security measures to protect your webhook endpoint.

### Step 1: Setting Up an Endpoint

#### What Is an Endpoint?

An endpoint is a URL on your server that listens for incoming webhook data. When an event occurs in Fungies that triggers a webhook, the data is sent to this endpoint.

#### How to Set Up an Endpoint

1. Choose a URL: Decide on a URL for your webhook endpoint. This could be something like `https://yourdomain.com/webhooks/fungies`.
2. Create a Route: In your software, create a route that corresponds to the endpoint URL. This route will handle incoming POST requests from Fungies.

Parse Incoming Data: Ensure your endpoint can parse the incoming JSON data. Most modern web frameworks, like Express for Node.js, Flask for Python, or Laravel for PHP, have built-in methods for handling JSON data.

#### Testing Example for Setting Up an Endpoint

1. Login the <https://webhook.site/> and it will be assigned a webhook handler that can accept webhook requests with POST/GET methods.
2. Copy and store the “**Your unique URL**”.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FRncycDwdY5BMrhh1uWiF%2Fimage15.png?alt=media&amp;token=7c89fae8-332c-4ca5-a120-0b99034fdac6" alt=""><figcaption><p>Testing Example Image for Setting Up an Endpoint</p></figcaption></figure>

## Configuring Webhooks in Fungies

Now that your software is ready to receive webhooks, the next step is to configure the webhook settings in Fungies.

**Step 1:** Go to the Fungies platform at [https://app.Fungies/login](https://app.fungies.io/login). Log in using your credentials and click on the '**Sign in** **with Email**' button.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FPt6BKT2iaoUshEgzj3To%2Fimage7.png?alt=media&amp;token=f3bec401-8c0b-4de3-858d-dd0c0455b2bd" alt=""><figcaption><p>Sign in into Fungies.io account Image</p></figcaption></figure>

**Step 2:** Navigate to the Developers section, where you'll find the following options:

1. Webhooks
2. API Keys

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FPvdGKE2e4bVnDQS3Iz6G%2Fimage5.png?alt=media&amp;token=44dc3cbf-fab1-43e0-8caf-7210b7cfdae1" alt=""><figcaption><p>Navigate to Fungies.io Developers Section Image</p></figcaption></figure>

### Generating the API Keys

An API key (secret key) will be used to sign webhook events. While you can use any string for the key, it should be kept secret and used to verify the event signatures.

**Step 1:** To generate the API key, click on the '**API Keys'** option and then select the '**Generate API Key**' button.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F6uh2Zb1TFOWjtV32g1jk%2Fimage2.png?alt=media&amp;token=175a92c8-1fa6-4d79-9877-a9623f19510c" alt=""><figcaption><p>Navigate to Generating the API Keys Image</p></figcaption></figure>

**Step 2:** After clicking the '**Generate API Key**' button, the Fungies system will instantly create a secret key. Click the '**Copy**' button to save the secret key to your clipboard.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FFTDc6fgIoRuUqlbEx6eV%2Fimage3.png?alt=media&amp;token=bb047109-2c70-4259-9061-2c6d83963394" alt=""><figcaption><p>Copy the Generated API Key Image</p></figcaption></figure>

### Creating a New Webhook

**Step 1:** Click on the '**Webhooks**' option to access the webhook configuration page, then select the '**Create a webhook**' button.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FNHjW9yQ1RhOAzv1Xdx6n%2Fimage9.png?alt=media&amp;token=10cbfae0-e65b-49fb-8345-d07ee95dfee9" alt=""><figcaption><p>Creating a New Webhook Image</p></figcaption></figure>

**Step 2:** Paste the URL you copied from '**Your unique URL**' into the '**Testing Example for Setting Up an Endpoint**.'

**Note:** This URL is for testing purposes only. You can use your custom application domain URL instead.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FLfzbvjpJVck8sQmoomlq%2Fimage12.png?alt=media&amp;token=aef7aec3-02df-43cd-862d-232bd19231e7" alt=""><figcaption><p>Create a Webhook URL Image</p></figcaption></figure>

**Step 3:** Copy the secret key from the '**API Keys**' page and paste it into the designated field.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FiOvmk09dFSm28BXQDyKY%2Fimage16.png?alt=media&amp;token=1ce430a3-fb70-44ee-896b-b3d520c9d1bf" alt=""><figcaption><p>Creating a Secret Key Image</p></figcaption></figure>

**Step 4:** Select the webhook event you'd like to trigger. The chosen event will be triggered, providing real-time updates to your software application.&#x20;

> These instructions are based on the "**On Payment Succesfull**" event type. To configure the other event types you can go through the "[**Types of Webhooks**](https://help.fungies.io/~/changes/WXReAtv0bIUUrsPqOpqn/for-saas-developers/types-of-webhooks?r=SxyOz9upk7sUeMmrk1ZS)" page.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FbQftDXjs0iJgOlcR4hU7%2Fimage14.png?alt=media&amp;token=25d95ecd-e905-430c-91f8-036505650aa3" alt=""><figcaption><p>Selecting the Webhook Events Image</p></figcaption></figure>

**Step 5:** Click on the “**+ Create Webhook**” button to set up the webhook.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F9pRUdCXTj6hioSld7R80%2Fimage6.png?alt=media&amp;token=ae7340d4-2aef-4b13-b9ea-df01bfb6f2e1" alt=""><figcaption><p>Click the Create Webhook Button Image</p></figcaption></figure>

You can view the successfully created webhooks on the Webhooks page.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FrYTbGsrNLC47Y6C9dZPk%2Fimage1.png?alt=media&amp;token=7ae58cee-b0db-4038-9b3f-e9c101a5feb9" alt=""><figcaption><p>Successfully Created Webhooks List on the Webhooks page Image</p></figcaption></figure>

### Testing the Webhook

Before going live, use the “**Test Webhook**” feature in Fungies to send a sample payload to your endpoint.

**Step 1:** Click on the webhook which you want to test.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FcutKDdnJII1Fc9iipmac%2Fimage10.png?alt=media&amp;token=566da56f-8299-4b7f-b1d8-89c02303879c" alt=""><figcaption><p>Clicking on the Created Webhook for Test Image</p></figcaption></figure>

**Step 2:** A webhook configuration page will open. Click the '**Test**' button to begin the webhook testing.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FnWooWJ4x2qKukfwuCGMO%2Fimage11.png?alt=media&amp;token=50679f4a-42ba-4196-bda7-d13764f840a4" alt=""><figcaption><p>Clicking on the Test Button for Webhook Test Image</p></figcaption></figure>

**Step 3:** Clicking the '**Test**' button will open a window where you can choose the details for the webhook event you want to trigger for the test.

* Select the webhook event type.
* Choose the item name, if applicable.
* Select the customer name, if applicable.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FYuR2TTkK36zCNtHJeb9u%2Fimage8.png?alt=media&amp;token=1be16dea-7c08-4de4-92ac-9de477f3ff07" alt=""><figcaption><p>Enter the Webhook Details for Test Image</p></figcaption></figure>

**Step 4:** Click the '**Send**' button to trigger the webhook.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F4Azdae8NgLhGb9cQ6Msn%2Fimage4.png?alt=media&amp;token=fd198425-5e4d-4413-a480-19b8aa250082" alt=""><figcaption><p>Clicking on the Send Button Image</p></figcaption></figure>

You can now view the trigger details (payload) on the endpoint handler you configured during the 'Setting Up an Endpoint' section.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F78TLv8gKbxSZZWpslJak%2Fimage13.png?alt=media&amp;token=2c617583-04a1-497f-876e-31ba890dc74e" alt=""><figcaption><p>View the Triggered Details (payload) on the Endpoint Handler Image</p></figcaption></figure>

#### Example of Request Payload Object (payment\_success)

This is a request body payload object for the payment\_success event

```
{
  "id": "f4cbd202-89c5-4538-b44b-11b2b7fa36ea",
  "type": "payment_success",
  "testMode": true,
  "data": {
    "items": [],
    "order": {
      "id": "47f68b70-898e-4dc8-99bd-9f30ce73c2f4",
      "totalItems": 0,
      "orderNumber": "2OJ3DJ0VP0CN"
    },
    "customer": {
      "id": "6e53e763-842e-4b19-872a-f02dfc8dc109",
      "email": "test@Fungies"
    }
  },
  "idempotencyKey": "f4cbd202-89c5-4538-b44b-11b2b7fa36ea"
}
```

#### Example of Response Object: 200

This is a response object for the payment\_success event

```
{
"data":"This URL has no default content configured. <a href="https://webhook.site/#!/view/7b736426-27aa-4b85-bda3-5d84fbc401eb">View in Webhook.site</a>."
}
```


# Types of Webhooks

This document will explore all the types of Webhooks supported by Fungies with their object responses.

Refer “[Using Webhooks](https://help.fungies.io/for-saas-developers/using-webhooks)” guide to configure all the listed types of webhooks (events).

## Webhooks Types (Events):

* Payment Success
* Payment Refunded
* Payment Failed
* Subscription Created
* Subscription Interval
* Subscription Updated
* Subscription Cancelled

Let’s discuss all the types (events) in the next sub-pages:


# Payment Success

The **Payment Success webhook** on the **Fungies.io** platform is designed to notify external systems (such as your server or application) whenever a payment transaction has been successfully processed. This webhook is part of the platform's suite of automated notifications and helps ensure external systems stay in sync with Fungies.io regarding payment-related events.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F6mgTtXFslDeDceJ9gXDW%2FScreenshot%202024-12-12%20at%2019.35.26.png?alt=media&amp;token=6526e4cf-303c-4968-99f0-96899854d9d1" alt="" width="563"><figcaption></figcaption></figure>

## Example of Request Payload Object (payment\_success)

```
{
  "id": "f4cbd202-89c5-4538-b44b-11b2b7fa36ea",
  "type": "payment_success",
  "testMode": true,
  "data": {
    "items": [],
    "order": {
      "id": "47f68b70-898e-4dc8-99bd-9f30ce73c2f4",
      "totalItems": 0,
      "orderNumber": "2OJ3DJ0VP0CN"
    },
    "customer": {
      "id": "6e53e763-842e-4b19-872a-f02dfc8dc109",
      "email": "test@Fungies"
    }
  },
  "idempotencyKey": "f4cbd202-89c5-4538-b44b-11b2b7fa36ea"
}
```


# Payment Refunded

Fired when a payment has been refunded to the customer. It provides details about the refund transaction, including the refunded amount and the original payment reference. Businesses can use this webhook to update financial records, notify customers of the refund status, and provide follow-up support to resolve any issues.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F746CmZfSUnUjhll6xeoj%2Ffungies2.png?alt=media&amp;token=dc2b98cc-58fb-42a4-9ace-ed94eb61e5ac" alt="" width="563"><figcaption></figcaption></figure>

### Example of Request Payload Object (payment\_refunded)

```
{
  "id": "5e65daf0-8253-4ffb-ab54-8645465aac75",
  "type": "payment_refunded",
  "testMode": true,
  "data": {
    "user": {
      "id": "6ea05f2f-fab2-4718-bfaf-abe888798100",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    },
    "items": [],
    "order": {
      "id": "a0671147-3eee-4e08-885c-66dc436623f2",
      "fee": 0,
      "tax": 0,
      "value": 0,
      "number": "kktRWz1FllD0WDDX",
      "object": "order",
      "status": "PAID",
      "userId": "6ea05f2f-fab2-4718-bfaf-abe888798100",
      "country": "US",
      "currency": "USD",
      "createdAt": 1732370437156,
      "totalItems": 0,
      "orderNumber": "kktRWz1FllD0WDDX",
      "currencyDecimals": 2
    },
    "payment": {
      "id": "a0671147-3eee-4e08-885c-66dc436623f2",
      "fee": 0,
      "tax": 0,
      "type": "one_time",
      "value": 0,
      "number": "kktRWz1FllD0WDDX",
      "object": "payment",
      "status": "PAID",
      "userId": "6ea05f2f-fab2-4718-bfaf-abe888798100",
      "orderId": "a0671147-3eee-4e08-885c-66dc436623f2",
      "currency": "USD",
      "createdAt": 1732370437156,
      "orderNumber": "kktRWz1FllD0WDDX",
      "currencyDecimals": 2
    },
    "customer": {
      "id": "6ea05f2f-fab2-4718-bfaf-abe888798100",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    }
  },
  "idempotencyKey": "5e65daf0-8253-4ffb-ab54-8645465aac75"
}
```


# Payment Failed

This webhook occurs when a payment attempt is unsuccessful, typically due to reasons like insufficient funds or invalid payment details. It helps notify the customer about the failure and may include error codes for troubleshooting. It enables businesses to prompt users to retry the payment or provide alternative payment options.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FR1mgnIGwdSLuDhVWNsof%2Ffungies3.png?alt=media&amp;token=849df28d-5950-46f8-b527-c6be83e74b44" alt="" width="563"><figcaption></figcaption></figure>

### Example of Request Payload Object (payment\_failed)

```
{
  "id": "424b6daa-2a01-4b42-864f-9385d3df1ebf",
  "type": "payment_failed",
  "testMode": true,
  "data": {
    "user": {
      "id": "34dfdeab-001c-4ded-ac23-13566d266224",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    },
    "items": [],
    "order": {
      "id": "cfc87241-85e6-412f-bdff-8d7df85749b5",
      "fee": 0,
      "tax": 0,
      "value": 0,
      "number": "0vVTf4eFvOR0HpMR",
      "object": "order",
      "status": "PAID",
      "userId": "34dfdeab-001c-4ded-ac23-13566d266224",
      "country": "US",
      "currency": "USD",
      "createdAt": 1732372298451,
      "totalItems": 0,
      "orderNumber": "0vVTf4eFvOR0HpMR",
      "currencyDecimals": 2
    },
    "payment": {
      "id": "cfc87241-85e6-412f-bdff-8d7df85749b5",
      "fee": 0,
      "tax": 0,
      "type": "one_time",
      "value": 0,
      "number": "0vVTf4eFvOR0HpMR",
      "object": "payment",
      "status": "PAID",
      "userId": "34dfdeab-001c-4ded-ac23-13566d266224",
      "orderId": "cfc87241-85e6-412f-bdff-8d7df85749b5",
      "currency": "USD",
      "createdAt": 1732372298451,
      "orderNumber": "0vVTf4eFvOR0HpMR",
      "currencyDecimals": 2
    },
    "customer": {
      "id": "34dfdeab-001c-4ded-ac23-13566d266224",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    }
  },
  "idempotencyKey": "424b6daa-2a01-4b42-864f-9385d3df1ebf"
}
```


# Subscription Created

Triggered when a new subscription is successfully created. This webhook can include details about the customer, subscription plan, and start date. Businesses use it to activate services, onboard new subscribers, or send welcome emails, ensuring a smooth and engaging start to the subscription journey.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHzT10MyUzkq27tGeWnQh%2Ffungies4.png?alt=media&amp;token=647b9611-e9ea-4091-a4e0-72b931894431" alt="" width="563"><figcaption></figcaption></figure>

### Example of Request Payload Object (subscription\_created)

```
{
  "id": "d6862a8e-884e-4429-908e-c659b96aac3b",
  "type": "subscription_created",
  "testMode": true,
  "data": {
    "user": {
      "id": "bc589721-695f-4f80-afa0-36711193258a",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    },
    "items": [],
    "lastPayment": {
      "id": "1a36e115-c3a5-4904-ab3d-0f9e1719664a",
      "fee": 0,
      "tax": 0,
      "type": "subscription_initial",
      "value": 0,
      "number": "z26yYXQWFMoFsOBa",
      "object": "payment",
      "status": "PAID",
      "userId": "bc589721-695f-4f80-afa0-36711193258a",
      "orderId": "1a36e115-c3a5-4904-ab3d-0f9e1719664a",
      "currency": "USD",
      "createdAt": 1732373176477,
      "orderNumber": "z26yYXQWFMoFsOBa",
      "currencyDecimals": 2
    },
    "subscription": {
      "id": "z26yYXQWFMoFsOBa",
      "object": "subscription",
      "userId": "bc589721-695f-4f80-afa0-36711193258a",
      "orderId": "1a36e115-c3a5-4904-ab3d-0f9e1719664a",
      "createdAt": 1731938713000,
      "canceledAt": null,
      "orderNumber": "z26yYXQWFMoFsOBa",
      "lastPaymentId": "1a36e115-c3a5-4904-ab3d-0f9e1719664a",
      "lastPaymentNumber": "z26yYXQWFMoFsOBa",
      "currentIntervalEnd": 1734530713000,
      "cancelAtIntervalEnd": false,
      "currentIntervalStart": 1731938713000
    }
  },
  "idempotencyKey": "d6862a8e-884e-4429-908e-c659b96aac3b"
}
```


# Subscription Interval

Subscription Interval is sent periodically based on a subscription's billing cycle, such as monthly or annually. This webhook provides updates on the recurring nature of the subscription, including charges or renewal reminders. It helps businesses maintain transparency, generate invoices, or send reminders for upcoming payments to the customer.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHJ0L5PzVNE7LO91HTJRB%2Ffungies5.png?alt=media&amp;token=010c18a4-1492-4891-94d7-a8c70a26e6eb" alt="" width="563"><figcaption></figcaption></figure>

### Example of Request Payload Object (subscription\_interval)

```
{
  "id": "04986b95-9406-4fb0-a683-a8703e521e7b",
  "type": "subscription_interval",
  "testMode": true,
  "data": {
    "user": {
      "id": "b38c3b93-4d07-4ad3-9dd8-04b056b339ee",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    },
    "items": [],
    "lastPayment": {
      "id": "55940915-2822-4860-bbf0-1df1375361f1",
      "fee": 0,
      "tax": 0,
      "type": "subscription_initial",
      "value": 0,
      "number": "S3oQQCCw7wOC6VeO",
      "object": "payment",
      "status": "PAID",
      "userId": "b38c3b93-4d07-4ad3-9dd8-04b056b339ee",
      "orderId": "55940915-2822-4860-bbf0-1df1375361f1",
      "currency": "USD",
      "createdAt": 1732373466231,
      "orderNumber": "S3oQQCCw7wOC6VeO",
      "currencyDecimals": 2
    },
    "subscription": {
      "id": "S3oQQCCw7wOC6VeO",
      "object": "subscription",
      "userId": "b38c3b93-4d07-4ad3-9dd8-04b056b339ee",
      "orderId": "55940915-2822-4860-bbf0-1df1375361f1",
      "createdAt": 1731938713000,
      "canceledAt": null,
      "orderNumber": "S3oQQCCw7wOC6VeO",
      "lastPaymentId": "55940915-2822-4860-bbf0-1df1375361f1",
      "lastPaymentNumber": "S3oQQCCw7wOC6VeO",
      "currentIntervalEnd": 1734530713000,
      "cancelAtIntervalEnd": false,
      "currentIntervalStart": 1731938713000
    }
  },
  "idempotencyKey": "04986b95-9406-4fb0-a683-a8703e521e7b"
}
```


# Subscription Updated

Subscription Updates are fired when any modification is made to an active subscription, such as a plan upgrade, downgrade, or billing information update. This webhook ensures subscription data is always current and can be used to adjust billing details, send confirmation messages, or trigger relevant workflows based on the updated subscription status.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FMSE0HFzBFFWVTAHcWhvP%2Ffungies6.png?alt=media&amp;token=5abe084b-ba8a-4c13-aff7-ba0807c59f62" alt="" width="563"><figcaption></figcaption></figure>

### Example of Request Payload Object (subscription\_updated)

```
{
  "id": "e15036d5-d1d1-4ff9-951c-138e63c09353",
  "type": "subscription_updated",
  "testMode": true,
  "data": {
    "user": {
      "id": "31313125-3dcb-47dc-a09a-1d7f33e45460",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    },
    "items": [],
    "lastPayment": {
      "id": "1d9b5f04-7bcb-4f53-8639-a70d8c0d8695",
      "fee": 0,
      "tax": 0,
      "type": "subscription_initial",
      "value": 0,
      "number": "uXXdy1A7BPdX8xDp",
      "object": "payment",
      "status": "PAID",
      "userId": "31313125-3dcb-47dc-a09a-1d7f33e45460",
      "orderId": "1d9b5f04-7bcb-4f53-8639-a70d8c0d8695",
      "currency": "USD",
      "createdAt": 1732373872603,
      "orderNumber": "uXXdy1A7BPdX8xDp",
      "currencyDecimals": 2
    },
    "subscription": {
      "id": "uXXdy1A7BPdX8xDp",
      "object": "subscription",
      "userId": "31313125-3dcb-47dc-a09a-1d7f33e45460",
      "orderId": "1d9b5f04-7bcb-4f53-8639-a70d8c0d8695",
      "createdAt": 1731938713000,
      "canceledAt": null,
      "orderNumber": "uXXdy1A7BPdX8xDp",
      "lastPaymentId": "1d9b5f04-7bcb-4f53-8639-a70d8c0d8695",
      "lastPaymentNumber": "uXXdy1A7BPdX8xDp",
      "currentIntervalEnd": 1734530713000,
      "cancelAtIntervalEnd": false,
      "currentIntervalStart": 1731938713000
    }
  },
  "idempotencyKey": "e15036d5-d1d1-4ff9-951c-138e63c09353"
}
```


# Subscription Cancelled

Subscription Cancelled is triggered when a subscription is terminated by either the customer or the platform. It includes information about the cancellation reason and end date. Businesses can use this webhook to deactivate services, gather user feedback, and implement retention strategies for users who choose to leave the service.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FmEafXzyrRHLjMjOTVwK1%2Ffungies7.png?alt=media&amp;token=0e654d20-e59e-41e6-98c9-497d0dc01dc9" alt="" width="563"><figcaption></figcaption></figure>

### Example of Request Payload Object (subscription\_cancelled)

```
{
  "id": "7e087b1b-9db1-40d8-9332-ace8f0d9911c",
  "type": "subscription_cancelled",
  "testMode": true,
  "data": {
    "user": {
      "id": "65f391b9-65bd-4f35-8dfa-d36e6b5404a0",
      "email": "test@fungies.io",
      "object": "user",
      "username": null,
      "internalId": null
    },
    "items": [],
    "lastPayment": {
      "id": "6d4864dc-c103-4750-8921-f3403170bdfe",
      "fee": 0,
      "tax": 0,
      "type": "subscription_initial",
      "value": 0,
      "number": "v3OpVdkByWdxhWyW",
      "object": "payment",
      "status": "PAID",
      "userId": "65f391b9-65bd-4f35-8dfa-d36e6b5404a0",
      "orderId": "6d4864dc-c103-4750-8921-f3403170bdfe",
      "currency": "USD",
      "createdAt": 1732374024809,
      "orderNumber": "v3OpVdkByWdxhWyW",
      "currencyDecimals": 2
    },
    "subscription": {
      "id": "v3OpVdkByWdxhWyW",
      "object": "subscription",
      "userId": "65f391b9-65bd-4f35-8dfa-d36e6b5404a0",
      "orderId": "6d4864dc-c103-4750-8921-f3403170bdfe",
      "createdAt": 1731938713000,
      "canceledAt": null,
      "orderNumber": "v3OpVdkByWdxhWyW",
      "lastPaymentId": "6d4864dc-c103-4750-8921-f3403170bdfe",
      "lastPaymentNumber": "v3OpVdkByWdxhWyW",
      "currentIntervalEnd": 1734530713000,
      "cancelAtIntervalEnd": false,
      "currentIntervalStart": 1731938713000
    }
  },
  "idempotencyKey": "7e087b1b-9db1-40d8-9332-ace8f0d9911c"
}
```


# Getting Started with the API

A quick guide to help you start using the API, from generating API keys to making your first requests.

Before starting the API requests, you’ll need a Fungies.io account. If you haven’t already, please

1. Register an account&#x20;
2. Add some products
3. Customize your online store

To begin using the API, you'll need `API key` and `write-API key` for authorization. These keys can be generated from the Fungies.io Developers section.

## Generating the API Keys

To authenticate requests, you must include your `API key` and `write-API key` in the request headers. For all "read" actions (GET requests), you need at least the `API key` (public key). For all "write" actions (POST, PATCH, DELETE, and PUT), you need both the `API key` and `write-API key` (secret key).

### Steps to Generate the API Keys

**Step 1:** To generate the API key, click on the '**API Keys**' option at the sidebar and then select the '**Generate API Key**' button.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FnoRTZzu7GPzJ7Thz6SaI%2FScreenshot%202024-09-09%20at%2015.34.01.png?alt=media&amp;token=294c097d-e832-4c0f-8220-47e0a753c105" alt=""><figcaption><p>Generate API Keys</p></figcaption></figure>

**Step 2:** After clicking the '**Generate API Key**' button, the Fungies system will instantly create an `API key` and `write-API key`. Click the '**Copy**' button to save the keys to your clipboard.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fe6Z65hCJQOlX4ItsKvAd%2FScreenshot%202024-09-10%20at%2016.12.46.png?alt=media&amp;token=f2983ecd-92e8-48b2-b2dd-bec7794802d5" alt=""><figcaption><p>Generated New API Keys</p></figcaption></figure>

> Keep your `API key` and `write-API key` private and secure. Don’t save them directly in your code or on GitHub. Instead, use environment files to store them. For added security, regularly update your API keys.

## When making an API Request

You can access the Fungies API at [`https://api.fungies.io/`](https://api.fungies.io/). Make sure all requests are made over HTTPS, as authentication is required for every request.

The API follows the JSON specification, so be sure to include the following headers in each request.

`header 'Content-Type: application/json'`

## Authentication

The API uses Bearer authentication for all requests. You will need an API key from the '[Generating the API Keys](https://help.fungies.io/for-saas-developers/getting-started-with-the-api#generating-the-api-keys)' section.&#x20;

To authenticate, add an Authorization header to all requests containing a valid API key:

For "read" actions (GET):

`header 'x-fngs-public-key:'`

For "write" actions (POST, PATCH, PUT, and DELETE):

`header 'x-fngs-secret-key:'`


# Orders APIs

Welcome to the Fungies API documentation! This article is about learning how to manage orders effectively using the Fungies API. We will walk you through the essential API endpoints, including how to retrieve, update, and cancel orders.

After generating the API key and write-API key, you can immediately start making requests to the Fungies Orders API endpoints.

Let's explore each Orders endpoint individually within its respective module.

<br>


# Managing Orders through API

This article is about learning how to effectively manage orders using the Fungies API. We will walk you through the essential API endpoints, including how to retrieve, update, and cancel orders

Welcome to the Fungies API documentation! This guide will walk you through managing orders using the Fungies API. You'll learn how to list orders, retrieve specific order details, update an order, and cancel an order.

After generating the `API key` and `write-API key` you can immediately start making requests to the Fungies Orders API endpoints

## Getting Started with APIs

A collection of endpoints that allow you to manage and interact with orders, including retrieving details, updating, and cancelling orders, to ensure seamless order management and processing.

### /orders/list (List All Orders)

The `/orders/list` endpoint is used to retrieve a list of all orders from the Fungies.io platform. It allows developers to access details of every order placed within the system, providing an overview of order activities.

> **Note**: This endpoint requires `API key` for authentication.

This is a `GET` API endpoint that accepts several parameters to filter the results:

* **status**: Specifies the current status of the orders. Possible values include `PENDING`, `PAID`, `FAILED`, `UNPAID`, `CANCELLED`, `REFUNDED`, `PARTIALLY_REFUNDED`, and `EXPIRED`.
* **userId**: Filters orders by the user ID of the customer.
* **createdAfter**: Returns orders created after a specified date.
* **createdBefore**: Returns orders created before a specified date.
* **page**: Specifies which page of the order list you want to retrieve.
* **limit**: Defines the maximum number of orders to return per page.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "success",
  "data": {
    "orders": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "status": "PENDING",
        "orderNumber": "string",
        "value": -1.7976931348623157e+308,
        "fee": -1.7976931348623157e+308,
        "tax": -1.7976931348623157e+308,
        "currency": "AFN",
        "createdAt": "string",
        "formatted": {
          "orderNumber": "string",
          "subtotal": "string",
          "totalValue": "string",
          "totalDiscount": "string",
          "tax": "string"
        }
      }
    ],
    "count": -1.7976931348623157e+308
  }
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

### /orders/orderId (Retrieve Order Details)

The GET `/orders/{orderId}` endpoint retrieves detailed information about a specific order based on the unique orderId. This endpoint is essential for accessing comprehensive details about an individual order, including its status, items, payment information, and customer details.

> **Note**: This endpoint requires `API key` for authentication.

This is a `GET` API endpoint that accepts a single parameter to filter the results:

* **orderId:** The orderId parameter is a unique identifier for a specific order in the Fungies.io platform.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "success",
  "data": {
    "order": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "PENDING",
      "orderNumber": "string",
      "value": -1.7976931348623157e+308,
      "fee": -1.7976931348623157e+308,
      "tax": -1.7976931348623157e+308,
      "currency": "AFN",
      "createdAt": "string",
      "formatted": {
        "orderNumber": "string",
        "subtotal": "string",
        "totalValue": "string",
        "totalDiscount": "string",
        "tax": "string"
      }
    }
  }
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

### /orders/{orderId}/update (Update an Order)

The PATCH `/orders/{orderId}/update` endpoint allows you to update the details of a specific order identified by the orderId. This endpoint is useful for modifying order attributes such as status, shipping information, or any other modifiable fields after creating the order.

> **Note**: This endpoint requires `API key` and `write-API key` (both) for authentication at the same time.

The `/orders/{orderId}/update` endpoint allows users to update an order by sending a request with the following values in the request body:

* **status**: The current status of the order.
* **value**: The total value of the order.
* **fee**: Any fees associated with the order.
* **tax**: The amount of tax applied to the order.
* **currency**: The currency used for the order.

**Request Body:**

```
{
  "status": "PENDING",
  "value": -1.7976931348623157e+308,
  "fee": -1.7976931348623157e+308,
  "tax": -1.7976931348623157e+308,
  "currency": "AFN"
}
```

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "success",
  "data": {
    "order": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "PENDING",
      "orderNumber": "string",
      "value": -1.7976931348623157e+308,
      "fee": -1.7976931348623157e+308,
      "tax": -1.7976931348623157e+308,
      "currency": "AFN",
      "createdAt": "string",
      "formatted": {
        "orderNumber": "string",
        "subtotal": "string",
        "totalValue": "string",
        "totalDiscount": "string",
        "tax": "string"
      }
    }
  }
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

### /orders/{orderId}/cancel (Cancel an Order)

The PATCH `/orders/{orderId}/cancel` endpoint is used to cancel a specific order identified by the orderId. This endpoint is typically used when an order needs to be stopped before it is fulfilled or processed. Cancelling an order will update its status to indicate that it has been cancelled.

> **Note**: This endpoint requires `API key` and `write-API key` (both) for authentication at the same time.

This is a PATCH API endpoint that accepts a single parameter to cancel/delete the results:

**orderId:** The orderId parameter is a unique identifier for a specific order in the Fungies.io platform.

The `/orders/{orderId}/cancel` endpoint does not require a request body; it uses an empty request body.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "success",
  "data": {
    "order": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "PENDING",
      "orderNumber": "string",
      "value": -1.7976931348623157e+308,
      "fee": -1.7976931348623157e+308,
      "tax": -1.7976931348623157e+308,
      "currency": "AFN",
      "createdAt": "string",
      "formatted": {
        "orderNumber": "string",
        "subtotal": "string",
        "totalValue": "string",
        "totalDiscount": "string",
        "tax": "string"
      }
    }
  }
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```


# Orders List

## GET /orders/list&#x20;

The `/orders/list` endpoint retrieves a comprehensive list of all orders placed within the **Fungies.io** platform. It enables developers to access detailed order information while supporting **optional filtering** and **pagination** for efficient data retrieval.

**Request Method**: GET

**Endpoint URL**: <https://api.fungies.io/v0/orders/list>

**Headers**: x-fngs-public-key: \<api-key>

**Example**: `Authorization: x-fngs-public-key: <api-key>`

> **Note**: This endpoint requires an API key for authentication. Refer to [this](https://help.fungies.io/for-saas-developers/getting-started-with-the-api#generating-the-api-keys) guide to generate your API key.

### Query Parameters

The query parameters are provided for the "List orders" API endpoint are as follows:

* **orderDirection** *(string)*: Specifies the sorting order of the returned list. \
  Available options are: ASC, DESC.<br>
* **skip** *(number | null)*: Specifies the number of records to skip from the beginning of the result set. Useful for pagination.\
  Required range: 0 <= x <= 1.7976931348623157e+308<br>
* **take** *(number | null)*: Defines the number of records to retrieve in the response. Helps in limiting the result set for pagination.\
  Required range: 0 <= x <= 1.7976931348623157e+308<br>
* **archived** *(string)*: Filters the orders by their archive status.<br>
* **withArchived** *(string)*: Includes archived orders in the response when specified.<br>
* **returnCount** *(string)*: Indicates whether to return the count of matching orders.<br>
* **term** *(string)*: Allows filtering orders based on a search term.<br>
* **ids** *(string)*: Filters the orders by a list of specific order IDs.<br>
* **number** *(string)*: Filters orders based on the order number.<br>
* **userId** (string): Filters orders associated with a specific user ID.<br>
* **subscriptionId** *(string)*: Filters orders linked to a particular subscription ID.<br>
* **statuses** *(string)*: Filters orders based on their status. \
  Available options include: **`PENDING`**, **`PAID`**, **`FAILED`**, **`UNPAID`**, **`CANCELLED`**, **`REFUNDED`**, **`PARTIALLY_REFUNDED`**, **`EXPIRED.`**<br>
* **types** *(string)*: Filters orders based on their type. \
  Available options include: **`one_time`**, **`subscription_initial`**, **`subscription_update`**, **`subscription_interval`**, **`claim_free.`**<br>
* **valueFrom** *(number | null):* Filters orders with a value greater than or equal to the specified amount.\
  Required range: -1.7976931348623157e+308 <= x <= 1.7976931348623157e+308<br>
* **valueTo** *(number | null)*: Filters orders with a value less than or equal to the specified amount.\
  Required range: -1.7976931348623157e+308 <= x <= 1.7976931348623157e+308<br>
* **currency** *(string)*: Filters orders by the currency in which they were processed. \
  The available options include a comprehensive list of global currencies: **`AFN`** (Afghanistan), **`ALL`** (Albania), **`DZD`** (Algeria), **`AOA`** (Angola), **`ARS`** (Argentina), **`AMD`** (Armenia), **`AWG`** (Aruba), **`AUD`** (Australia), **`AZN`** (Azerbaijan), **`BSD`** (Bahamas), **`BDT`** (Bangladesh), **`BBD`** (Barbados), **`BZD`** (Belize), **`BMD`** (Bermuda), **`BOB`** (Bolivia), **`BAM`** (Bosnia and Herzegovina), **`BWP`** (Botswana), **`BRL`** (Brazil), **`BHD`** (Bahrain), **`GBP`** (United Kingdom), **`BND`** (Brunei), **`BGN`** (Bulgaria), **`BIF`** (Burundi), **`BYN`** (Belarus), **`KHR`** (Cambodia), **`CAD`** (Canada), **`CVE`** (Cape Verde), **`KYD`** (Cayman Islands), **`KWD`** (Kuwait), **`XAF`** (Central African CFA), **`XPF`** (CFP Franc), **`CLP`** (Chile), **`CNY`** (China), **`COP`** (Colombia), **`KMF`** (Comoros), **`CDF`** (Congo - Kinshasa), **`CRC`** (Costa Rica), **`HRK`** (Croatia), **`CZK`** (Czech Republic), **`DKK`** (Denmark), **`DJF`** (Djibouti), **`DOP`** (Dominican Republic), **`XCD`** (East Caribbean Dollar), **`EGP`** (Egypt), ETB (Ethiopia), **`EUR`** (Eurozone), **`FKP`** (Falkland Islands), **`FJD`** (Fiji), **`GMD`** (Gambia), **`GEL`** (Georgia), **`GIP`** (Gibraltar), **`GTQ`** (Guatemala), **`GNF`** (Guinea), **`GYD`** (Guyana), **`HTG`** (Haiti), **`HNL`** (Honduras), **`HKD`** (Hong Kong), **`HUF`** (Hungary), **`ISK`** (Iceland), **`INR`** (India), **`IDR`** (Indonesia), **`ILS`** (Israel), **`JMD`** (Jamaica), **`JPY`** (Japan), **`JOD`** (Jordan), **`KZT`** (Kazakhstan), **`KES`** (Kenya), **`KGS`** (Kyrgyzstan), **`LAK`** (Laos), **`LBP`** (Lebanon), **`LSL`** (Lesotho), **`LRD`** (Liberia), **`MOP`** (Macau), **`MKD`** (North Macedonia), **`MGA`** (Madagascar), **`MWK`** (Malawi), **`MYR`** (Malaysia), **`MVR`** (Maldives), **`MRO`** (Mauritania), **`MUR`** (Mauritius), **`MXN`** (Mexico), **`MDL`** (Moldova), **`MNT`** (Mongolia), **`MAD`** (Morocco), **`MZN`** (Mozambique), **`MMK`** (Myanmar), **`NAD`** (Namibia), **`NPR`** (Nepal), ANG (Netherlands Antilles), TWD (Taiwan), NZD (New Zealand), NIO (Nicaragua), NGN (Nigeria), **`NOK`** (Norway), **`OMR`** (Oman), **`PKR`** (Pakistan), **`PAB`** (Panama), **`PGK`** (Papua New Guinea), **`PYG`** (Paraguay), **`PEN`** (Peru), **`PHP`** (Philippines), **`PLN`** (Poland), **`QAR`** (Qatar), **`RON`** (Romania), **`RUB`** (Russia), **`RWF`** (Rwanda), **`SHP`** (Saint Helena), **`SVC`** (El Salvador), **`WST`** (Samoa), **`STD`** (São Tomé and Príncipe), **`SAR`** (Saudi Arabia), **`RSD`** (Serbia), **`SCR`** (Seychelles), **`SLL`** (Sierra Leone), **`SGD`** (Singapore), **`SBD`** (Solomon Islands), **`SOS`** (Somalia), **`ZAR`** (South Africa), **`KRW`** (South Korea), **`LKR`** (Sri Lanka), **`SRD`** (Suriname), **`SZL`** (Eswatini), **`SEK`** (Sweden), **`CHF`** (Switzerland), **`TJS`** (Tajikistan), **`TZS`** (Tanzania), **`THB`** (Thailand), **`TND`** (Tunisia), **`TOP`** (Tonga), **`TTD`** (Trinidad and Tobago), **`TRY`** (Turkey), **`UGX`** (Uganda), **`UAH`** (Ukraine), **`AED`** (United Arab Emirates), **`UYU`** (Uruguay), **`USD`** (United States), **`UZS`** (Uzbekistan), **`VUV`** (Vanuatu), **`VEF`** (Venezuela), **`VND`** (Vietnam), **`XOF`** (West African CFA), **`YER`** (Yemen), **`ZMW`** (Zambia), **`SLE`** (Sierra Leone).<br>
* **country** *(string)*: Filters orders by country code from a predefined list of global country codes. \
  The available options include a comprehensive list of country codes representing various countries and regions worldwide. **`AF`** (Afghanistan), **`AX`** (Aland Islands), **`AL`** (Albania), **`DZ`** (Algeria), **`AD`** (Andorra), **`AO`** (Angola), **`AI`** (Anguilla), **`AQ`** (Antarctica), **`AG`** (Antigua and Barbuda), **`AR`** (Argentina), **`AM`** (Armenia), **`AW`** (Aruba), **`AU`** (Australia), **`AT`** (Austria), **`AZ`** (Azerbaijan), **`BS`** (Bahamas), **`BH`** (Bahrain), **`BD`** (Bangladesh), **`BB`** (Barbados), **`BY`** (Belarus), **`BE`** (Belgium), **`BZ`** (Belize), **`BJ`** (Benin), **`BM`** (Bermuda), **`BT`** (Bhutan), **`BO`** (Bolivia), **`BA`** (Bosnia and Herzegovina), **`BW`** (Botswana), **`BV`** (Bouvet Island), **`BR`** (Brazil), **`IO`** (British Indian Ocean Territory), **`VG`** (British Virgin Islands), **`BN`** (Brunei), **`BG`** (Bulgaria), **`BF`** (Burkina Faso), **`BI`** (Burundi), **`KH`** (Cambodia), **`CM`** (Cameroon), **`CA`** (Canada), **`CV`** (Cape Verde), **`BQ`** (Caribbean Netherlands), **`KY`** (Cayman Islands), **`CF`** (Central African Republic), **`TD`** (Chad), **`CL`** (Chile), **`CN`** (China), **`CO`** (Colombia), **`KM`** (Comoros), **`KM`** (Congo - Brazzaville), **`CD`** (Congo - Kinshasa), **`CK`** (Cook Islands), **`CR`** (Costa Rica), **`CI`** (Côte d’Ivoire), **`HR`** (Croatia), **`CW`** (Curaçao), **`CY`** (Cyprus), **`CZ`** (Czechia), **`DK`** (Denmark), **`DJ`** (Djibouti), **`DM`** (Dominica), **`DO`** (Dominican Republic), **`EC`** (Ecuador), **`EG`** (Egypt), **`SV`** (El Salvador), **`GQ`** (Equatorial Guinea), **`ER`** (Eritrea), **`EE`** (Estonia), **SZ** (Eswatini), **`ET`** (Ethiopia), **`FK`** (Falkland Islands), **`FO`** (Faroe Islands), **`FJ`** (Fiji), **`FI`** (Finland), **`FR`** (France), **`GF`** (French Guiana), **`PF`** (French Polynesia), **`TF`** (French Southern Territories), **`GA`** (Gabon), **`GM`** (Gambia), **`GE`** (Georgia), **`DE`** (Germany), **`GH`** (Ghana), **`GI`** (Gibraltar), **`GR`** (Greece), **`GL`** (Greenland), **`GD`** (Grenada), **`GP`** (Guadeloupe), **`GU`** (Guam), **`GT`** (Guatemala), **`GG`** (Guernsey), **`GN`** (Guinea), **`GW`** (Guinea-Bissau), **`GY`** (Guyana), **`HT`** (Haiti), **`HN`** (Honduras), **`HK`** (Hong Kong), **`HU`** (Hungary), **`IS`** (Iceland), **`IN`** (India), **`ID`** (Indonesia), **`IQ`** (Iraq), **`IE`** (Ireland), **`IM`** (Isle of Man), **`IL`** (Israel), **`IT`** (Italy), **`JM`** (Jamaica), **`JP`** (Japan), **`JE`** (Jersey), **`JO`** (Jordan), **`KZ`** (Kazakhstan), **`KE`** (Kenya), **`KI`** (Kiribati), **`XK`** (Kosovo), **`KW`** (Kuwait), **`KG`** (Kyrgyzstan), **`LA`** (Laos), **`LV`** (Latvia), **`LB`** (Lebanon), **`LS`** (Lesotho), **`LR`** (Liberia), **`LY`** (Libya), **`LI`** (Liechtenstein), **`LT`** (Lithuania), **`LU`** (Luxembourg), **`MO`** (Macau), **`MG`** (Madagascar), **`MW`** (Malawi), **`MY`** (Malaysia), **`MV`** (Maldives), **`ML`** (Mali), **`MT`** (Malta), **`MQ`** (Martinique), **`MR`** (Mauritania), **`MU`** (Mauritius), **`YT`** (Mayotte), **`MX`** (Mexico), **`MD`** (Moldova), **`MC`** (Monaco), **`MN`** (Mongolia), **`ME`** (Montenegro), **`MS`** (Montserrat), **`MA`** (Morocco), **`MZ`** (Mozambique), **`MM`** (Myanmar), **`NA`** (Namibia), **`NP`** (Nauru), **`NP`** (Nepal), **`NL`** (Netherlands), **`NC`** (New Caledonia), **`NZ`** (New Zealand), **`NI`** (Nicaragua), **`NE`** (Niger), **`NG`** (Nigeria), **`NU`** (Niue), **`NF`** (Norfolk Island), **`KP`** (North Korea), **`MK`** (North Macedonia), **`MP`** (Northern Mariana Islands), **`NO`** (Norway), **`OM`** (Oman), **`PK`** (Pakistan), **`PS`** (Palestine), **`PA`** (Panama), **`PG`** (Papua New Guinea), **`PY`** (Paraguay), **`PE`** (Peru), **`PH`** (Philippines), **`PN`** (Pitcairn Islands), **`PL`** (Poland), **`PT`** (Portugal), **`PR`** (Puerto Rico), **`QA`** (Qatar), **`RO`** (Romania), **`RU`** (Russia), **`RW`** (Rwanda), **`WS`** (Samoa), **`SM`** (San Marino), **`ST`** (São Tomé and Príncipe), **`SA`** (Saudi Arabia), **`SN`** (Senegal), **`RS`** (Serbia), **`SC`** (Seychelles), **`SL`** (Sierra Leone), **`SG`** (Singapore), **`SX`** (Sint Maarten), **`SK`** (Slovakia), **`SI`** (Slovenia), **`SB`** (Solomon Islands), **`SO`** (Somalia), **`ZA`** (South Africa), **`KR`** (South Korea), **`ES`** (Spain), **`LK`** (Sri Lanka), **`BL`** (Saint Barthélemy), **`SH`** (Saint Helena), **`KN`** (Saint Kitts and Nevis), **`LC`** (Saint Lucia), **`MF`** (Saint Martin), **`PM`** (Saint Pierre and Miquelon), **`VC`** (Saint Vincent and the Grenadines), **`SD`** (Sudan), **`SR`** (Suriname), **`SJ`** (Svalbard and Jan Mayen), **`SE`** (Sweden), **`CH`** (Switzerland), **`SY`** (Syria), **`TW`** (Taiwan), **`TJ`** (Tajikistan), **`TZ`** (Tanzania), **`TH`** (Thailand), **`TL`** (Timor-Leste), **`TG`** (Togo), **`TK`** (Tokelau), **`TK`** (Tonga), **`TT`** (Trinidad and Tobago), **`TN`** (Tunisia), **`TR`** (Turkey), **`TM`** (Turkmenistan), **`TC`** (Turks and Caicos Islands), **`TV`** (Tuvalu), **`UG`** (Uganda), **`UA`** (Ukraine), **`AE`** (United Arab Emirates), **`GB`** (United Kingdom), **`US`** (United States), **`UY`** (Uruguay), **`UZ`** (Uzbekistan), **`VU`** (Vanuatu), **`VA`** (Vatican City), **`VE`** (Venezuela), **`VN`** (Vietnam), **`WF`** (Wallis and Futuna), **`EH`** (Western Sahara), **`YE`** (Yemen), **`ZM`** (Zambia), **`ZM`** (Zimbabwe).<br>
* **createdFrom** *(integer | null)*: Filters orders created on or after a specific timestamp. \
  The value must be within the range 0 <= x <= 9007199254740991.<br>
* **createdTo** *(integer | null)*: Filters orders created on or before a specific timestamp. \
  The value must also be within the range 0 <= x <= 9007199254740991.<br>
* **orderBy** *(string)*: Specifies the sorting criteria for the orders. \
  Available options include: **`createdAt`**, **`orderNumber`**, **`value`**

### Responses Body

#### Response (200) - Success

1. **status** *(string) required:* Indicates the response status of the API call. The allowed value is success, meaning the request was processed successfully.<br>
2. **data** *(object) required*: The data is an object that contains the following children:

&#x20;**— data.orders** *(array of objects) required*: Contains a list of order objects with the following attributes:

* **data.orders.id** *(string) required:* A unique identifier for each order.
* **data.orders.number** *(string) required*: The order number assigned to the transaction.
* **data.orders.status** *(enum\<string>) required*: The current status of the order. \
  Available options are: **`PENDING`**, **`FAILED`**, **`UNPAID`**, **`CANCELLED`**, **`REFUNDED`**, **`PARTIALLY_REFUNDED`**, **`EXPIRED`**
* **data.orders.createdAt** *(integer) required*: The timestamp indicating when the order was created.\
  Required range: 0 <= x <= 9007199254740991
* **data.orders.userId** *(string) required*: The unique identifier of the user who placed the order.
* **data.orders.orderNumber** *(string) required*: The reference number assigned to the order for tracking purposes.
* **`data.orders.object`** *(enum\<string>)* *default **`order`***: Defines the type of object returned in the response.\
  Available options: **`order`**
* **data.orders.value** *(integer | null) default **`0`*** : The total value of the order.\
  Required range: -9007199254740991 <= x <= 9007199254740991
* **data.orders.tax** *(integer | null)  default: **`0`:*** The tax amount is applied to the order.\
  Required range: -9007199254740991 <= x <= 9007199254740991
* **data.orders.fee** *(integer | null)  default:**`0`*** :  The additional fee applied to the order (e.g., service or processing fee).\
  Required range: -9007199254740991 <= x <= 9007199254740991
* **data.orders.totalItems** *(integer | null) default:**`0`***: The total number of items included in the order.\
  Required range: 0 <= x <= 9007199254740991
* **data.orders.country** *(string | null):* The country associated with the order is represented by its country code.
* **data.orders.currency** *(enum\<string> | null):* The currency in which the order was placed.\
  Available options: **`AFN`** (Afghanistan), **`ALL`** (Albania), **`DZD`** (Algeria), **`AOA`** (Angola), **`ARS`** (Argentina), **`AMD`** (Armenia), **`AWG`** (Aruba), **`AUD`** (Australia), **`AZN`** (Azerbaijan), **`BSD`** (Bahamas), **`BDT`** (Bangladesh), **`BBD`** (Barbados), **`BZD`** (Belize), **`BMD`** (Bermuda), **`BOB`** (Bolivia), **`BAM`** (Bosnia and Herzegovina), **`BWP`** (Botswana), **`BRL`** (Brazil), **`BHD`** (Bahrain), **`GBP`** (United Kingdom), **`BND`** (Brunei), **`BGN`** (Bulgaria), **`BIF`** (Burundi), **`BYN`** (Belarus), **`KHR`** (Cambodia), **`CAD`** (Canada), **`CVE`** (Cape Verde), **`KYD`** (Cayman Islands), **`KWD`** (Kuwait), **`XAF`** (Central African CFA), **`XPF`** (CFP Franc), **`CLP`** (Chile), **`CNY`** (China), **`COP`** (Colombia), **`KMF`** (Comoros), **`CDF`** (Congo - Kinshasa), **`CRC`** (Costa Rica), **`HRK`** (Croatia), **`CZK`** (Czech Republic), **`DKK`** (Denmark), **`DJF`** (Djibouti), **`DOP`** (Dominican Republic), **`XCD`** (East Caribbean Dollar), **`EGP`** (Egypt), **`ETB`** (Ethiopia), **`EUR`** (Eurozone), **`FKP`** (Falkland Islands), **`FJD`** (Fiji), **`GMD`** (Gambia), **`GEL`** (Georgia), **`GIP`** (Gibraltar), **`GTQ`** (Guatemala), **`GNF`** (Guinea), **`GYD`** (Guyana), **`HTG`** (Haiti), **`HNL`** (Honduras), **`HKD`** (Hong Kong), **`HUF`** (Hungary), **`ISK`** (Iceland), INR (India), **`IDR`** (Indonesia), **`ILS`** (Israel), **`JMD`** (Jamaica), **`JPY`** (Japan), **`JOD`** (Jordan), **`KZT`** (Kazakhstan), **`KES`** (Kenya), **`KGS`** (Kyrgyzstan), **`LAK`** (Laos), **`LBP`** (Lebanon), **`LSL`** (Lesotho), **`LRD`** (Liberia), **`MOP`** (Macau), **`MKD`** (North Macedonia), **`MGA`** (Madagascar), **`MWK`** (Malawi), **`MYR`** (Malaysia), **`MVR`** (Maldives), **`MRO`** (Mauritania), **`MUR`** (Mauritius), **`MXN`** (Mexico), **`MDL`** (Moldova), **`MNT`** (Mongolia), **`MAD`** (Morocco), **`MZN`** (Mozambique), **`MMK`** (Myanmar), **`NAD`** (Namibia), **`NPR`** (Nepal), **`ANG`** (Netherlands Antilles), **`TWD`** (Taiwan), **`NZD`** (New Zealand), **`NIO`** (Nicaragua), **`NGN`** (Nigeria), **`NOK`** (Norway), **`OMR`** (Oman), **`PKR`** (Pakistan), **`PAB`** (Panama), **`PGK`** (Papua New Guinea), **`PYG`** (Paraguay), **`PEN`** (Peru), **`PHP`** (Philippines), **`PLN`** (Poland), **`QAR`** (Qatar), **`RON`** (Romania), **`RUB`** (Russia), **`RWF`** (Rwanda), **`SHP`** (Saint Helena), **`SVC`** (El Salvador), **`WST`** (Samoa), **`STD`** (São Tomé and Príncipe), **`SAR`** (Saudi Arabia), **`RSD`** (Serbia), **`SCR`** (Seychelles), **`SLL`** (Sierra Leone), **`SGD`** (Singapore), **`SBD`** (Solomon Islands), **`SOS`** (Somalia), **`ZAR`** (South Africa), **`KRW`** (South Korea), **`LKR`** (Sri Lanka), **`SRD`** (Suriname), **`SZL`** (Eswatini), **`SEK`** (Sweden), **`CHF`** (Switzerland), **`TJS`** (Tajikistan), **`TZS`** (Tanzania), **`THB`** (Thailand), **`TND`** (Tunisia), **`TOP`** (Tonga), **`TTD`** (Trinidad and Tobago), **`TRY`** (Turkey), **`UGX`** (Uganda), **`UAH`** (Ukraine), **`AED`** (United Arab Emirates), **`UYU`** (Uruguay), **`USD`** (United States), **`UZS`** (Uzbekistan), **`VUV`** (Vanuatu), **`VEF`** (Venezuela), **`VND`** (Vietnam), **`XOF`** (West African CFA), **`YER`** (Yemen), ZMW (Zambia), **`SLE`** (Sierra Leone).
* **data.orders.currencyDecimals** *(integer | null)*: The number of decimal places supported by the specified currency.\
  Required range: -9007199254740991 <= x <= 9007199254740991

— **data.orders.user** *(object | null)*: This is the user details object; it will have the children listed below:

* **data.orders.user.id** *(string) required*: A unique identifier for the user who placed the order.
* **data.orders.user.object** *(enum\<string>)  default: **`user`***: Defines the type of object returned in the response.\
  Available options: **`user`**
* **data.orders.user.username** *(string | null)*: The username of the user associated with the order, if available.

**— data.count** *(number | null) required*: Represents the total number of orders that match the request criteria.\
Required range: -1.7976931348623157e+308 <= x <= 1.7976931348623157e+308

#### Response (400) - Error

1. **status** *(string) required*: Represents the status of the response. The allowed value is an error.
2. **error** *(object) required*: Contains details about the error, including the following child attributes:

* **error.message** *(string) required*: A descriptive message explaining the reason for the error.

### Example of Endpoint Usage

Examples of how to use the endpoint across different programming languages.

1. **cURL:**

```
curl --request GET \
  --url https://api.fungies.io/v0/orders/list \
  --header 'x-fngs-public-key: <api-key>'
```

2. **Python:**

```
import requests

url = "https://api.fungies.io/v0/orders/list"

headers = {"x-fngs-public-key": "<api-key>"}

response = requests.request("GET", url, headers=headers)

print(response.text)
```

3. **JavaScript:**

```
const options = {method: 'GET', headers: {'x-fngs-public-key': '<api-key>'}};

fetch('https://api.fungies.io/v0/orders/list', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
```

4. **PHP:**

```
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.fungies.io/v0/orders/list",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => [
    "x-fngs-public-key: <api-key>"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
```

5. **Go:**

```
package main

import (
"fmt"
"net/http"
"io/ioutil"
)

func main() {

url := "https://api.fungies.io/v0/orders/list"

req, _ := http.NewRequest("GET", url, nil)

req.Header.Add("x-fngs-public-key", "<api-key>")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)

fmt.Println(res)
fmt.Println(string(body))

}
```

6. **JAVA:**

```
HttpResponse<String> response = Unirest.get("https://api.fungies.io/v0/orders/list")
  .header("x-fngs-public-key", "<api-key>")
  .asString();
```

### Example of a Successful Response (200)

200 OK – The list of orders is successfully retrieved.

```
{
  "status": "<string>",
  "data": {
    "orders": [
      {
        "object": "order",
        "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "number": "<string>",
        "status": "PENDING",
        "value": 0,
        "tax": 0,
        "fee": 0,
        "totalItems": 0,
        "country": null,
        "currency": null,
        "currencyDecimals": null,
        "createdAt": 4503599627370495,
        "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "user": null,
        "orderNumber": "<string>"
      }
    ],
    "count": 0
  }
}
```

### Example of Error Response (400)

400 Bad Request – Invalid query parameters.

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```


# Cancel Order

## PATCH/orders/{orderIdOrNumber}/cancel

The `PATCH /orders/{orderIdOrNumber}/cancel` endpoint is used to cancel a specific order by updating its status to **CANCELLED**. This endpoint is typically used when an order needs to be stopped before it is fulfilled or processed. **Write access** is required to use this endpoint.

**Request Method:** PATCH

**Endpoint URL:** <https://api.fungies.io/v0/orders/{orderIdOrNumber}/cancel>

**Headers:**

x-fngs-public-key: \<api-key>

x-fngs-secret-key: \<api-key>

**Example:**

```
Authorization: x-fngs-public-key: <api-key>
```

```
Authorization: x-fngs-secret-key: <api-key>
```

> **Note:** This endpoint requires an API key for authentication. Refer to [this ](https://help.fungies.io/for-saas-developers/getting-started-with-the-api#generating-the-api-keys)guide to generate your API key.

### Path Parameters

The Path Parameters are required to specify the order that needs to be canceled.

* **orderIdOrNumber** *(string) required:* Identifies the specific order to cancel. This parameter accepts either the unique order ID (Option 1) or the order number (Option 2) to process the cancellation request.

### Request Body

The request body for the Cancel Order API is of type `object`. This body structure allows the system to process the order cancellation request, ensuring the specified order is updated accordingly.

### Responses Body

#### Response (200) - Success

The response confirms that the order cancellation request was successfully processed.

1. **status** *(string) required:* Indicates the outcome of the API request. The allowed value is success, confirming that the cancellation was applied.
2. **data** *(object) required*: The data object contains details related to the canceled order. It includes the following children:

**— data.order** *(object) required*: This object holds the details of the order and other relevant information. It includes the following children:

* **data.order.id** *(string) required:* A unique identifier assigned to the order.
* **data.order.number** *(string) required:* The order number is used for reference and tracking.
* **data.order.status** *(enum) required:* Represents the current status of the order. \
  Available options: **`PENDING`**, **`PAID`**, **`FAILED`**, **`UNPAID`**, **`CANCELLED`**, **`REFUNDED`**, **`PARTIALLY_REFUNDED`**, **`EXPIRED`**.
* **data.order.createdAt** *(integer) required:* The timestamp represents when the order was created.\
  Required range: 0 <= x <= 9007199254740991
* **data.order.userId** *(string) required*: The unique identifier of the user associated with the order.
* **data.order.orderNumber** *(string) required:* The reference number assigned to the order for tracking purposes.
* **data.order.object** *(enum) default: order*: Represents the type of object. \
  Available options: `order`
* **data.order.value** *(integer | null) default: 0*: Represents the monetary value of the order. \
  Required range: -9007199254740991 <= x <= 9007199254740991
* **data.order.tax** *(integer | null) default: 0*: The amount of tax applied to the order. \
  Required range: -9007199254740991 <= x <= 9007199254740991
* **data.order.fee** *(integer | null) default: 0*: The additional fee associated with the order, such as processing or service fees. \
  Required range: -9007199254740991 <= x <= 9007199254740991
* **data.order.totalItems** *(integer | null) default: 0*: The total number of items included in the order.\
  Required range: 0 <= x <= 9007199254740991
* **data.order.country** *(string | null):* The country associated with the order, typically where it was placed or where it will be delivered.
* **data.order.currency** *(enum | null)*: The currency used for the order transaction. \
  Available options: **`AFN`** (Afghanistan), **`ALL`** (Albania), **`DZD`** (Algeria), **`AOA`** (Angola), **`ARS`** (Argentina), **`AMD`** (Armenia), **`AWG`** (Aruba), **`AUD`** (Australia), **`AZN`** (Azerbaijan), **`BSD`** (Bahamas), **`BDT`** (Bangladesh), **`BBD`** (Barbados), **`BZD`** (Belize), **`BMD`** (Bermuda), **`BOB`** (Bolivia), **`BAM`** (Bosnia and Herzegovina), **`BWP`** (Botswana), **`BRL`** (Brazil), **`BHD`** (Bahrain), **`GBP`** (United Kingdom), **`BND`** (Brunei), **`BGN`** (Bulgaria), **`BIF`** (Burundi), **`BYN`** (Belarus), **`KHR`** (Cambodia), **`CAD`** (Canada), **`CVE`** (Cape Verde), **`KYD`** (Cayman Islands), **`KWD`** (Kuwait), **`XAF`** (Central African CFA), **`XPF`** (CFP Franc), **`CLP`** (Chile), **`CNY`** (China), **`COP`** (Colombia), **`KMF`** (Comoros), **`CDF`** (Congo - Kinshasa), **`CRC`** (Costa Rica), **`HRK`** (Croatia), **`CZK`** (Czech Republic), **`DKK`** (Denmark), **`DJF`** (Djibouti), **`DOP`** (Dominican Republic), **`XCD`** (East Caribbean Dollar), **`EGP`** (Egypt), **`ETB`** (Ethiopia), **`EUR`** (Eurozone), **`FKP`** (Falkland Islands), **`FJD`** (Fiji), **`GMD`** (Gambia), **`GEL`** (Georgia), **`GIP`** (Gibraltar), **`GTQ`** (Guatemala), **`GNF`** (Guinea), **`GYD`** (Guyana), **`HTG`** (Haiti), **`HNL`** (Honduras), **`HKD`** (Hong Kong), **`HUF`** (Hungary), **`ISK`** (Iceland), **`INR`** (India), **`IDR`** (Indonesia), **`ILS`** (Israel), **`JMD`** (Jamaica), **`JPY`** (Japan), **`JOD`** (Jordan), **`KZT`** (Kazakhstan), **`KES`** (Kenya), **`KGS`** (Kyrgyzstan), **`LAK`** (Laos), **`LBP`** ( Lebanon), **`LSL`** (Lesotho), **`LRD`** (Liberia), **`MOP`** (Macau), **`MKD`** (North Macedonia), **`MGA`** (Madagascar), **`MWK`** (Malawi), **`MYR`** (Malaysia), **`MVR`** (Maldives), **`MRO`** (Mauritania), **`MUR`** (Mauritius), **`MXN`** (Mexico), **`MDL`** (Moldova), **`MNT`** (Mongolia), **`MAD`** (Morocco), **`MZN`** (Mozambique), **`MMK`** (Myanmar), **`NAD`** (Namibia), **`NPR`** (Nepal), **`ANG`** (Netherlands Antilles), **`TWD`** (Taiwan), **`NZD`** (New Zealand), **`NIO`** (Nicaragua), **`NGN`** (Nigeria), **`NOK`** (Norway), **`OMR`** (Oman), **`PKR`** (Pakistan), **`PAB`** (Panama), **`PGK`** (Papua New Guinea), **`PYG`** (Paraguay), **`PEN`** (Peru), **`PHP`** (Philippines), **`PLN`** (Poland), **`QAR`** (Qatar), **`RON`** (Romania), **`RUB`** (Russia), **`RWF`** (Rwanda), **`SHP`** (Saint Helena), **`SVC`** (El Salvador), **`WST`** (Samoa), **`STD`** (São Tomé and Príncipe), **`SAR`** (Saudi Arabia), **`RSD`** (Serbia), **`SCR`** (Seychelles), **`SLL`** (Sierra Leone), **`SGD`** (Singapore), **`SBD`** (Solomon Islands), **`SOS`** (Somalia), **`ZAR`**  (South Africa), **`KRW`** (South Korea), **`LKR`** (Sri Lanka), **`SRD`** (Suriname), **`SZL`** (Eswatini), **`SEK`** (Sweden), **`CHF`** (Switzerland), **`TJS`** (Tajikistan), **`TZS`** ( Tanzania), **`THB`**( Thailand), **`TND`** (Tunisia), **`TOP`** (Tonga), **`TTD`** (Trinidad and Tobago), **`TRY`** (Turkey), **`UGX`** (Uganda), **`UAH`** (Ukraine), **`AED`** (United Arab Emirates), **`UYU`** (Uruguay), **`USD`** (United States), **`UZS`** (Uzbekistan), **`VUV`** (Vanuatu), **`VEF`** (Venezuela), **`VND`** (Vietnam), **`XOF`** (West African CFA), **`YER`** (Yemen), **`ZMW`** (Zambia), **`SLE`** (Sierra Leone).
* **data.order.currencyDecimals** *(integer | null)*: Specifies the number of decimal places used in the currency format for the order. \
  Required range: -9007199254740991 <= x <= 9007199254740991
* **data.order.user** *(object | null):* Contains user-related details associated with the order. It includes the following children:
  * **data.order.user.id** *(string) required:* A unique identifier is assigned to the user.
  * **data.order.user.object** *(enum) default: user:* Specifies the type of object. The available option is user
  * **data.order.user.username** *(string | null):* The username of the user associated with the order.

#### Response (400) - Error

1. **status** *(string) required*: Represents the outcome of the API request. The allowed value is an error, indicating that the request was unsuccessful.
2. **error** *(object) required*: Contains details about the error encountered during the request. It includes the following child attributes:
   1. **error.message** *(string) required:* A descriptive message explaining the reason for the error.

### Example of Endpoint Usage

Examples of how to use the endpoint across different programming languages.

1. **cURL**

```
curl --request PATCH \
  --url https://api.fungies.io/v0/orders/{orderIdOrNumber}/cancel \
  --header 'Content-Type: application/json' \
  --header 'x-fngs-public-key: <api-key>' \
  --header 'x-fngs-secret-key: <api-key>' \
  --data '{}'
```

2. **Python**

```
import requests

url = "https://api.fungies.io/v0/orders/{orderIdOrNumber}/cancel"

payload = {}
headers = {
    "x-fngs-public-key": "<api-key>",
    "x-fngs-secret-key": "<api-key>",
    "Content-Type": "application/json"
}

response = requests.request("PATCH", url, json=payload, headers=headers)

print(response.text)
```

3. **JavaScript**

```
const options = {
  method: 'PATCH',
  headers: {
    'x-fngs-public-key': '<api-key>',
    'x-fngs-secret-key': '<api-key>',
    'Content-Type': 'application/json'
  },
  body: '{}'
};

fetch('https://api.fungies.io/v0/orders/{orderIdOrNumber}/cancel', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
```

4. **PHP**

```
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.fungies.io/v0/orders/{orderIdOrNumber}/cancel",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PATCH",
  CURLOPT_POSTFIELDS => "{}",
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json",
    "x-fngs-public-key: <api-key>",
    "x-fngs-secret-key: <api-key>"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
```

5. **Go**

```
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api.fungies.io/v0/orders/{orderIdOrNumber}/cancel"

	payload := strings.NewReader("{}")

	req, _ := http.NewRequest("PATCH", url, payload)

	req.Header.Add("x-fngs-public-key", "<api-key>")
	req.Header.Add("x-fngs-secret-key", "<api-key>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

6. **Java**

```
HttpResponse<String> response = Unirest.patch("https://api.fungies.io/v0/orders/{orderIdOrNumber}/cancel")
  .header("x-fngs-public-key", "<api-key>")
  .header("x-fngs-secret-key", "<api-key>")
  .header("Content-Type", "application/json")
  .body("{}")
  .asString();
```

### Example of a Successful Response (200)

200 OK – The list of orders is successfully retrieved.

```
{
  "status": "<string>",
  "data": {
    "order": {
      "object": "order",
      "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
      "number": "<string>",
      "status": "PENDING",
      "value": 0,
      "tax": 0,
      "fee": 0,
      "totalItems": 0,
      "country": null,
      "currency": null,
      "currencyDecimals": null,
      "createdAt": 4503599627370495,
      "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
      "user": null,
      "orderNumber": "<string>"
    }
  }
}
```

### Example of Error Response (400)

400 Bad Request – Invalid query parameters.

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```


# Update Order

## PATCH/orders/{orderIdOrNumber}/update

The `PATCH /orders/{orderIdOrNumber}/update` endpoint updates an existing order's details, including status, fees, and taxes. It requires **write access** with x-fngs-public-key and x-fngs-secret-key. Updates are sent in JSON format.

**Request Method**: PATCH

**Endpoint URL**: <https://api.fungies.io/v0/orders/{orderIdOrNumber}/update>

**Headers:**

x-fngs-public-key: \<api-key>

x-fngs-secret-key: \<api-key>

**Example:**&#x20;

```
Authorization: x-fngs-public-key: <api-key>
```

```
Authorization: x-fngs-secret-key: <api-key>
```

> **Note:** This endpoint requires an API key for authentication. Refer to [this ](https://help.fungies.io/for-saas-developers/getting-started-with-the-api#generating-the-api-keys)guide to generate your API key.

### Path Parameters

The path parameter is required for the **Update Order** API endpoint and is used to specify the order that needs to be updated.

* **orderIdOrNumber** *(string) required:* Identifies the specific order to update. This parameter accepts either the unique order ID (Option 1) or the order number (Option 2) to modify order details.

### Request Body

The request body for the `PATCH /orders/{orderIdOrNumber}/update` endpoint allows updating specific attributes of an order.

* **status** *(enum)*: Specifies the current status of the order. \
  Available options: **`PENDING`**, **`PAID`**, **`FAILED`**, **`UNPAID`**, **`CANCELLED`**, **`REFUNDED`**, **`PARTIALLY_REFUNDED`**, **`EXPIRED`**.
* **value** *(number | null)*: Represents the monetary value of the order. \
  Range: -1.7976931348623157e+308 <= x <= 1.7976931348623157e+308
* **fee** *(number | null):* Indicates any applicable fees associated with the order. \
  Range: -1.7976931348623157e+308 <= x <= 1.7976931348623157e+308
* **tax** *(number | null):* Specifies the tax amount applied to the order. \
  Range: -1.7976931348623157e+308 <= x <= 1.7976931348623157e+308
* **currency** *(enum | null)*: Defines the currency type associated with the order. The accepted values are ISO 4217 currency codes.\
  Available options: **`AFN`** (Afghanistan), **`ALL`** (Albania), **`DZD`** (Algeria), **`AOA`** (Angola), **`ARS`** (Argentina), **`AMD`** (Armenia), **`AWG`** (Aruba), **`AUD`** (Australia), **`AZN`** (Azerbaijan), **`BSD`** (Bahamas), **`BDT`** (Bangladesh), **`BBD`** (Barbados), **`BZD`** (Belize), **`BMD`** (Bermuda), **`BOB`** (Bolivia), **`BAM`** (Bosnia and Herzegovina), **`BWP`** (Botswana), **`BRL`** (Brazil), **`BHD`** (Bahrain), **`GBP`** (United Kingdom), **`BND`** (Brunei), **`BGN`** (Bulgaria), **`BIF`** (Burundi), **`BYN`** (Belarus), **`KHR`** (Cambodia), **`CAD`** (Canada), **`CVE`** (Cape Verde), **`KYD`** (Cayman Islands), **`KWD`** (Kuwait), **`XAF`** (Central African CFA), **`XPF`** (CFP Franc), **`CLP`** (Chile), **`CNY`** (China), **`COP`** (Colombia), **`KMF`** (Comoros), **`CDF`** (Congo - Kinshasa), **`CRC`** (Costa Rica), **`HRK`** (Croatia), **`CZK`** (Czech Republic), **`DKK`** (Denmark), **`DJF`** (Djibouti), **`DOP`** (Dominican Republic), **`XCD`** (East Caribbean Dollar), **`EGP`** (Egypt), **`ETB`** (Ethiopia), **`EUR`** (Eurozone), **`FKP`** (Falkland Islands), **`FJD`** (Fiji), **`GMD`** (Gambia), **`GEL`** (Georgia), **`GIP`** (Gibraltar), **`GTQ`** (Guatemala), **`GNF`** (Guinea), **`GYD`** (Guyana), **`HTG`** (Haiti), **`HNL`** (Honduras), **`HKD`** (Hong Kong), **`HUF`** (Hungary), **`ISK`** (Iceland), **`INR`** (India), **`IDR`** (Indonesia), **`ILS`** (Israel), **`JMD`** (Jamaica), **`JPY`** (Japan), **`JOD`** (Jordan), **`KZT`** (Kazakhstan), **`KES`** (Kenya), **`KGS`** (Kyrgyzstan), **`LAK`** (Laos), **`LBP`** (Lebanon), **`LSL`** (Lesotho), **`LRD`** (Liberia), **`MOP`** (Macau), **`MKD`** (North Macedonia), **`MGA`** (Madagascar), **`MWK`** (Malawi), **`MYR`** (Malaysia), **`MVR`** (Maldives), **`MRO`** (Mauritania), **`MUR`** (Mauritius), **`MXN`** (Mexico), **`MDL`** (Moldova), **`MNT`** (Mongolia), **`MAD`** (Morocco), **`MZN`** (Mozambique), **`MMK`** (Myanmar), **`NAD`** (Namibia), **`NPR`** (Nepal), **`ANG`** (Netherlands Antilles), **`TWD`** (Taiwan), **`NZD`** (New Zealand), **`NIO`** (Nicaragua), **`NGN`** (Nigeria), **`NOK`** (Norway), **`OMR`** (Oman), **`PKR`** (Pakistan), **`PAB`** (Panama), **`PGK`** (Papua New Guinea), **`PYG`** (Paraguay), **`PEN`** (Peru), **`PHP`** (Philippines), **`PLN`** (Poland), **`QAR`** (Qatar), **`RON`** (Romania), **`RUB`** (Russia), **`RWF`** (Rwanda), **`SHP`** (Saint Helena), **`SVC`** (El Salvador), **`WST`** (Samoa), **`STD`** (São Tomé and Príncipe), **`SAR`** (Saudi Arabia), **`RSD`** (Serbia), **`SCR`** (Seychelles), **`SLL`** (Sierra Leone), **`SGD`** (Singapore), **`SBD`** (Solomon Islands), **`SOS`** (Somalia), **`ZAR`** (South Africa), **`KRW`** (South Korea), **`LKR`** (Sri Lanka), **`SRD`** (Suriname), **`SZL`** (Eswatini), **`SEK`** (Sweden), **`CHF`** (Switzerland), **`TJS`** (Tajikistan), **`TZS`** (Tanzania), **`THB`** (Thailand), **`TND`** (Tunisia), **`TOP`** (Tonga), **`TTD`** (Trinidad and Tobago), **`TRY`** (Turkey), **`UGX`** (Uganda), **`UAH`** (Ukraine), **`AED`** (United Arab Emirates), **`UYU`** (Uruguay), **`USD`** (United States), **`UZS`** (Uzbekistan), **`VUV`** (Vanuatu), **`VEF`** (Venezuela), **`VND`** (Vietnam), **`XOF`** (West African CFA), **`YER`** (Yemen), **`ZMW`** (Zambia), **`SLE`** (Sierra Leone).

### Responses Body

#### Response (200) - Success

The response confirms that the order update request was successfully processed.

1. **status** *(string) required*: Indicates the outcome of the API request. The allowed value is success, confirming that the update was applied.
2. **data** *(object) required*: The data object contains the details of the updated order. It includes the following children:

**— data.order** *(object) required:* This object holds the details of the order, including its ID, status, payment information, and associated customer details. It includes the following child attributes:

* **data.order.id** *(string) required:* A unique identifier assigned to the order.
* **data.order.number** *(string) required:* The order number is assigned for reference and tracking purposes.
* **data.order.status** *(enum) required:* The current status of the order. \
  Available options: **`PENDING`**, **`PAID`**, **`FAILED`**, **`UNPAID`**, **`CANCELLED`**, **`REFUNDED`**, **`PARTIALLY_REFUNDED`**, **`EXPIRED`**.
* **data.order.createdAt** *(integer) required:* The timestamp represents when the order was created.\
  Required range: 0 ≤ x ≤ 9007199254740991
* **data.order.userId** *(string) required:* The user identifier associated with the order.
* **data.order.orderNumber** *(string) required*: The unique order number assigned to the transaction.
* **data.order.object** *(enum):* Defines the object type. The default value is order. \
  Available options: `order`
* **data.order.value** *(integer | null) default: 0:* The total value of the order. \
  Required range: -9007199254740991 ≤ x ≤ 9007199254740991
* **data.order.tax** *(integer | null) default: 0:* The tax amount is applied to the order. \
  Required range: -9007199254740991 ≤ x ≤ 9007199254740991
* **data.order.fee** *(integer | null) default: 0*: The fee amount associated with the order. \
  Required range: -9007199254740991 ≤ x ≤ 9007199254740991
* **data.order.totalItems** *(integer | null) default: 0*: The total number of items included in the order.\
  Required range: 0 ≤ x ≤ 9007199254740991
* **data.order.country** *(string | null)*: The country associated with the order.
* **data.order.currency** *(enum | null):* The currency in which the order is processed. \
  Available options: **`AFN`**(Afghanistan), **`ALL`**(Albania), **`DZD`**(Algeria), **`AOA`**(Angola), **`ARS`**(Argentina), **`AMD`**(Armenia), **`AWG`**(Aruba), **`AUD`**(Australia), **`AZN`**(Azerbaijan), **`BSD`**(Bahamas), **`BDT`**(Bangladesh), **`BBD`**(Barbados), **`BZD`**(Belize), **`BMD`**(Bermuda), **`BOB`**(Bolivia), **`BAM`**(Bosnia and Herzegovina), **`BWP`**(Botswana), **`BRL`**(Brazil), **`BHD`**(Bahrain), **`GBP`**(United Kingdom), **`BND`**(Brunei), **`BGN`**(Bulgaria), **`BIF`**(Burundi), **`BYN`**(Belarus), **`KHR`**(Cambodia), **`CAD`**(Canada), **`CVE`**(Cape Verde), **`KYD`**(Cayman Islands), **`KWD`**(Kuwait), **`XAF`**(Central African CFA), **`XPF`**(CFP Franc), **`CLP`**(Chile), **`CNY`**(China), **`COP`**(Colombia), **`KMF`**(Comoros), **`CDF`**(Congo - Kinshasa), **`CRC`**(Costa Rica), **`HRK`**(Croatia), **`CZK`**(Czech Republic), **`DKK`**(Denmark), **`DJF`**(Djibouti), **`DOP`**(Dominican Republic), **`XCD`**(East Caribbean Dollar), **`EGP`**(Egypt), **`ETB`**(Ethiopia), **`EUR`**(Eurozone), **`FKP`**(Falkland Islands), **`FJD`**(Fiji), **`GMD`**(Gambia), **`GEL`**(Georgia), **`GIP`**(Gibraltar), **`GTQ`**(Guatemala), **`GNF`**(Guinea), **`GYD`**(Guyana), **`HTG`**(Haiti), **`HNL`**(Honduras), **`HKD`**(Hong Kong), **`HUF`**(Hungary), **`ISK`**(Iceland), **`INR`**(India), **`IDR`**(Indonesia), **`ILS`**(Israel), **`JMD`**(Jamaica), **`JPY`**(Japan), **`JOD`**(Jordan), **`KZT`**(Kazakhstan), **`KES`**(Kenya), **`KGS`**(Kyrgyzstan), **`LAK`**(Laos), **`LBP`**(Lebanon), **`LSL`**(Lesotho), **`LRD`**(Liberia), **`MOP`**(Macau), **`MKD`**(North Macedonia), **`MGA`**(Madagascar), **`MWK`**(Malawi), **`MYR`**(Malaysia), **`MVR`**(Maldives), **`MRO`**(Mauritania), **`MUR`**(Mauritius), **`MXN`**(Mexico), **`MDL`**(Moldova), **`MNT`**(Mongolia), **`MAD`**(Morocco), **`MZN`**(Mozambique), **`MMK`**(Myanmar), **`NAD`**(Namibia), **`NPR`**(Nepal), **`ANG`**(Netherlands Antilles), **`TWD`**(Taiwan), **`NZD`**(New Zealand), **`NIO`**(Nicaragua), **`NGN`**(Nigeria), **`NOK`**(Norway), **`OMR`**(Oman), **`PKR`**(Pakistan), **`PAB`**(Panama), **`PGK`**(Papua New Guinea), **`PYG`**(Paraguay), **`PEN`**(Peru), **`PHP`**(Philippines), **`PLN`**(Poland), **`QAR`**(Qatar), **`RON`**(Romania), **`RUB`**(Russia), **`RWF`**(Rwanda), **`SHP`**(Saint Helena), **`SVC`**(El Salvador), **`WST`**(Samoa), **`STD`**(São Tomé and Príncipe), **`SAR`**(Saudi Arabia), **`RSD`**(Serbia), **`SCR`**(Seychelles), **`SLL`**(Sierra Leone), **`SGD`**(Singapore), **`SBD`**(Solomon Islands), **`SOS`**(Somalia), **`ZAR`**(South Africa), **`KRW`**(South Korea), **`LKR`**(Sri Lanka), **`SRD`**(Suriname), **`SZL`**(Eswatini), **`SEK`**(Sweden), **`CHF`**(Switzerland), **`TJS`**(Tajikistan), **`TZS`**(Tanzania), **`THB`**(Thailand), **`TND`**(Tunisia), **`TOP`**(Tonga), **`TTD`**(Trinidad and Tobago), **`TRY`**(Turkey), **`UGX`**(Uganda), **`UAH`**(Ukraine), **`AED`**(United Arab Emirates), **`UYU`**(Uruguay), **`USD`**(United States), **`UZS`**(Uzbekistan), **`VUV`**(Vanuatu), **`VEF`**(Venezuela), **`VND`**(Vietnam), **`XOF`**(West African CFA), **`YER`**(Yemen), **`ZMW`**(Zambia), **`SLE`**(Sierra Leone).
* **data.order.currencyDecimals** *(integer | null)*: The number of decimal places used for the currency in the order. \
  Required range: -9007199254740991 ≤ x ≤ 9007199254740991
* **data.order.user** *(object | null)*: This object contains details about the user associated with the order. It includes the following child attributes:
  * **data.order.user.id** *(string) required:* A unique identifier is assigned to the user associated with the order.
  * **data.order.user.object** *(enum) default: user:* Specifies the type of object. \
    The only available option is `user`
  * **data.order.user.username** *(string | null):* The username of the user associated with the order, if available.

#### Response (400) - Error

1. **status** *(string) required*: Represents the status of the response. The allowed value is an error.
2. **error** *(object) required:* This object contains details about the error encountered during the request. It includes the following child attributes:
   1. **error.message** *(string) required*: A descriptive message explaining the reason for the error.

### Example of Endpoint Usage

Examples of how to use the endpoint across different programming languages.

1. **cURL**

```
curl --request PATCH \
  --url https://api.fungies.io/v0/orders/{orderIdOrNumber}/update \
  --header 'Content-Type: application/json' \
  --header 'x-fngs-public-key: <api-key>' \
  --header 'x-fngs-secret-key: <api-key>' \
  --data '{
  "status": "PENDING",
  "value": 0,
  "fee": 0,
  "tax": 0,
  "currency": "AFN"
}'
```

2. **Python**

```
import requests

url = "https://api.fungies.io/v0/orders/{orderIdOrNumber}/update"

payload = {
    "status": "PENDING",
    "value": 0,
    "fee": 0,
    "tax": 0,
    "currency": "AFN"
}
headers = {
    "x-fngs-public-key": "<api-key>",
    "x-fngs-secret-key": "<api-key>",
    "Content-Type": "application/json"
}

response = requests.request("PATCH", url, json=payload, headers=headers)

print(response.text)
```

3. **JavaScript**

```
const options = {
  method: 'PATCH',
  headers: {
    'x-fngs-public-key': '<api-key>',
    'x-fngs-secret-key': '<api-key>',
    'Content-Type': 'application/json'
  },
  body: '{"status":"PENDING","value":0,"fee":0,"tax":0,"currency":"AFN"}'
};

fetch('https://api.fungies.io/v0/orders/{orderIdOrNumber}/update', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
```

4. **PHP**

```
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.fungies.io/v0/orders/{orderIdOrNumber}/update",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PATCH",
  CURLOPT_POSTFIELDS => "{\n  \"status\": \"PENDING\",\n  \"value\": 0,\n  \"fee\": 0,\n  \"tax\": 0,\n  \"currency\": \"AFN\"\n}",
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json",
    "x-fngs-public-key: <api-key>",
    "x-fngs-secret-key: <api-key>"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
```

5. **Go**

```
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api.fungies.io/v0/orders/{orderIdOrNumber}/update"

	payload := strings.NewReader("{\n  \"status\": \"PENDING\",\n  \"value\": 0,\n  \"fee\": 0,\n  \"tax\": 0,\n  \"currency\": \"AFN\"\n}")

	req, _ := http.NewRequest("PATCH", url, payload)

	req.Header.Add("x-fngs-public-key", "<api-key>")
	req.Header.Add("x-fngs-secret-key", "<api-key>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

6. **Java**

```
HttpResponse<String> response = Unirest.patch("https://api.fungies.io/v0/orders/{orderIdOrNumber}/update")
  .header("x-fngs-public-key", "<api-key>")
  .header("x-fngs-secret-key", "<api-key>")
  .header("Content-Type", "application/json")
  .body("{\n  \"status\": \"PENDING\",\n  \"value\": 0,\n  \"fee\": 0,\n  \"tax\": 0,\n  \"currency\": \"AFN\"\n}")
  .asString();
```

### Example of a Successful Response (200)

200 OK – The list of orders is successfully retrieved.

```
{
  "status": "<string>",
  "data": {
    "order": {
      "object": "order",
      "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
      "number": "<string>",
      "status": "PENDING",
      "value": 0,
      "tax": 0,
      "fee": 0,
      "totalItems": 0,
      "country": null,
      "currency": null,
      "currencyDecimals": null,
      "createdAt": 4503599627370495,
      "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
      "user": null,
      "orderNumber": "<string>"
    }
  }
}
```

### Example of Error Response (400)

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```


# Managing Subscriptions through API

Subscriptions through API provide developers with detailed guide on how to handle subscription-related operations using API endpoints. This includes updating, retrieving, & cancelling subscriptions.

Managing subscriptions is a key feature of the Fungies.io platform, allowing businesses to offer recurring billing and subscription-based services to their users. The subscription endpoints enable developers to retrieve, manage, and cancel subscriptions, providing full control over the subscription lifecycle. These endpoints are particularly useful for handling subscription statuses, updating customer details, and processing cancellations.

To access these endpoints, authentication via API keys is required, you can go through the "[Getting Started with the API](https://help.fungies.io/for-saas-developers/getting-started-with-the-api)" guide in which you will learn how you can generate the `API-key` and `write-API-key`.

After generating the `API key` and `write-API key` you can immediately start making requests to the Fungies Subscriptions API endpoints.

## GET /subscriptions/list (List All Subscriptions)

The `/subscriptions/list` endpoint is used to retrieve a list of all subscriptions from the Fungies.io platform. It allows developers to access details of every subscription within the system, providing an overview of active, cancelled, or all subscriptions.

> **Note:** This endpoint requires an `API key` for authentication.

This is a `GET` API endpoint that accepts the following parameters:

* **`status`:** Specifies the current status of the subscriptions. Possible values include-

  `active`**:** Lists all active subscriptions.\
  `canceled`**:** Lists all cancelled subscriptions.\
  `all`**:** Lists both active and cancelled subscriptions.
* **`cursor`:** The cursor parameter is used for pagination. It points to a specific position in a list of results, allowing you to retrieve the next set of data starting from this position.
* **`take`:** The take parameter defines the number of items to return in a single request. It controls how many records are fetched from the database or API at once. For example, the setting `take=10` would retrieve 10 records per request.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": {
    "subscriptions": [
      {
        "id": "<string>",
        "currentPeriodEnd": "2023-11-07T05:31:56Z",
        "currentPeriodStart": "2023-11-07T05:31:56Z",
        "cancelAtPeriodEnd": true,
        "createdAt": "2023-11-07T05:31:56Z",
        "status": "active",
        "interval": "day",
        "canceledAt": "2023-11-07T05:31:56Z",
        "cancellationDetails": {
          "comment": "<string>",
          "feedback": "<string>",
          "reason": "<string>"
        },
        "user": {
          "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
          "email": "jsmith@example.com",
          "createdAt": "2023-11-07T05:31:56Z",
          "details": {
            "avatar": "<string>"
          },
          "settings": {
            "newsletter": true
          },
          "username": "<string>"
        },
        "cart": {
          "id": "<string>",
          "status": "ACTIVE",
          "itemsInCart": 0,
          "totalValue": 0,
          "subtotal": 0,
          "totalValueWithTax": 0,
          "totalTax": 0,
          "createdAt": "2023-11-07T05:31:56Z"
        }
      }
    ],
    "count": 0
  }
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

## GET /subscriptions/{subscriptionId} (Get Subscription by ID)

The `/subscriptions/{subscriptionId}` endpoint is used to retrieve details of a specific subscription by its unique ID. This allows developers to access subscription information for a particular user.

> **Note:** This endpoint requires an `API key` for authentication.

This is a `GET` API endpoint that accepts a single parameter to filter the results:

* **`subscriptionId`:** The unique ID of the subscription you want to retrieve.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": {
    "id": "<string>",
    "currentPeriodEnd": "2023-11-07T05:31:56Z",
    "currentPeriodStart": "2023-11-07T05:31:56Z",
    "cancelAtPeriodEnd": true,
    "createdAt": "2023-11-07T05:31:56Z",
    "status": "active",
    "interval": "day",
    "canceledAt": "2023-11-07T05:31:56Z",
    "cancellationDetails": {
      "comment": "<string>",
      "feedback": "<string>",
      "reason": "<string>"
    },
    "user": {
      "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
      "email": "jsmith@example.com",
      "createdAt": "2023-11-07T05:31:56Z",
      "details": {
        "avatar": "<string>"
      },
      "settings": {
        "newsletter": true
      },
      "username": "<string>"
    },
    "cart": {
      "id": "<string>",
      "status": "ACTIVE",
      "itemsInCart": 0,
      "totalValue": 0,
      "subtotal": 0,
      "totalValueWithTax": 0,
      "totalTax": 0,
      "createdAt": "2023-11-07T05:31:56Z"
    }
  }
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

## PATCH /subscriptions/{subscriptionId}/cancel (Cancel Subscription)

The `/subscriptions/{subscriptionId}/cancel` endpoint is used to cancel a specific subscription by its ID. It allows developers to cancel a user's subscription and offers options for how the cancellation should be handled, such as immediate cancellation or at the end of the billing period.

> **Note:** This endpoint requires an `API key` and `write-API key` (both) for authentication at the same time.

This is a `PATCH` API endpoint that requires the following in the request body:

* **`Id`:** The ID used as the unique identifier of the specific subscription.
* **`cancelOption`:** The cancelOption determines how the subscription should be cancelled. It allows you to specify whether the cancellation should take effect immediately or at the end of the current billing cycle. Available options- \
  `immediately`: When set, the action (such as cancellation or modification of the subscription) will take effect immediately upon execution.\
  `endPeriod`: When set, the action will be deferred until the end of the current billing period. This allows the subscription to continue through the remainder of the paid period before changes like cancellation or downgrades are applied.
* **`refundOption`:** The refundOption defines how refunds should be handled when a subscription is cancelled. It provides options for whether and how much to refund the user based on the timing of the cancellation. Available options: \
  `noRefund`: When set, this parameter ensures that no refund is issued upon cancellation of the subscription, regardless of any remaining time in the billing cycle.\
  `lastPayment`: When set, the system will retain the last payment made for the subscription without issuing a refund or making any adjustments.\
  `prorate`: When set, this parameter enables prorated adjustments based on the remaining time in the subscription period. For example, if a user upgrades or downgrades their subscription in the middle of a billing cycle, the system will calculate a prorated charge or credit to reflect the partial use of the original plan.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": {
    "success": true
  }
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```


# Managing and Creating Users through API

Managing and Creating Users through API" provides developers with detailed instructions on how to create, update, and manage user accounts within a system using API endpoints.

User management is an essential feature of the Fungies.io platform, enabling developers to handle user accounts programmatically. The user-related endpoints allow you to create new users, retrieve user information, update user details, and manage user inventory. These endpoints are designed to simplify user account management by providing necessary features like listing users, modifying their details, and archiving accounts.

To access these endpoints, authentication via API keys is required, you can go through the "[Getting Started with the API](https://help.fungies.io/for-saas-developers/getting-started-with-the-api)" guide in which you will learn how you can generate the `API-key` and `write-API-key`.

After generating the `API-key` and `write-API key` you can immediately start making requests to the Fungies User management API endpoints.

## GET /users/list (List All Users)

The `/users/list` endpoint is used to retrieve a list of all users on the Fungies.io platform. It allows developers to access details of every user in the system, including filtering options based on user creation dates and email.

> **Note:** This endpoint requires an `API-key` for authentication.

This is a `GET` API endpoint that accepts the following parameters:

* **`email`**: Filters users by their email address.
* **`createdAfter`**: Returns users created after a specified date.
* **`createdBefore`**: Returns users created before a specified date.
* **`page`**: Specifies which page of the user list you want to retrieve.
* **`limit`**: Defines the maximum number of users to return per page.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": "<string>"
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

## POST /users/create (Create a New User)

The `/users/create` endpoint allows developers to create a new user in the system by providing the necessary information such as email, password, and username.

> **Note:** This endpoint requires an `API-key` and `write-API key` (both) for authentication at the same time.

This is a `POST` API endpoint that requires the following in the request body:

* **`email`**: The email address of the new user.
* **`password`**: The password for the user account.
* **`username`**: The username for the user.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": "<string>"
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

## **GET /users/{userId} (Get User by ID)**

The `/users/{userId}` endpoint is used to retrieve details of a specific user by their unique user ID.

> **Note:** This endpoint requires an `API-key` for authentication.

This is a `GET` API endpoint that requires a single parameter:

* **`userId`**: The unique ID of the user you want to retrieve.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": "<string>"
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

## **PATCH /users/{userId}/update (Update User Details)**

The `/users/{userId}/update` endpoint allows developers to update a user's details, such as their email or username.

> **Note:** This endpoint requires an `API-key` and `write-API key` (both) for authentication at the same time.

This is a `PATCH` API endpoint that requires a single parameter and request body:

* `userId`: The unique ID of the user to update.
* **Request Body**:

  `email`: The updated email address for the user.

  `username`: The updated username for the user.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": "<string>"
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

## **PATCH /users/{userId}/archive (Archive User)**

The `/users/{userId}/archive` endpoint is used to archive a specific user account, effectively deactivating it while preserving its data.

> **Note:** This endpoint requires an `API-key` and `write-API key` (both) for authentication at the same time.

This is a `PATCH` API endpoint that requires a single parameter and request body:

* **`userId`**: The unique ID of the user to archive.
* **`Request`` ``Body`**: An object specifying any additional data needed for archiving the user.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": "<string>"
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```

## **GET /users/{userId}/inventory (Get User Inventory)**

The `/users/{userId}/inventory` endpoint retrieves the inventory of digital products or subscriptions associated with a specific user.

> **Note:** This endpoint requires an `API-key` for authentication.

This is a `GET` API endpoint that requires the following parameters:

* **`userId`**: The unique ID of the user whose inventory you want to retrieve.
* **`productType`**: Filters inventory by the type of product. Available options-

  `DigitalDownload` ,`Game` ,`GiftCard` ,`SoftwareKey` ,`VirtualCurrency` ,`VirtualItem` ,`Subscription`.
* **`expiresAfter`**: Filters items that expire after a specific date.

**Successful Response:**

When the request is successful, you will receive a response like this:

```
{
  "status": "<string>",
  "data": "<string>"
}
```

**Error Response:**

If the request fails, you will receive an error response like this:

```
{
  "status": "error",
  "error": {
    "message": "Sample error message"
  }
}
```


# Customizing Subscription Confirmation Page

You can customize your Confirmation Page in the Overlay as well as in Hosted Checkout by going to Settings -> Store -> Checkout Summary tab, like below:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FGYr0lZLMyKpgmBMnesmm%2Fimage.png?alt=media&amp;token=91c7cd83-4554-4983-85e3-ff645441dd1c" alt=""><figcaption><p>Change the texts and settings of Confirmation Page here</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FyjjmSvFfEEo1fjTXHaBE%2Fimage.png?alt=media&amp;token=859ef5ee-9d14-4acb-8e1a-e3567c55d2c2" alt=""><figcaption><p>Fields that can be customized</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FgYzFnQgONAe5uHvdKKNn%2Fimage.png?alt=media&amp;token=a526a93c-8093-4f46-b096-1989c28e0cdf" alt=""><figcaption><p>3 areas where you can customize your Confirmation Page</p></figcaption></figure>

1. Title: this is the main title of the page
2. Subtitle: explain actions for the user
3. Button Text + URL: customize it however you like and paste the URL of your App/Software

Be careful with this one:&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FdDZyxcbJwReK80lo42Vq%2Fimage.png?alt=media&amp;token=4ef3b83e-c085-4af3-93ac-bca343f3f4cd" alt=""><figcaption><p>Redirecting to URL right after successful payment</p></figcaption></figure>

When you fill in anything here - the user will be instantly redirected to desired URL (without seeing Confirmation Page).


# Using CustomFields to parse data from your Software / App

This article is intended for developers who would want to redirect users from their application or software to a Hosted Checkout / Overlay Checkout - and recognize the User's ID.

## Custom Fields for Products, Subscriptions, and Overlays

Define Custom Fields for products, subscriptions, and overlays to add flexibility in handling custom metadata for each resource. This document provides instructions on configuring these Custom Fields effectively, including examples and screenshots for better understanding.

{% embed url="<https://youtu.be/c4lpVrI_lRw>" %}
Finding and editing CustomFields for your Subscription products
{% endembed %}

### Custom Fields Overview

Custom Fields allow you to add additional metadata to products, subscriptions, or overlays. This metadata can include internal IDs, customer notes, or any other information that helps streamline transaction management.

Custom Fields can be defined at both the project level and the individual product level. Product-level Custom Fields take precedence over project-level Custom Fields, allowing more specific data, such as a user's internal ID, to be passed throughout the transaction process and returned via webhook notifications.

#### Where to Use Custom Fields

* Products: Define Custom Fields for individual products in addition to existing project-level Custom Fields.
* Subscriptions: Use Custom Fields to manage subscription-specific information for users.
* Overlays: Add Custom Fields to overlays, which can be validated using regular expressions (regex) or a validation API.

### Redirecting Customers with Custom Fields (Hosted Checkout Example)

Attach Custom Fields as query parameters when redirecting customers to the platform for transactions. This allows custom data (e.g., a user ID) to be included in the checkout process and sent back via webhook upon completion.\
\
NOTE: All defined custom fields are required and must pass validation.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FnbUcj6ep8rWJFZv7vPmN%2Fimage.png?alt=media&amp;token=e4c2a915-87cf-4b5d-a248-bf232a4a1f1d" alt=""><figcaption><p>Custom Fields will be parsed from your app by URL parameter and be visible to the end-user</p></figcaption></figure>

#### Custom Field Validation Failure

If custom field validation fails during checkout, the user will be informed, and they will not be able to proceed further until the validation passes.

<br>

Example URL with Custom Fields:

<https://my-fungies-store.com/subscribe/9813eb2e-2305-4fa1-8096-9646bd8e63e8?user_id=sbs000001&server_name=sbs_europe>

This data will be included in the webhook payload, making it easy to track and manage transactions in your app.

### Embedding Overlays with Custom Fields

Custom Fields can be used when embedding overlays. These fields can be validated according to predefined rules using either regex validation or a custom validation API.

Process Overview:

1. Define Custom Fields and choose a validation method.
2. Add these fields when embedding an overlay.
3. The fields will be validated before the overlay is displayed, based on your configuration.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FTCcigyC5VsMgBAirAIz7%2Fimage.png?alt=media&amp;token=4581e95b-0b40-42c7-81dd-aa37b87d2878" alt=""><figcaption><p>Overlay button with parsed URL parameters for user_id</p></figcaption></figure>

### Receiving Custom Fields in Webhook Notifications

Upon transaction or subscription completion, the Custom Fields are sent to your server through webhook notifications. This allows for seamless integration of user tracking or other metadata without requiring extra lookups.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FHZJtrzJSv4NjLS3DT7Ij%2Fimage.png?alt=media&amp;token=f6392063-11dd-47e6-8dc8-e78515418240" alt=""><figcaption><p>Sample Webhook response with customFields parsed from your app</p></figcaption></figure>

Webhook Payload: This is an example of a webhook payload that demonstrates the structure of Custom Fields. It illustrates how data such as user IDs and server names can be passed through the transaction process and returned via the webhook for tracking and integration.

### Custom Fields Validation Options

When defining Custom Fields for products, subscriptions, or overlays, you have two main validation options:

* Regex Validation: Define a regular expression to ensure the data format is correct (e.g., a phone number or email address).
* Validation API: Provide an API endpoint to validate the customField values in real-time. You can also set a secret key to prevent unauthorized access to your validation API. Validation passes when the endpoint returns a code 200; any other code is recognized as a validation failure.

These options help you control the data being submitted, preventing invalid information from causing issues.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FH6jZ2PixkyfAGtTCgTb8%2Fimage.png?alt=media&amp;token=36aac917-7826-4ea6-b9df-3d14fca24096" alt=""><figcaption><p>Defining custom fields</p></figcaption></figure>

### Summary

* Custom Fields can now be defined for products, subscriptions, and overlays individually, in addition to project-level configurations. Product-level custom fields are prioritized over project-level custom fields.
* Attach Custom Fields as query parameters for user redirects involving transactions or embedded overlays.
* The Custom Fields are included in webhook responses for easy integration with your systems.
* Use regex or API validation to ensure the data integrity of Custom Fields.
* Remember the custom fields should be in JSON Format, like e.g.

```
data-fungies-custom-fields='{"user_id":"123"}'
```

### Next Steps

To configure Custom Fields, navigate to the product, subscription, or overlay settings and define the necessary fields. Ensure that appropriate validation rules are set up, and test webhook payloads to verify accuracy and completeness.

If you have any questions, check out our [developer documentation](https://docs.fungies.io/introduction) or reach out to our [support team](mailto:support@fungies.io) for assistance.

\
\ <br>


# Pre-fill fields (e-mail, discount) in checkout URL

### Custom Links for Hosted Checkout

#### Purpose

This feature allows to use custom links for the hosted checkout on their websites. It streamlines the checkout process by dynamically pre-filling user-specific details, such as the user’s email address and the quantity of the product being purchased. This is particularly beneficial for businesses selling subscriptions or products requiring customized inputs.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FCAaI0MF6kjzYQeW278Np%2Fimage.png?alt=media&amp;token=6e2a82a8-1fd7-4498-a68b-10726a9f8cdd" alt=""><figcaption><p>Hosted Checkout with pre-filled Customer E-mail + pre-filled Discount Code</p></figcaption></figure>

***

#### How It Works

You can add specific query parameters to the hosted checkout URL to dynamically pass values like:

* User Email: Pre-fills the email field for the end-user using the fngs-user-email parameter.
* Quantity: Pre-sets the quantity for the product using the fngs-quantity parameter.

Note: To use the fngs-quantity parameter for subscription offers, the Mutable Quantity feature must be enabled in the offer settings.

When the link with the query parameters is used to redirect a user to the hosted checkout page, these parameters are automatically applied, providing a tailored and seamless checkout experience.

***

#### Steps to Use

1. Construct the Custom Link:

Start with the base URL of the hosted checkout page:\
\
<https://example.com/checkout>

Add query parameters to the URL for dynamic values:

* fngs-user-email: The user's email address.
* fngs-quantity: The quantity of the product.
* fngs-discount-code: Discount code prefill.
* fngs-customer-country: The country of the customer (2-character country code) which will pre-fill the Country field with the country you set up here (e.g. \[your\_url]/checkout/\[trx\_id]?fngs-customer-country=US)
* Example:

<https://example.com/checkout?fngs-user-email=john.doe@example.com\\&fngs-quantity=3>

2. Enable Mutable Quantity (For Subscription Offers):\
   \
   If the offer involves subscriptions, ensure the Mutable Quantity feature is enabled in the offer settings. Without this setting, the fngs-quantity parameter will not be applied to subscription products.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfzayHwJ8SBkXGkaz6n0aXjxXerb6bTE6Wqb4qruRfupLLNjepZGSgxM9EKXPmncQvBuaKdBvqqi79J-DouxGAsbRAN5CIjYVvn6e136HiEEPsC_pXgpfshzj4CN30-yMe7IAPM?key=BrtvmpwdK3cgLr352VxlgHcl)

3. Redirect to the Link:

* Use the custom link in your website’s code to redirect users to the checkout page. Ensure the query parameters are correctly populated with dynamic values before redirection.

3. Verify the Checkout:\
   \
   The hosted checkout page will display:

* Prefilled Email: From the fngs-user-email parameter.
* Quantity: From the fngs-quantity parameter, if applicable.

![](https://lh7-rt.googleusercontent.com/docsz/AD_4nXezvGvUtNivwOltHlY2XlzC7ALIv3EAJQwSrE5xzJpTOnJjhJq1JTugEtFdsDailozuXpGHWscDC2x9E0LouoVffoJlYOd7mgKtul1V9xaJ-JBiZUTtCOet7aoczuPRm0sVceMpFg?key=BrtvmpwdK3cgLr352VxlgHcl)

<br>


# Additional charges on top of Subscriptions

You can charge customers on top of their monthly subscriptions. Think of this as a sort of Usage-Based Subscription where your API can instruct how much to charge the customer based on your own estimate of your software's usage like:

* Credits
* Data
* Storage
* API Calls

This charge will be added to an existing Subscription and will generate a separate invoice.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F2OncPH0qqfgCzcCf6ssv%2Fimage.png?alt=media&amp;token=6af08c5e-ad4e-4644-8a70-82620472406c" alt=""><figcaption><p>Example Subscription with a custom charge (overcharge) on top of existing Subscription</p></figcaption></figure>

You can charge on top of existing Subscription using this [API endpoint](https://api.app.fungies.io/v0/api-docs/#/subscriptions/PostV0SubscriptionsSubscriptionIdOrNumberCharge):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FwdT7ZUZaYcuuhoFYdDFX%2Fimage.png?alt=media&amp;token=3c341d53-dcc2-488a-8e1e-4adbb9cecf49" alt=""><figcaption><p>API endpoint to charge any amount on top of existing Subscription</p></figcaption></figure>

You can charge as many time you want:

```
"description": "Transaction description",
"items": [{
 "name": "overusage A",
 "value": 200,
},{
 "name": "overusage B",
 "value": 500,
}] 
```

In above example, the customer will be charged with $2 for Overusage A and $5 for Overusage B.

There will be:

* Additional invoices generated for each Overusage / Charge above current Subscription
* History of all charges for certain Subscription can be seen from the Dashboard in Subscription details of the customer.


# Upgrading or Downgrading Plans with API

### Introduction

This guide explains how to implement subscription upgrade and downgrade functionality in your SaaS application using Fungies as your Merchant of Record payment solution. We'll cover both dashboard-based management and API-based implementation, with a focus on integrating this functionality into your existing SaaS application.

### Prerequisites

Before implementing subscription upgrades and downgrades, ensure you have:

1. Created a subscription product in Fungies
2. Configured multiple plans with the same interval periods (days/weeks/months)
3. Generated API keys for programmatic access

### Dashboard-Based Subscription Management

#### Upgrading or Downgrading Subscriptions Manually

We provide a straightforward way to manage subscriptions through the Dashboard:

1. Log in to your Fungies Dashboard
2. Navigate to the Subscriptions section
3. Find the customer's subscription you want to modify
4. Click on "Manage subscription"
5. Select a different plan from the dropdown menu
6. Confirm the change

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FLg46TTuV8FYUTIle7JEw%2Fimage.png?alt=media&amp;token=904662bb-55c0-4322-89e6-8827e0d888a4" alt=""><figcaption><p>You can Upgrade/Downgrade customer subscription within the Dashboard</p></figcaption></figure>

When a subscription is upgraded or downgraded:

* Customers receive an email with updated terms
* If upgraded, they are charged a prorated amount for the difference
* If downgraded, the amount is deducted from their next invoice

#### Important Considerations

* Only plans with the same interval periods can be switched between (e.g., monthly to monthly)
* Proration is handled automatically by Fungies
* Changes take effect immediately or at the next billing cycle, depending on your configuration

### API-Based Subscription Management

For a seamless experience within your SaaS application, you can implement subscription upgrades and downgrades programmatically using the Fungies API.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FNv4wbJtswAtd7R1KRW2x%2Fimage.png?alt=media&amp;token=203def69-41cb-4ca3-ab49-86ea16cf7d1f" alt=""><figcaption><p>Upgrading or Downgrading customer Subscriptions can be done via API</p></figcaption></figure>

#### Update Subscription Endpoint

The key endpoint for managing subscription upgrades and downgrades is:

```
PATCH https://api.fungies.io/v0/subscriptions/{subscriptionIdOrNumber}/update
```

#### Required Headers

```
Content-Type: application/json
x-fngs-public-key: <your-public-api-key>
x-fngs-secret-key: <your-secret-api-key>
```

#### Request Body Parameters

```json
{
  "prorationBehavior": "none",
  "items": [
    {
      "name": "Premium Plan",
      "unitPrice": 10000,
      "currency": "USD",
      "quantity": 1,
      "offerId": "123e4567-e89b-12d3-a456-426614174000"
    }
  ]
}
```

Key parameters:

* **prorationBehavior**: Controls how proration is handled
  * `"none"`: No proration is calculated
  * `"create_prorations"`: Creates prorated credits or charges
  * `"always_invoice"`: Always generates an invoice for the proration
* **items**: Array containing the new subscription plan details
  * `name`: Display name of the plan
  * `unitPrice`: Price in smallest currency unit (e.g., cents)
  * `currency`: Three-letter currency code
  * `quantity`: Number of units
  * `offerId`: Unique identifier of the plan/offer to upgrade/downgrade to

#### Retrieving Subscription Information

Before updating a subscription, you may need to retrieve the current subscription details:

```
GET https://api.fungies.io/v0/subscriptions/{subscriptionId}
```

This endpoint returns detailed information about the subscription, including its current plan, billing cycle, and status.

#### Handling Responses

A successful update will return a 200 status code with the updated subscription details. Error responses (400) will include information about what went wrong, such as invalid parameters or authentication issues.


# Using Fungies.js npm package

The Fungies JavaScript SDK provides easy integration for Fungies checkout in your web applications.

It can be found [here](https://www.npmjs.com/package/@fungies/fungies-js).

### Installation

```
npm install @fungies/fungies-js
```

```
yarn add @fungies/fungies-js
```

```
pnpm add @fungies/fungies-js
```


# Next.js 15 integration guide

## Integrating Fungies with Next.js 15: A Concise Guide

### 1. Introduction

Fungies is a payment merchant of record platform designed specifically for SaaS developers. It offers a streamlined way to handle payments, subscriptions, and checkout experiences with key benefits including:

* No hidden fees pricing structure
* Beautiful checkout solutions (Overlay, Embedded, and Hosted options)
* Easy integration process
* No-code store builder for quick setup

This guide will walk you through integrating Fungies checkout into your Next.js 15 application. We'll use straightforward language and provide practical code examples that you can adapt to your own projects.

### 2. Getting Started with Fungies & Next.js

#### Prerequisites

Before beginning the integration process, ensure you have:

* **Next.js 15 Project**: Create one with `npx create-next-app@latest my-fungies-app`
  * Use TypeScript (recommended)
  * Use App Router (to leverage Next.js 15 features)
* **Fungies Account**:
  * Sign up at [Fungies.io](https://fungies.io/)
  * For testing, use the Sandbox environment: [https://app.stage.fungies.net](https://app.stage.fungies.net/)
  * Create a store in your dashboard
  * Set up at least one product or subscription
  * Note your API keys (public and secret)
  * Create a checkout element and note the checkout URL
* **Development Environment**:
  * Node.js 18.17 or later
  * npm, yarn, or pnpm package manager

#### Installation

Install the Fungies JavaScript SDK in your Next.js project:bash

```
# Using npm
npm install @fungies/fungies-js

# Using yarn
yarn add @fungies/fungies-js

# Using pnpm
pnpm add @fungies/fungies-js
```

#### Setup

1. **Environment Variables**

Create a `.env.local` file in your project root:

```
# .env.local
# For production
NEXT_PUBLIC_FUNGIES_PUBLIC_KEY=pub_your_public_key
FUNGIES_SECRET_KEY=sec_your_secret_key

# For sandbox testing (https://app.stage.fungies.net) 
NEXT_PUBLIC_FUNGIES_SANDBOX_PUBLIC_KEY=pub_your_sandbox_key
FUNGIES_SANDBOX_SECRET_KEY=sec_your_sandbox_key
NEXT_PUBLIC_FUNGIES_ENVIRONMENT=sandbox
```

2. **SDK Initialization**

Create a utility file to initialize the Fungies SDK (`lib/fungies.ts`):typescript

```
// lib/fungies.ts
import { Fungies } from '@fungies/fungies-js';

// Initialize Fungies on the client side only
export const initFungies = () => {
  if (typeof window !== 'undefined') {
    Fungies.Initialize({
      // Optional: Disable data attribute support if not needed
      // enableDataAttributes: false
    });
    
    return Fungies;
  }
  
  return null;
};

// Helper function to get the Fungies instance
export const getFungies = () => {
  if (typeof window !== 'undefined') {
    return Fungies;
  }
  
  return null;
};
```

This utility ensures Fungies is only initialized on the client side, preventing server-side rendering errors.

### 3. Implementing Fungies Checkout

#### Checkout Options Overview

Fungies offers three main checkout integration options:

1. **Overlay Checkout**: Displays in a modal overlay (simplest option)
2. **Embedded Checkout**: Displays directly within your page layout
3. **Hosted Checkout**: Redirects to a Fungies-hosted checkout page

We'll focus on implementing the Overlay and Embedded options as they provide the best balance of ease and user experience.

#### Overlay Checkout Implementation

Create a client component for the overlay checkout (`components/OverlayCheckoutButton.tsx`):typescript

```
'use client';

import { useEffect } from 'react';
import { initFungies, getFungies } from '@/lib/fungies';

interface OverlayCheckoutButtonProps {
  checkoutUrl: string;
  buttonText?: string;
  customerEmail?: string;
  discountCode?: string;
  quantity?: number;
  customFields?: Record<string, string>;
  onCheckoutComplete?: () => void;
  onCheckoutClose?: () => void;
}

export default function OverlayCheckoutButton({
  checkoutUrl,
  buttonText = 'Buy Now',
  customerEmail,
  discountCode,
  quantity,
  customFields,
  onCheckoutComplete,
  onCheckoutClose
}: OverlayCheckoutButtonProps) {
  useEffect(() => {
    // Initialize Fungies when the component mounts
    const Fungies = initFungies();
    
    if (Fungies) {
      // Set up event listeners
      const handleComplete = () => {
        console.log('Checkout completed!');
        onCheckoutComplete?.();
      };
      
      const handleClose = () => {
        console.log('Checkout closed!');
        onCheckoutClose?.();
      };
      
      // Add event listeners
      document.addEventListener('fungies:checkout:complete', handleComplete);
      document.addEventListener('fungies:checkout:close', handleClose);
      
      // Clean up event listeners on unmount
      return () => {
        document.removeEventListener('fungies:checkout:complete', handleComplete);
        document.removeEventListener('fungies:checkout:close', handleClose);
      };
    }
  }, [onCheckoutComplete, onCheckoutClose]);
  
  const handleCheckout = () => {
    const Fungies = getFungies();
    if (!Fungies) return;
    
    Fungies.Checkout.open({
      checkoutUrl,
      settings: {
        mode: 'overlay',
      },
      ...(customerEmail && { customerEmail }),
      ...(discountCode && { discountCode }),
      ...(quantity && { quantity }),
      ...(customFields && { customFields })
    });
  };
  
  return (
    <button 
      onClick={handleCheckout}
      className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
    >
      {buttonText}
    </button>
  );
}
```

Use this component in any page:tsx

```
// app/products/[id]/page.tsx
import OverlayCheckoutButton from '@/components/OverlayCheckoutButton';

export default function ProductPage() {
  const checkoutUrl = 'https://your-store.fungies.io/checkout-element/your-checkout-id';
  
  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-4">Product Name</h1>
      <p className="mb-6">Product description goes here...</p>
      <div className="flex items-center justify-between">
        <span className="text-2xl font-semibold">$29.99</span>
        <OverlayCheckoutButton 
          checkoutUrl={checkoutUrl}
          onCheckoutComplete={()  => {
            // Redirect or show success message
            console.log('Purchase completed!');
          }}
        />
      </div>
    </div>
  );
}
```

#### Embedded Checkout Implementation

Create a container component for the embedded checkout (`components/EmbeddedCheckout.tsx`):typescript

```
'use client';

import { useEffect, useRef } from 'react';
import { initFungies, getFungies } from '@/lib/fungies';

interface EmbeddedCheckoutProps {
  checkoutUrl: string;
  containerClassName?: string;
  customerEmail?: string;
  discountCode?: string;
  quantity?: number;
  customFields?: Record<string, string>;
  onCheckoutComplete?: () => void;
  onCheckoutClose?: () => void;
}

export default function EmbeddedCheckout({
  checkoutUrl,
  containerClassName = 'w-full min-h-[600px] border rounded',
  customerEmail,
  discountCode,
  quantity,
  customFields,
  onCheckoutComplete,
  onCheckoutClose
}: EmbeddedCheckoutProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const containerId = 'fungies-embedded-checkout';
  
  useEffect(() => {
    // Initialize Fungies when the component mounts
    const Fungies = initFungies();
    
    if (Fungies && containerRef.current) {
      // Set up event listeners
      const handleComplete = () => {
        console.log('Checkout completed!');
        onCheckoutComplete?.();
      };
      
      const handleClose = () => {
        console.log('Checkout closed!');
        onCheckoutClose?.();
      };
      
      // Add event listeners
      document.addEventListener('fungies:checkout:complete', handleComplete);
      document.addEventListener('fungies:checkout:close', handleClose);
      
      // Open the checkout in embedded mode
      Fungies.Checkout.open({
        checkoutUrl,
        settings: {
          mode: 'embed',
          frameTarget: containerId,
        },
        ...(customerEmail && { customerEmail }),
        ...(discountCode && { discountCode }),
        ...(quantity && { quantity }),
        ...(customFields && { customFields })
      });
      
      // Clean up event listeners and checkout on unmount
      return () => {
        document.removeEventListener('fungies:checkout:complete', handleComplete);
        document.removeEventListener('fungies:checkout:close', handleClose);
        Fungies.Checkout.close();
      };
    }
  }, [checkoutUrl, customerEmail, discountCode, quantity, customFields, onCheckoutComplete, onCheckoutClose]);
  
  return (
    <div 
      id={containerId}
      ref={containerRef}
      className={containerClassName}
    />
  );
}
```

Use the embedded checkout in your pages:tsx

```
// app/checkout/page.tsx
import EmbeddedCheckout from '@/components/EmbeddedCheckout';

export default function CheckoutPage() {
  const checkoutUrl = 'https://your-store.fungies.io/checkout-element/your-checkout-id';
  
  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-6">Checkout</h1>
      <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
        <div>
          <h2 className="text-xl font-semibold mb-4">Order Summary</h2>
          <div className="border rounded p-4 mb-4">
            <p className="font-medium">Premium SaaS Subscription</p>
            <p className="text-gray-600">$29.99/month</p>
          </div>
        </div>
        <div>
          <h2 className="text-xl font-semibold mb-4">Payment Details</h2>
          <EmbeddedCheckout 
            checkoutUrl={checkoutUrl}
            containerClassName="w-full min-h-[600px] border rounded-lg shadow-md bg-white"
            onCheckoutComplete={()  => {
              // Redirect to success page
              window.location.href = '/checkout/success';
            }}
          />
        </div>
      </div>
    </div>
  );
}
```

### 4. Handling Payments & Events

#### Working with Checkout Data

Fungies provides several options for customizing the checkout experience:

**Pre-filling Customer Information**

typescript

```
Fungies.Checkout.open({
  checkoutUrl,
  settings: { mode: 'overlay' },
  customerEmail: 'customer@example.com',
  customFields: {
    firstName: 'John',
    lastName: 'Doe'
  }
});
```

**Applying Discount Codes**

typescript

```
Fungies.Checkout.open({
  checkoutUrl,
  settings: { mode: 'overlay' },
  discountCode: 'WELCOME10'
});
```

**Setting Quantities**

typescript

```
Fungies.Checkout.open({
  checkoutUrl,
  settings: { mode: 'overlay' },
  quantity: 2
});
```

#### Webhook Integration

Webhooks allow your application to receive real-time notifications about events in your Fungies account.Create an API route to handle webhook events:typescript

```
// app/api/webhooks/fungies/route.ts
import { NextRequest, NextResponse } from 'next/server';
import crypto from 'crypto';

// This should be stored in your environment variables
const webhookSecret = process.env.FUNGIES_WEBHOOK_SECRET;

export async function POST(request: NextRequest) {
  try {
    // Get the signature from the headers
    const signature = request.headers.get('x-fngs-signature');
    
    if (!signature || !webhookSecret) {
      return NextResponse.json(
        { error: 'Missing signature or webhook secret' },
        { status: 401 }
      );
    }
    
    // Get the raw request body
    const rawBody = await request.text();
    
    // Verify the signature
    const hmac = crypto.createHmac('sha256', webhookSecret);
    const digest = hmac.update(rawBody).digest('hex');
    
    if (digest !== signature) {
      return NextResponse.json(
        { error: 'Invalid signature' },
        { status: 401 }
      );
    }
    
    // Parse the webhook payload
    const event = JSON.parse(rawBody);
    
    // Handle different event types
    switch (event.type) {
      case 'payment_success':
        await handlePaymentSuccess(event);
        break;
      case 'subscription_created':
        await handleSubscriptionCreated(event);
        break;
      case 'subscription_cancelled':
        await handleSubscriptionCancelled(event);
        break;
      // Add more event handlers as needed
      default:
        console.log(`Unhandled event type: ${event.type}`);
    }
    
    // Return a 200 response to acknowledge receipt of the webhook
    return NextResponse.json({ received: true });
  } catch (error) {
    console.error('Webhook error:', error);
    return NextResponse.json(
      { error: 'Webhook processing failed' },
      { status: 500 }
    );
  }
}

// Example event handlers
async function handlePaymentSuccess(event: any) {
  // Update your database, send confirmation emails, etc.
  console.log('Payment successful:', event.data.id);
}

async function handleSubscriptionCreated(event: any) {
  // Provision access to your service, update user status, etc.
  console.log('Subscription created:', event.data.id);
}

async function handleSubscriptionCancelled(event: any) {
  // Update user status, send retention emails, etc.
  console.log('Subscription cancelled:', event.data.id);
}
```

**Security Considerations for Webhooks**

1. **Always verify signatures** using the webhook secret
2. **Store secrets in environment variables**, never hardcode them
3. **Design webhook handlers to be idempotent** as Fungies may retry webhook deliveries
4. **Catch and log errors** but still return a 200 status to acknowledge receipt
5. **Keep webhook processing quick** or move long-running tasks to a background job

### 5. Integrating with Next.js 15 Features

#### Server vs. Client Components

Next.js 15 uses React's Server Components by default, but Fungies SDK requires client-side JavaScript.**Server Components** are great for:

* Fetching data from your backend or APIs
* Accessing environment variables securely
* Rendering static content

**Client Components** are necessary for:

* Interacting with the Fungies SDK
* Handling user interactions like button clicks
* Managing local state

Here's a pattern for combining both:tsx

```
// app/products/[id]/page.tsx (Server Component)
import { Suspense } from 'react';
import ProductDetails from './ProductDetails';
import CheckoutSection from './CheckoutSection';
import { getProductById } from '@/lib/products';

export default async function ProductPage({ params }: { params: { id: string } }) {
  // Fetch product data on the server
  const product = await getProductById(params.id);
  
  return (
    <div className="max-w-6xl mx-auto p-6">
      <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
        <Suspense fallback={<div>Loading product details...</div>}>
          {/* Server Component for product details */}
          <ProductDetails product={product} />
        </Suspense>
        
        <Suspense fallback={<div>Loading checkout options...</div>}>
          {/* Client Component for Fungies integration */}
          <CheckoutSection 
            productId={product.id}
            price={product.price}
            checkoutUrl={product.checkoutUrl}
          />
        </Suspense>
      </div>
    </div>
  );
}
```

tsx

```
// app/products/[id]/CheckoutSection.tsx (Client Component)
'use client';

import { useState, useEffect } from 'react';
import { initFungies, getFungies } from '@/lib/fungies';

export default function CheckoutSection({
  productId,
  price,
  checkoutUrl
}) {
  // Client-side code for Fungies integration
  // ...
}
```

#### Server Actions

Next.js 15 includes Server Actions, which allow you to run server-side code from client components. This is perfect for operations that require your secret API key.typescript

```
// app/actions/checkout.ts
'use server';

// This function runs on the server and can access environment variables securely
export async function createCheckoutSession(formData: FormData) {
  const productId = formData.get('productId') as string;
  const quantity = parseInt(formData.get('quantity') as string, 10);
  
  if (!productId || isNaN(quantity)) {
    throw new Error('Invalid product or quantity');
  }
  
  try {
    // Use your secret API key securely on the server
    const apiKey = process.env.FUNGIES_SECRET_KEY;
    
    // Make API request to Fungies to create a checkout session
    const response = await fetch('https://api.fungies.io/v0/checkout-sessions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-fngs-public-key': process.env.NEXT_PUBLIC_FUNGIES_PUBLIC_KEY!,
        'x-fngs-secret-key': apiKey!,
      },
      body: JSON.stringify({
        productId,
        quantity,
        successUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/checkout/success`,
        cancelUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/checkout/cancel`,
      }) ,
    });
    
    if (!response.ok) {
      throw new Error('Failed to create checkout session');
    }
    
    const data = await response.json();
    return { checkoutUrl: data.url };
  } catch (error) {
    console.error('Error creating checkout session:', error);
    throw new Error('Failed to create checkout session');
  }
}
```

Use this Server Action in a client component:tsx

```
// app/products/[id]/CheckoutForm.tsx
'use client';

import { useEffect, useState } from 'react';
import { createCheckoutSession } from '@/app/actions/checkout';
import { initFungies, getFungies } from '@/lib/fungies';

export default function CheckoutForm({ productId }: { productId: string }) {
  const [quantity, setQuantity] = useState(1);
  const [isLoading, setIsLoading] = useState(false);
  
  useEffect(() => {
    initFungies();
  }, []);
  
  async function handleSubmit(formData: FormData) {
    setIsLoading(true);
    
    try {
      // Call the server action
      const result = await createCheckoutSession(formData);
      
      // Open the checkout using the returned URL
      const Fungies = getFungies();
      if (Fungies && result.checkoutUrl) {
        Fungies.Checkout.open({
          checkoutUrl: result.checkoutUrl,
          settings: { mode: 'overlay' },
        });
      }
    } catch (err) {
      console.error(err);
    } finally {
      setIsLoading(false);
    }
  }
  
  return (
    <form action={handleSubmit} className="space-y-4">
      <input type="hidden" name="productId" value={productId} />
      
      <div>
        <label htmlFor="quantity" className="block text-sm font-medium text-gray-700 mb-1">
          Quantity
        </label>
        <select
          id="quantity"
          name="quantity"
          value={quantity}
          onChange={(e) => setQuantity(parseInt(e.target.value, 10))}
          className="w-full px-3 py-2 border border-gray-300 rounded-md"
        >
          {[1, 2, 3, 4, 5].map((num) => (
            <option key={num} value={num}>{num}</option>
          ))}
        </select>
      </div>
      
      <button
        type="submit"
        disabled={isLoading}
        className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
      >
        {isLoading ? 'Processing...' : 'Proceed to Checkout'}
      </button>
    </form>
  );
}
```

#### Performance Tips

**Lazy Loading Checkout Components**

Use Next.js dynamic imports to lazy load checkout components:typescript

```
// components/LazyCheckoutButton.tsx
import dynamic from 'next/dynamic';

// Dynamically import the checkout component
const CheckoutButton = dynamic(
  () => import('@/components/OverlayCheckoutButton'),
  {
    loading: () => <button className="px-4 py-2 bg-gray-300 text-gray-700 rounded">
      Loading...
    </button>,
    ssr: false, // Disable server-side rendering
  }
);

export default function LazyCheckoutButton(props) {
  return <CheckoutButton {...props} />;
}
```

**Optimizing Webhook Processing**

For long-running webhook tasks, use a background process:typescript

```
// app/api/webhooks/fungies/route.ts
export async function POST(request: NextRequest) {
  try {
    // Verify the webhook (code omitted for brevity)
    
    // Get the event data
    const event = await request.json();
    
    // For long-running tasks, use a background process
    await enqueueWebhookProcessing(event);
    
    // Return a 200 response immediately
    return NextResponse.json({ received: true });
  } catch (error) {
    console.error('Webhook error:', error);
    return NextResponse.json(
      { error: 'Webhook processing failed' },
      { status: 500 }
    );
  }
}

// Function to enqueue webhook processing
async function enqueueWebhookProcessing(event: any) {
  // This could be a message queue, database insert, etc.
  console.log('Enqueueing webhook processing for event:', event.id);
}
```

### 6. Testing & Deployment

#### Testing with Fungies Sandbox

Fungies provides a Sandbox environment for testing:

* **Sandbox App URL**: [https://app.stage.fungies.net](https://app.stage.fungies.net/)
* **Sandbox API Docs**: <https://api.stage.fungies.net/v0/api-docs/>

Set up environment variables to switch between environments:typescript

```
// lib/fungies-config.ts
export const FUNGIES_ENVIRONMENTS = {
  sandbox: {
    apiBase: 'https://api.stage.fungies.net/v0',
    checkoutBase: 'https://checkout.stage.fungies.net',
    publicKey: process.env.NEXT_PUBLIC_FUNGIES_SANDBOX_PUBLIC_KEY,
    secretKey: process.env.FUNGIES_SANDBOX_SECRET_KEY,
  },
  production: {
    apiBase: 'https://api.fungies.io/v0',
    checkoutBase: 'https://checkout.fungies.io',
    publicKey: process.env.NEXT_PUBLIC_FUNGIES_PRODUCTION_PUBLIC_KEY,
    secretKey: process.env.FUNGIES_PRODUCTION_SECRET_KEY,
  },
};

export const getFungiesConfig = ()  => {
  const environment = process.env.NEXT_PUBLIC_FUNGIES_ENVIRONMENT || 
                     (process.env.NODE_ENV === 'production' ? 'production' : 'sandbox');
  
  return FUNGIES_ENVIRONMENTS[environment as keyof typeof FUNGIES_ENVIRONMENTS];
};
```

Use this configuration in your API calls:typescript

```
// Example server action using the environment config
export async function createCheckoutSession(formData: FormData) {
  const config = getFungiesConfig();
  
  // This will use https://api.stage.fungies.net/v0/checkout-sessions in sandbox mode
  // or https://api.fungies.io/v0/checkout-sessions in production
  const response = await fetch(`${config.apiBase}/checkout-sessions`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-fngs-public-key': config.publicKey!,
      'x-fngs-secret-key': config.secretKey!,
    },
    // ...
  }) ;
  
  // ...
}
```

#### Debugging Common Issues

**SDK Not Loading**

typescript

```
// Debug helper to check if SDK is loaded
export const debugFungiesSDK = () => {
  if (typeof window === 'undefined') {
    console.log('Running on server - Fungies SDK not available');
    return false;
  }
  
  if (typeof Fungies === 'undefined') {
    console.error('Fungies SDK not loaded correctly');
    return false;
  }
  
  console.log('Fungies SDK loaded successfully');
  return true;
};
```

**Webhook Verification Issues**

typescript

```
// app/api/webhooks/fungies/debug/route.ts
export async function POST(request: NextRequest) {
  try {
    // Get the signature from the headers
    const signature = request.headers.get('x-fngs-signature');
    const webhookSecret = process.env.FUNGIES_WEBHOOK_SECRET;
    
    console.log('Received webhook with signature:', signature);
    console.log('Using webhook secret (first 4 chars):', webhookSecret?.substring(0, 4));
    
    // Get the raw request body
    const rawBody = await request.text();
    
    // Verify the signature
    const hmac = crypto.createHmac('sha256', webhookSecret || '');
    const digest = hmac.update(rawBody).digest('hex');
    
    console.log('Calculated signature:', digest);
    console.log('Signatures match:', digest === signature);
    
    // Return debug info (only in development!)
    if (process.env.NODE_ENV === 'development') {
      return NextResponse.json({
        received: true,
        signatureProvided: signature,
        signatureCalculated: digest,
        match: digest === signature,
      });
    }
    
    return NextResponse.json({ received: true });
  } catch (error) {
    console.error('Webhook debug error:', error);
    return NextResponse.json(
      { error: 'Webhook processing failed' },
      { status: 500 }
    );
  }
}
```

#### Deployment

**Environment Variables in Production**

For Vercel deployments, add these environment variables in the Vercel dashboard:

```
NEXT_PUBLIC_FUNGIES_ENVIRONMENT=production
NEXT_PUBLIC_FUNGIES_PRODUCTION_PUBLIC_KEY=pub_your_production_key
FUNGIES_PRODUCTION_SECRET_KEY=sec_your_production_key
FUNGIES_WEBHOOK_SECRET=your_webhook_secret
NEXT_PUBLIC_BASE_URL=https://your-production-domain.com
```

**Security Best Practices**

1. **Never expose your secret API key in client-side code**
2. **Add security headers to your webhook endpoints**
3. **Validate user input before sending it to Fungies**
4. **Use Server Actions for operations requiring the secret key**

### 7. Conclusion

In this guide, we've covered how to integrate Fungies checkout into your Next.js 15 application. We've explored:

1. Setting up the Fungies SDK in a Next.js environment
2. Implementing both Overlay and Embedded checkout options
3. Working with checkout data and customization
4. Setting up webhooks to handle payment events
5. Leveraging Next.js 15 features like Server Components and Server Actions
6. Testing with the Fungies Sandbox environment
7. Deploying your integration to production

For more information, refer to:

* [Fungies Documentation](https://docs.fungies.io/)
* [Fungies API Documentation](https://api.fungies.io/v0/api-docs/)
* [Fungies Sandbox API Documentation](https://api.stage.fungies.net/v0/api-docs/)
* [Next.js Documentation](https://nextjs.org/docs)

For support, contact <support@fungies.io> or join the Fungies community forums.


# Orders

Under the "Order" tab you'll see all transactions that were completed on your marketplace. The table displays essential details about the order.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FRY3KRuUS1vGpfXN3UhAu%2Fimage.png?alt=media&amp;token=6c715206-f855-4013-b7e2-9230d4881b2e" alt=""><figcaption><p>A list of all orders from your Web Store</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F520014yyKoTwzryY9pb1%2Fimage.png?alt=media&amp;token=fb743bbe-4baa-45d0-ba19-46343cfc8cdb" alt=""><figcaption><p>Clicking on an Order will redirect you to its details, such as User's e-mail and Fungies Fee (5%+50 cents commission)</p></figcaption></figure>

In the list of orders you can see all necessary data:

* Order Number
* Buyer's e-mail
* Transaction status: Completed, Pending or Failed
* Value of the Order
* Fungies Commission
* Tax Amount
* Date of the Transaction


# Platform Fees

In this section we'll describe Fungies Business Model and how we charge you - Game Developers

Below you'll find our Pricing details. Check it on our [website](https://fungies.io/pricing/):&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FaKbV0lkzoZ8l5t9bDoTr%2Fimage.png?alt=media&amp;token=8efe3e1e-6f77-4b47-83b8-504ba0d7f205" alt=""><figcaption><p>Simple pricing - we only take 5% + $0.5 per transaction</p></figcaption></figure>

How does it work?

We use something called Stripe Connect which is intended for Marketplaces like Uber or AirBnB - where there's one Master Merchant account - that's Fungies, and many Sub-Merchant accounts - like Game Developers. More information about Stripe Connect can be found [here](https://stripe.com/en-pl/connect).

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FvXVle4HMPkorQKL9beym%2Fimage.png?alt=media&amp;token=fbcf074c-17a6-48a7-926d-a8a5b7021ccb" alt=""><figcaption><p>The money flow for Connected Accounts (Stripe Express) - you own the Connected Account</p></figcaption></figure>

1. The customer pays to our Stripe account using 400+ paymen methods available globally
2. We receive the amount and then it's redirected instantly to your Stripe Sub-Merchant account
3. We deduct our Platform Fee which is 5%+$0.5 per every transaction that's occured on your Web Store
4. We pay Stripe fees
5. You receive the net amount
6. Taxes are colleced, calculated and reported by us - you receive Net Revenue


# Users list

To see all registered users go to Users list. You can export it if needed!&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fu8cqTSFGRKb7iyAsYZrB%2Fimage.png?alt=media&amp;token=40558b6d-98f6-4abb-ad02-75f491d4e6a7" alt=""><figcaption><p>Under Users tab you'll see all the customers that have registered in your Web Store</p></figcaption></figure>

The Newsletter column indicates if the User has agreed to receive Marketing materials from your Web Store like E-mail Newsletters or SMS'es.

In the Joined column you'll see the date of registration.


# Integrating with Game's Back-end

Please head over to [Webhooks](/for-game-developers/webhooks) for more information on how to integrate your Mobile Game's back-end with your Web Store.

Webhooks in the Dashboard can be found [here](https://app.fungies.io/settings/webhooks).

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FGt2k70Qk28zEB5MdNkr0%2Fimage.png?alt=media&amp;token=41cde904-524b-4f68-94da-5aa2ab9d1526" alt=""><figcaption><p>You can send Webhook data to your game's back-end in order to reward the Player with items bought in the Web Store</p></figcaption></figure>

Remember, you can sell:

* Game Keys
* In-App Purchases (In-Game Assets)
* Anything that you offer in-game

On your own branded Web Store.


# Customizing Purchase Confirmation Page

If you want to customize your Confirmation Page after the user has purchased your Game Key, simply head to Settings -> Store -> Checkout Summary tab, just like below:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FU7JQzIPxFI9wUQGk7GCT%2Fimage.png?alt=media&amp;token=a081cf3b-3eac-4048-80ce-7478431e4dbf" alt=""><figcaption><p>Customize your confirmation page for the customer</p></figcaption></figure>

1. You can change the Link Text + URL - this can be e.g. your Refund Policy page
2. Change Warning Text that appears next to the "i" icon
3. Change the Checkbox text
4. Edit the button after revealing game code or key (Button Text + URL)

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FhmWgQWq3UbRpEpGQwHGz%2Fimage.png?alt=media&amp;token=1199bd2c-ea64-4812-9137-7b8640c52583" alt=""><figcaption><p>Edit Warning Text, Link URL next to it and also Checkbox text</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FrXhQhaqsJpRI206CPyX7%2Fimage.png?alt=media&amp;token=55b827f9-5855-4c98-bfda-92e27cea92f1" alt=""><figcaption><p>You can also edit the button after user has confirmed checbkox</p></figcaption></figure>


# Webhooks

If you have IAP in your Mobile or PC game - you can send purchase information from the Web Store to your game's backend via Webhooks.

In order for your game to recognize a successful Web Store transaction, data will be sent to your game's backend via [Webhooks](https://app.fungies.io/settings/webhooks):

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FmLrfFAUZvmTRPMFeBZp7%2Fimage.png?alt=media&amp;token=f1bcb9bb-a5a1-4f52-9020-485216ce88d6" alt=""><figcaption><p>Access Webhooks in your <a href="https://app.fungies.io/settings/webhooks">Dashboard</a></p></figcaption></figure>

More detailed information on technical implementation of Webhooks can be found in our [documentation](https://docs.fungies.io/).


# SaaS Developers with Subscription Products

## Fungies for SaaS — Subscriptions, Custom Fields, Webhooks & Customer Portal

> A complete walk-through for adding subscription billing, app-specific metadata capture, real-time event handling, and self-serve subscription management to any SaaS, using **Fungies** as the merchant-of-record and **Stripe** under the hood.

***

### What you'll build

A Next.js (App Router) SaaS that:

1. Sells a **monthly subscription** plan from a hosted Fungies checkout.
2. Captures a **custom field** (e.g. `playerId`, `tenantSlug`, `seat_count`) at checkout so each subscription is tied to the right account in your DB.
3. Listens to **webhooks** to provision access on `payment_success`, renew on `subscription_interval`, and revoke on `subscription_cancelled` / `payment_refunded`.
4. Deep-links users to **Fungies' hosted Customer Portal** so they can update their card, change plans, and cancel without you building a billing UI.

Total reading time: \~25 min. Total integration time: a focused afternoon.

***

### Prerequisites

| Need                                                                                        | Where                       |
| ------------------------------------------------------------------------------------------- | --------------------------- |
| Fungies workspace + Subscription product with at least one recurring offer                  | help-center/getting-started |
| Stripe Connect linked to your Fungies workspace                                             | help-center/stripe-connect  |
| Public HTTPS URL for webhooks (use `ngrok http 3000` in dev)                                | ngrok or Cloudflare Tunnel  |
| Node 20+ and a Next.js 15 app (or any Node server — examples are framework-agnostic enough) | —                           |

Set these env vars in `.env.local`:

```bash
FUNGIES_PUBLIC_KEY=pub_...
FUNGIES_SECRET_KEY=sec_...
FUNGIES_WEBHOOK_SECRET=whsec_...           # set when you register the webhook
FUNGIES_STORE_URL=https://yourstore.com/   # e.g. azzeki.com — your custom domain or *.app.fungies.io
FUNGIES_API_BASE=https://api.fungies.io
```

> **Auth note (verified live):** every API call requires BOTH `x-fngs-public-key` AND `x-fngs-secret-key` headers, even for `GET` calls. Missing either → `401 "API key is invalid"`. Special chars (`+`, `=`, `/`) in keys are sent verbatim — no URL encoding.

***

### Step 1 — Define your subscription product

In the Fungies dashboard:

1. **Products → Add product → type: Subscription**.
2. Add an **Offer** with `recurringInterval: month`, `recurringIntervalCount: 1`, your price (e.g. `999` cents = €9.99) and currency.
3. Optionally set a `trialInterval` for free trials.

Verify it from the API:

```bash
curl https://api.fungies.io/v0/products/list \
  -H "x-fngs-public-key: $FUNGIES_PUBLIC_KEY" \
  -H "x-fngs-secret-key: $FUNGIES_SECRET_KEY"
```

> **Empirical gotcha:** `GET /v0/products` (no `/list` suffix) returns `404 "Can not GET /v0/products"`. Always use `/list`. Same applies to `/v0/offers/list`, `/v0/orders/list`, `/v0/payments/list`, `/v0/discounts/list`, `/v0/elements/checkout/list`.

Then grab the offer details:

```bash
curl "https://api.fungies.io/v0/offers/list?take=10" \
  -H "x-fngs-public-key: $FUNGIES_PUBLIC_KEY" \
  -H "x-fngs-secret-key: $FUNGIES_SECRET_KEY"
```

You'll get something like:

```json
{
  "object": "offer",
  "id": "4cab6ea0-7ba5-42eb-bded-128c08a93c8f",
  "price": 999,
  "currency": "EUR",
  "recurringInterval": "month",
  "recurringIntervalCount": 1,
  "trialInterval": null,
  "status": "OPEN"
}
```

> `price: 999` is in the **smallest currency unit** (€9.99). Don't divide on the way in.

Save that offer UUID — you'll use it everywhere.

***

### Step 2 — Add a custom field for app metadata

This is how you bind a Fungies order to a record in your DB.

In the dashboard: **Products → Project → Custom Fields → Add field**.

Example for a game-style SaaS:

```
Label:       Player ID
Placeholder: Enter your in-game player ID
Regex:       ^[a-zA-Z0-9_]{3,32}$
```

For a multi-tenant B2B SaaS use `tenantSlug` or `workspace_id`.

> **CRITICAL gotcha (verified live):** custom fields have **two** identifiers:
>
> * A **string key** (the label slug) used by the JS SDK.
> * A **UUID** used by the Checkout Elements API.
>
> The UUID is only visible in the dashboard. **Pre-filling with an unknown id silently succeeds (200 OK) but the value is dropped — nothing renders on checkout, nothing comes back in webhooks.** You will spend a sad afternoon debugging this if you don't read this paragraph twice.

Find the UUID by visiting the field in the dashboard URL bar, or by inspecting the rendered checkout DOM after creation.

***

### Step 3 — Open the checkout from your app

You have two production-grade options. Pick one.

#### Path A — JS SDK overlay (recommended for SaaS signup flows)

`app/(marketing)/pricing/CheckoutButton.tsx`:

```tsx
"use client";
import { useEffect } from "react";

declare global {
  interface Window { Fungies: any; }
}

export function CheckoutButton({ offerId, user }: {
  offerId: string;
  user: { id: string; email: string };
}) {
  useEffect(() => {
    if (!document.getElementById("fungies-sdk")) {
      const s = document.createElement("script");
      s.id = "fungies-sdk";
      s.src = "https://cdn.jsdelivr.net/npm/@fungies/fungies-js@latest";
      s.defer = true;
      document.body.appendChild(s);
    }
  }, []);

  const onClick = () => {
    window.Fungies.Checkout.open({
      checkoutUrl: `${process.env.NEXT_PUBLIC_FUNGIES_STORE_URL}checkout/${offerId}`,
      settings: { mode: "overlay" },
      billingData: { email: user.email },
      customFields: { playerId: user.id },   // ← string key, set in dashboard
    });
  };

  return (
    <button
      onClick={onClick}
      className="rounded-md bg-black px-4 py-2 text-white hover:bg-zinc-800 active:scale-[0.98] transition"
    >
      Subscribe
    </button>
  );
}
```

That's it. The SDK opens the hosted checkout in an overlay, the customer pays, your webhook fires.

#### Path B — Server-minted Checkout Element

Use this when you want a **stable shareable URL** (email blast, in-app link) that already has the custom field baked in.

`app/api/checkout/route.ts`:

```ts
import { NextResponse } from "next/server";

export async function POST(req: Request) {
  const { offerId, playerId } = await req.json();

  const r = await fetch(`${process.env.FUNGIES_API_BASE}/v0/elements/checkout/create`, {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "x-fngs-public-key": process.env.FUNGIES_PUBLIC_KEY!,
      "x-fngs-secret-key": process.env.FUNGIES_SECRET_KEY!,
    },
    body: JSON.stringify({
      name: `signup_${playerId}_${Date.now()}`,
      offersIds: [offerId],
      customFields: [
        { id: process.env.FUNGIES_CF_PLAYER_ID_UUID!, value: playerId }, // ← UUID, not string key
      ],
    }),
  });

  const json = await r.json();
  const elementId = json.data.checkoutElement.id;
  return NextResponse.json({
    url: `${process.env.FUNGIES_STORE_URL}checkout-element/${elementId}`,
  });
}
```

> **Two important caveats (verified live):**
>
> 1. There is **no archive/delete endpoint** for elements — every one you mint persists forever in `/v0/elements/checkout/list`. Mint per-user (or per-tenant) and reuse, not per-click.
> 2. `GET /v0/elements/checkout/{id}` returns **404**. Store the id when you create it.

***

### Step 4 — Receive and verify webhooks

In **Developers → Webhooks**, add an endpoint pointing to `https://yourapp.com/api/fungies/webhook` and subscribe to:

* `payment_success`
* `payment_refunded` ← canonical name (the docs occasionally show `payment_refund` — that's a typo)
* `payment_failed`
* `subscription_created`
* `subscription_interval`
* `subscription_updated`
* `subscription_cancelled`

Copy the secret it generates into `FUNGIES_WEBHOOK_SECRET`.

`app/api/fungies/webhook/route.ts`:

```ts
import crypto from "node:crypto";
import { NextResponse } from "next/server";

export const runtime = "nodejs";

const seen = new Set<string>(); // swap for a Postgres table in prod

function verify(rawBody: Buffer, sigHeader: string | null, secret: string) {
  if (!sigHeader) return false;
  const expected =
    "sha256_" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(sigHeader);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

export async function POST(req: Request) {
  const raw = Buffer.from(await req.arrayBuffer());
  const sig = req.headers.get("x-fngs-signature");

  if (!verify(raw, sig, process.env.FUNGIES_WEBHOOK_SECRET!)) {
    return new NextResponse("bad signature", { status: 401 });
  }

  const event = JSON.parse(raw.toString("utf8"));

  // Idempotency on event.idempotencyKey, NOT event.id (verified)
  if (seen.has(event.idempotencyKey)) {
    return NextResponse.json({ ok: true, deduped: true });
  }
  seen.add(event.idempotencyKey);

  // Acknowledge fast, do work async — but for the tutorial we do it inline
  await handle(event);
  return NextResponse.json({ ok: true });
}

async function handle(event: any) {
  switch (event.type) {
    case "payment_success":          return onPaymentSuccess(event);
    case "subscription_interval":    return onRenewal(event);
    case "subscription_updated":     return onPlanChange(event);
    case "subscription_cancelled":   return onCancel(event);
    case "payment_refunded":         return onRefund(event);
    case "payment_failed":           return onPaymentFailed(event);
    default:
      console.log("unhandled fungies event", event.type);
  }
}
```

> **Webhook payloads carry MORE data than REST GETs.** Specifically `data.items[].customFields` and the customer's email are **only** in the webhook — `GET /v0/orders/{id}` does not return `items[]`. Do not rely on REST polling as a "missed events" fallback for attribution.
>
> **Always use the raw request body** for signature verification. If you let your framework JSON-parse first, the bytes change and HMAC fails.

***

### Step 5 — Provision and revoke access

Drive your access state from the events:

```ts
// reads playerId from items[] (set at checkout via Step 3)
function getPlayerId(event: any): string | null {
  const items = event?.data?.items ?? [];
  for (const it of items) {
    const cf = it.customFields ?? {};
    if (cf.playerId) return String(cf.playerId);
  }
  return null;
}

async function onPaymentSuccess(event: any) {
  // type: "subscription_initial" | "subscription_interval" | "one_time"
  const paymentType = event.data.payment?.type;
  const playerId = getPlayerId(event);
  const subscriptionId = event.data.subscription?.id;
  const periodEnd = event.data.subscription?.currentIntervalEnd;

  if (!playerId) {
    console.error("no playerId in custom fields", event.idempotencyKey);
    return;
  }

  if (paymentType === "subscription_initial") {
    await db.subscriptions.upsert({
      playerId,
      fungiesSubscriptionId: subscriptionId,
      status: "active",
      currentPeriodEnd: new Date(periodEnd),
    });
    await grantAccess(playerId);
  }
}

async function onRenewal(event: any) {
  await db.subscriptions.update({
    where: { fungiesSubscriptionId: event.data.subscription.id },
    data: {
      status: "active",
      currentPeriodEnd: new Date(event.data.subscription.currentIntervalEnd),
    },
  });
}

async function onPlanChange(event: any) {
  // e.g. customer upgraded — sync new offer / seats
  await db.subscriptions.update({
    where: { fungiesSubscriptionId: event.data.subscription.id },
    data: { offerId: event.data.subscription.offerId /* ...etc */ },
  });
}

async function onCancel(event: any) {
  // Subscription stays "active" until currentIntervalEnd — revoke then
  await db.subscriptions.update({
    where: { fungiesSubscriptionId: event.data.subscription.id },
    data: {
      status: "cancel_at_period_end",
      cancelAt: new Date(event.data.subscription.currentIntervalEnd),
    },
  });
}

async function onRefund(event: any) {
  const playerId = getPlayerId(event);
  await db.subscriptions.update({
    where: { fungiesSubscriptionId: event.data.subscription?.id },
    data: { status: "refunded" },
  });
  if (playerId) await revokeAccess(playerId);
}

async function onPaymentFailed(event: any) {
  // Subscription will move to past_due — give a grace period before revoke
  await db.subscriptions.update({
    where: { fungiesSubscriptionId: event.data.subscription?.id },
    data: { status: "past_due" },
  });
}
```

Subscription lifecycle reference (from .kb/api/subscriptions-endpoints.qmd):

```
incomplete → active → past_due → unpaid → canceled
                    → canceled
                    → paused → active / canceled
incomplete → incomplete_expired
```

***

### Step 6 — Programmatic subscription control (admin actions)

When your support team needs to act on a subscription from your own admin UI, use the Subscriptions API directly:

| Action                  | Call                                            |
| ----------------------- | ----------------------------------------------- |
| Inspect                 | `GET /v0/subscriptions/{id}`                    |
| Update (seats / amount) | `PATCH /v0/subscriptions/{id}/update`           |
| Charge immediately      | `POST /v0/subscriptions/{id}/charge`            |
| Cancel                  | `PATCH /v0/subscriptions/{id}/cancel`           |
| Pause billing only      | `PATCH /v0/subscriptions/{id}/pause-collection` |

Example — change seat count:

```bash
curl -X PATCH "$FUNGIES_API_BASE/v0/subscriptions/$SUB_ID/update" \
  -H "x-fngs-public-key: $FUNGIES_PUBLIC_KEY" \
  -H "x-fngs-secret-key: $FUNGIES_SECRET_KEY" \
  -H "content-type: application/json" \
  -d '{ "quantity": 5 }'
```

> Pausing **payment collection** does **not** pause the subscription period — the customer keeps their access, you just stop charging. Useful for goodwill credit.

***

### Step 7 — Wire up the Customer Portal (self-serve)

You don't need to build a billing UI. Fungies hosts one per store at the path **`/portal`** on your storefront domain (for example: <https://azzeki.com/portal>).

The flow your end-users go through:

1. They click a **Manage billing** link in your SaaS that points to `https://<your-store>/portal`.
2. They sign in with the same email they used at checkout (magic link).
3. They land on the **Customer Portal** showing all their subscriptions, orders, invoices and saved payment methods.
4. They click **Manage Subscription** on any active row to:
   * Update payment method (card / wallet).
   * Change plan (only if you've configured Plans in the Subscriptions dashboard).
   * Cancel (with confirmation) or reactivate a previously cancelled one.
   * Download invoices / receipts with tax breakdowns.

Deep-link from your SaaS:

```tsx
// .env.local: NEXT_PUBLIC_FUNGIES_STORE_URL=https://yourstore.com/
<a
  href={`${process.env.NEXT_PUBLIC_FUNGIES_STORE_URL}portal`}
  className="text-sm underline hover:no-underline"
  target="_blank"
  rel="noopener noreferrer"
>
  Manage billing
</a>
```

You can also pre-fill the customer's email so they skip typing it before the magic-link step:

```tsx
<a
  href={`${process.env.NEXT_PUBLIC_FUNGIES_STORE_URL}portal?email=${encodeURIComponent(user.email)}`}
  ...
>Manage billing</a>
```

> **Path is `/portal` on every Fungies storefront** — works on both custom domains (e.g. `yourstore.com/portal`) and the default `*.app.fungies.io/portal`. No theme overrides this.

States the portal exposes (mirror these in your own UI when you read your DB):

* **Active** — running with a valid payment method.
* **Trialing** — in free trial.
* **Cancelled** — scheduled for termination at period end.
* **Past Due** — payment failed, in grace period.

***

### Step 8 — Seller-side editing & pausing (you, not the customer)

For ops actions you do on behalf of a customer:

1. **Dashboard → Transactions → Subscriptions** lists every subscriber.
2. Click **Edit** on a row to change **Quantity** (seats) or **Amount** (price-per-seat). A drawer slides in.
3. Click **Pause Payment Collection** to stop billing without ending the period — useful when a customer disputes a charge or you want to give a credit. You'll be presented with options for how long to pause.

Same operations are available via API (Step 6) if you want to expose them in your own admin tools.

***

### Step 9 — Test the whole loop locally

```bash
# Terminal 1
pnpm dev
# Terminal 2
ngrok http 3000
```

1. Copy the ngrok HTTPS URL into the Fungies dashboard webhook config (e.g. `https://abc123.ngrok.app/api/fungies/webhook`).
2. Open your `/pricing` page, click **Subscribe**, complete a real test payment with a Stripe test card.
3. In your terminal you should see the event sequence:

```
   payment_success           subscription_initial
   subscription_created
   
```

4. Trigger a refund from the Fungies dashboard → expect `payment_refunded`.
5. Cancel the test subscription from the dashboard → expect `subscription_cancelled`.

If something doesn't show up, check the **Webhook deliveries** log in the dashboard — failed deliveries are listed there with response bodies. See .kb/developers/webhooks-test.qmd.

***

### Production checklist

* HTTPS only; HSTS on.
* Webhook signature verification on, using **raw body buffer**.
* Idempotency keyed on `event.idempotencyKey` (UUID), persisted in Postgres / Redis with a unique index.
* Webhook handler returns 2xx in <1s; heavy work on a queue.
* `event.testMode === true` events are quarantined to your staging DB.
* Retry your downstream side-effects with backoff; Fungies will retry 5xx for you.
* Custom field UUIDs stored in env vars per environment (staging vs prod have different UUIDs).
* One webhook endpoint per concern when complexity grows (multiple endpoints are supported — useful when adding e.g. an affiliate platform later).
* Secrets rotated quarterly; never log raw keys or signatures.

***

### Troubleshooting matrix

| Symptom                                         | Likely cause                                                              | Fix                                                           |
| ----------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------- |
| `401 "API key is invalid"` on every call        | Missing one of the two headers                                            | Send both `x-fngs-public-key` and `x-fngs-secret-key`         |
| `404 "Can not GET /v0/products"`                | Used the wrong URL pattern                                                | Append `/list` (e.g. `/v0/products/list`)                     |
| Custom field empty on rendered checkout         | Pre-filled with unknown id (string key via Elements API, or UUID via SDK) | SDK uses string key; Elements API uses UUID. Match the path.  |
| Webhook never fires                             | Endpoint not public, returns non-2xx, or wrong events selected            | Open dashboard → Webhook deliveries; inspect last attempt     |
| Signature mismatch                              | Body was JSON-parsed before HMAC                                          | Use raw buffer; in Next.js use `req.arrayBuffer()`            |
| `subscription_interval` missing                 | Trial still running, or you didn't subscribe to that event                | Check offer has no active trial; re-check event subscriptions |
| `data.items[]` is undefined                     | You called `GET /v0/orders/{id}` instead of reading the webhook           | Items are webhook-only; persist them on receipt               |
| `GET /v0/elements/checkout/{id}` 404            | No public single-element get                                              | Use `/list` and filter by id, or store the id at create time  |
| `POST /v0/discounts/create` rejects `amount: 0` | Minimum discount is 1%                                                    | Use a real discount or use a different attribution mechanism  |


# SaaS Developers with Pay-As-You-Go products (Usage-based)

## Fungies for SaaS — Usage-Based / Pay-As-You-Go on Top of Subscriptions

> Companion tutorial to [SaaS Subscription Tutorial](/tutorials/saas-developers-with-subscription-products). You already have a base monthly subscription wired up. Now you want to bill customers for what they actually consume — API calls, GB transferred, AI tokens, seats added mid-cycle. This walk-through shows how to do that with Fungies' `[POST /v0/subscriptions/{subscriptionIdOrNumber}/charge](https://docs.fungies.io/api-reference/subscriptions/charge-subscription)` endpoint, what its real constraints are, and how to wire it into a metering pipeline that won't double-charge or leak revenue.

***

### What you'll build

A SaaS that:

1. Sells a **base monthly plan** (e.g. "Pro — $20/mo, includes 10k API calls").
2. **Meters** every API call your customers make.
3. Once a billing period closes (or a hard threshold is crossed), **rolls up the overage** and charges it to the same subscription as a separate invoice using `/charge`.
4. Reconciles via webhook (`payment_success` with `payment.type === "subscription_extra"`).
5. Optionally sells **prepaid credit packs** so heavy users can pay up-front and you bill against credits locally.

***

### How `/charge` actually works

`POST /v0/subscriptions/{subscriptionIdOrNumber}/charge`

* **What it does:** creates a new invoice on an active subscription and immediately attempts to charge the saved payment method. Does NOT alter the recurring schedule.
* **What it returns:** a `payment` object with the new payment type **`subscription_extra`** (distinct from `subscription_initial`, `subscription_interval`, `subscription_update`). Status flows `PENDING → PAID | FAILED`.
* **What it requires:** an `active` subscription (not `trialing`, `paused`, `canceled`, `past_due`).
* **Auth:** same two headers as everywhere else — `x-fngs-public-key` + `x-fngs-secret-key`.

#### The constraints that shape your design (from the OpenAPI spec)

| Constraint                                             | Practical impact                                                                                                                            |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `items` array: **`minItems: 1, maxItems: 1`**          | **Only ONE line item per call.** No multi-metric invoices in one POST. To bill 3 different things, send 3 calls.                            |
| `unitPrice`: integer, **`exclusiveMinimum: 100`**      | **Minimum unit price is 101 cents (\~$1.01).** Per-event micro-billing (e.g. $0.001/API call) is **impossible** — you must aggregate first. |
| `quantity`: `number` (double), `minimum: 1`, default 1 | Fractional quantities are allowed (`1.42 GB`).                                                                                              |
| `currency` enum                                        | **Must match your workspace currency.** Cross-currency charges rejected.                                                                    |
| `offerId`: UUID (optional)                             | If provided, `name` / `unitPrice` / `currency` are pulled from the offer — you only need to send `quantity`.                                |
| Path param `subscriptionIdOrNumber`                    | Accepts the UUID **or** the human-readable order number with optional `#` prefix.                                                           |

> **Read the second row twice.** The single biggest design decision in usage-based billing on Fungies is that **you cannot charge less than \~$1 per `/charge` call**. This forces an aggregate-then-charge pattern, not a charge-per-event pattern. We lean into that below.

#### Minimum valid request

```bash
curl -X POST "https://api.fungies.io/v0/subscriptions/$SUB_ID/charge" \
  -H "x-fngs-public-key: $FUNGIES_PUBLIC_KEY" \
  -H "x-fngs-secret-key: $FUNGIES_SECRET_KEY" \
  -H "content-type: application/json" \
  -d '{
    "description": "API overage — November 2026",
    "items": [{
      "name": "API calls overage (12,420 calls @ $0.001)",
      "unitPrice": 1242,
      "currency": "USD",
      "quantity": 1
    }]
  }'
```

Response:

```json
{
  "status": "success",
  "data": {
    "payment": {
      "object": "payment",
      "id": "<uuid>",
      "type": "subscription_extra",
      "number": "...",
      "status": "PAID",
      "value": 1242,
      "currency": "USD",
      "subscriptionId": "<sub-id>",
      "subscription": { "id": "...", "status": "active" },
      "invoiceNumber": "2026-11-...",
      "invoiceUrl": "https://yourstore.com/api/invoice/<base64>",
      "charges": [
        {
          "id": "...",
          "status": "succeeded",
          "paymentMethod": { "type": "card", "brand": "visa", "last4": "4242" }
        }
      ]
    }
  }
}
```

***

### Step 1 — Pricing model first, code second

Before writing a single line, decide the model. Three patterns map cleanly onto the constraints above.

#### Pattern A — Periodic rollup (most SaaS use this)

> Meter locally; at the end of each billing cycle, sum total $ owed, charge once.

* **Best for:** API platforms, AI inference, bandwidth, anything continuously consumed.
* **Pros:** one charge per customer per cycle; minimum-unit-price problem disappears (you're aggregating to dollars).
* **Cons:** customer surprise risk if usage spikes — mitigate with email alerts at 50/80/100% thresholds.

#### Pattern B — Threshold-triggered

> Meter locally; charge as soon as accrued usage crosses a configurable dollar amount (e.g. every $20 of overage).

* **Best for:** customers who want predictable smaller charges, or to limit your AR exposure.
* **Pros:** failed charges caught early; cash flow even within the cycle.
* **Cons:** more API calls, more invoices for the customer.

#### Pattern C — Prepaid credits

> Sell a credit pack via the normal checkout (e.g. "$50 = 5,000 credits"); decrement on usage; offer auto-top-up by calling `/charge` when balance dips below threshold.

* **Best for:** AI APIs, gaming, anywhere customers want hard caps and the merchant wants money up-front.
* **Pros:** no overage debt, simple mental model.
* **Cons:** credits ledger lives in your DB — you need clear refund/expiry rules.

The rest of this tutorial implements **Pattern A** with a sketch of B and C at the end.

***

### Step 2 — Meter usage in your DB

You need three tables. Here's a Supabase / Postgres minimal schema:

```sql
create table subscriptions (
  id text primary key,                          -- Fungies subscription id (e.g. order-number-based)
  user_id uuid not null references users(id),
  base_offer_id uuid not null,
  included_units bigint not null default 0,     -- e.g. 10000 API calls baked into base plan
  unit_price_cents int not null,                -- e.g. 1 = $0.01 per call beyond included
  currency text not null,                       -- must match workspace currency
  current_period_start timestamptz not null,
  current_period_end timestamptz not null,
  status text not null
);

create table usage_events (
  id bigserial primary key,
  subscription_id text not null references subscriptions(id),
  occurred_at timestamptz not null default now(),
  units bigint not null,                        -- 1 per API call, or N for batched events
  metric text not null default 'api_call',
  request_id text,                              -- for idempotency at the meter level
  unique (subscription_id, request_id)          -- swallow duplicate meter writes
);
create index idx_usage_sub_period on usage_events (subscription_id, occurred_at);

create table usage_charges (
  id uuid primary key default gen_random_uuid(),
  subscription_id text not null references subscriptions(id),
  period_start timestamptz not null,
  period_end timestamptz not null,
  metric text not null,
  units_billed bigint not null,
  unit_price_cents int not null,
  total_cents int not null,                     -- equals fungies payment.value
  fungies_payment_id text unique,               -- nullable until POST returns
  status text not null default 'pending',       -- pending | charged | failed | skipped
  created_at timestamptz not null default now(),
  unique (subscription_id, period_start, period_end, metric)  -- idempotency key
);
```

Write usage on the hot path:

```ts
// every customer-facing API call
async function meter(subscriptionId: string, units = 1, requestId: string) {
  await db.from("usage_events").insert({
    subscription_id: subscriptionId,
    units,
    metric: "api_call",
    request_id: requestId, // your own request id; unique constraint dedupes retries
  });
}
```

Keep this fire-and-forget cheap. Don't compute totals on the hot path; do that in the rollup.

***

### Step 3 — The nightly / end-of-period rollup job

Run this on a cron (e.g. once a day, plus a final pass an hour after each subscription's `current_period_end`).

```ts
// scripts/run-overage-charges.ts — Node, runs on a schedule
import "dotenv/config";

const FUNGIES_API = process.env.FUNGIES_API_BASE!;
const HEADERS = {
  "content-type": "application/json",
  "x-fngs-public-key": process.env.FUNGIES_PUBLIC_KEY!,
  "x-fngs-secret-key": process.env.FUNGIES_SECRET_KEY!,
};

const MIN_CHARGE_CENTS = 101; // hard API floor (exclusiveMinimum: 100)

async function main() {
  const dueSubs = await db
    .from("subscriptions")
    .select("*")
    .eq("status", "active")
    .lte("current_period_end", new Date().toISOString());

  for (const sub of dueSubs.data ?? []) {
    await rollupAndCharge(sub);
  }
}

async function rollupAndCharge(sub: any) {
  const { data: usage } = await db.rpc("sum_usage", {
    sub_id: sub.id,
    from: sub.current_period_start,
    to: sub.current_period_end,
  });
  const totalUnits = Number(usage?.[0]?.total ?? 0);
  const overUnits = Math.max(0, totalUnits - sub.included_units);
  const totalCents = overUnits * sub.unit_price_cents;

  if (totalCents < MIN_CHARGE_CENTS) {
    await rollForward(sub, overUnits, totalCents);
    return;
  }

  // Reserve an idempotency row BEFORE calling Fungies
  const { data: chargeRow, error } = await db
    .from("usage_charges")
    .insert({
      subscription_id: sub.id,
      period_start: sub.current_period_start,
      period_end: sub.current_period_end,
      metric: "api_call",
      units_billed: overUnits,
      unit_price_cents: sub.unit_price_cents,
      total_cents: totalCents,
      status: "pending",
    })
    .select()
    .single();

  if (error?.code === "23505") {
    // Unique violation: another worker already charged this period
    return;
  }

  // ONE item only per call (API limit: maxItems: 1)
  const r = await fetch(`${FUNGIES_API}/v0/subscriptions/${sub.id}/charge`, {
    method: "POST",
    headers: HEADERS,
    body: JSON.stringify({
      description: `Overage — ${sub.current_period_start.toISOString().slice(0, 7)}`,
      items: [
        {
          name: `API calls overage (${overUnits.toLocaleString()} calls @ $${(sub.unit_price_cents / 100).toFixed(3)})`,
          unitPrice: totalCents, // bundle to satisfy >100 minimum
          currency: sub.currency, // must match workspace currency
          quantity: 1,
        },
      ],
    }),
  });

  const json = await r.json();
  if (json.status !== "success") {
    await db
      .from("usage_charges")
      .update({ status: "failed" })
      .eq("id", chargeRow.id);
    console.error("Fungies /charge failed", sub.id, json.error?.message);
    return;
  }

  await db
    .from("usage_charges")
    .update({ status: "charged", fungies_payment_id: json.data.payment.id })
    .eq("id", chargeRow.id);
}

async function rollForward(sub: any, units: number, cents: number) {
  // Below the $1 API floor — push into next period so it eventually accrues
  await db.from("usage_events").insert({
    subscription_id: sub.id,
    units,
    metric: "carry_forward",
    request_id: `cf_${sub.id}_${sub.current_period_end.toISOString()}`,
  });
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
```

#### Three things that make this safe

1. **Reserve before charge.** The `usage_charges` row is inserted with `status: 'pending'` *before* the network call. The `unique (subscription_id, period_start, period_end, metric)` constraint guarantees that two cron workers (or one cron and a manual retry) can't both POST `/charge` for the same window.
2. **One item per call.** The OpenAPI spec hard-caps `items` at 1. If you have multiple metrics (calls + bandwidth + storage), iterate and POST separately, each with its own `usage_charges` row keyed by `metric`.
3. **Roll forward sub-dollar overages.** Don't lose them; carry into next period as a synthetic `usage_event` so they accrue.

***

### Step 4 — Reconcile via webhook

Add `subscription_extra` handling to the webhook handler from the base subscriptions tutorial:

```ts
case "payment_success":
  if (event.data.payment?.type === "subscription_extra") {
    return onOverageCharged(event);
  }
  return onPaymentSuccess(event);

async function onOverageCharged(event: any) {
  const paymentId = event.data.payment.id;
  await db.from("usage_charges")
    .update({ status: "charged" })
    .eq("fungies_payment_id", paymentId);
  console.log("overage settled", paymentId, event.data.payment.value, event.data.payment.currency);
}
```

If `payment_failed` arrives for a `subscription_extra`, mark the row failed and decide your retry policy (e.g. retry tomorrow; if still failing after 3 days, suspend the account or downgrade).

```ts
case "payment_failed":
  if (event.data.payment?.type === "subscription_extra") {
    await db.from("usage_charges")
      .update({ status: "failed" })
      .eq("fungies_payment_id", event.data.payment.id);
    await notifyCustomerOfFailedOverage(event.data.subscription.id);
  }
  break;
```

> **Why webhooks even though `/charge` returns synchronously?** The synchronous response tells you the *initial* charge result. Card auths can later be reversed (`PARTIALLY_REFUNDED`, `REFUNDED`, network disputes). Webhooks are the only way to learn about those state transitions. Always treat the synchronous response as a fast path, not the source of truth.

***

### Step 5 — Show the customer what they're being charged

Two surfaces matter.

#### In your app (real-time)

A "current cycle usage" widget:

```tsx
export async function UsageMeter({
  subscriptionId,
}: {
  subscriptionId: string;
}) {
  const { units, included, unitPriceCents, currency } =
    await getCurrentCycleUsage(subscriptionId);
  const over = Math.max(0, units - included);
  const projectedCents = over * unitPriceCents;

  return (
    <div className="rounded-lg border p-4">
      <div className="text-sm text-zinc-500">Current cycle</div>
      <div className="text-2xl font-medium">
        {units.toLocaleString()} / {included.toLocaleString()} calls
      </div>
      {over > 0 && (
        <div className="mt-2 text-sm text-amber-700">
          Projected overage:{" "}
          <strong>
            {(projectedCents / 100).toFixed(2)} {currency}
          </strong>{" "}
          at end of cycle
        </div>
      )}
    </div>
  );
}
```

#### In Fungies (after charge)

The customer sees the new invoice in the [hosted Customer Portal at `/portal`](https://azzeki.com/portal) under the subscription's invoice list, with the `description` you sent and a downloadable PDF (`invoiceUrl` from the response).

**Tip:** put a human-readable breakdown in `name` since the portal shows it verbatim. `"API calls overage (12,420 calls @ $0.001)"` is better than `"Overage"`.

***

### Step 6 — Pattern B (threshold-triggered) in 30 lines

Same plumbing, but the trigger is a metered total instead of a clock:

```ts
const THRESHOLD_CENTS = 2000; // charge every $20 of overage

async function onUsageWritten(subscriptionId: string) {
  const sub = await getSub(subscriptionId);
  const totalUnits = await sumUsageInCurrentCycle(sub);
  const overUnits = Math.max(0, totalUnits - sub.included_units);
  const accrued = overUnits * sub.unit_price_cents;

  const alreadyCharged = await sumChargedInCurrentCycle(sub);
  const due = accrued - alreadyCharged;

  if (due >= THRESHOLD_CENTS) {
    await chargeOverage(sub, due); // same logic as Step 3
  }
}
```

Call `onUsageWritten` from a queue (BullMQ, Trigger.dev, Inngest) — never from the hot meter path, and never more than once per subscription concurrently (use a per-subscription lock).

***

### Step 7 — Pattern C (prepaid credits) in sketch

Two pieces:

1. **Sell credit packs as one-time products** through the normal checkout. On `payment_success` with `type: "one_time"`, credit the user's local ledger.
2. **Auto-top-up via `/charge`** when balance drops below a threshold and the user has opted in. Use the same idempotency pattern from Step 3, but key on `(subscription_id, top_up_request_id)` instead of period.

Refunds: when a user cancels, decide whether to refund unused credits via Fungies' refund flow, or let them expire — document this in your ToS.

***

### Production checklist

* `MIN_CHARGE_CENTS = 101` constant in code (matches `exclusiveMinimum: 100`).
* `usage_charges` unique index on `(subscription_id, period_start, period_end, metric)` is enforced.
* Per-subscription concurrency lock around the rollup (Postgres advisory lock or queue concurrency 1).
* `currency` on every charge is asserted equal to workspace currency at startup.
* Multi-metric? One `/charge` call per metric per period (the API caps `items` at 1 — chain calls).
* Subscription `status` checked = `active` before POSTing — `paused` / `canceled` / `past_due` will reject.
* Webhook handler discriminates `payment.type === "subscription_extra"` from regular `subscription_interval`.
* Customer-facing email when an overage charge succeeds AND when one fails.
* Sub-dollar overages roll forward into next cycle, not silently dropped.
* Synchronous `/charge` response NEVER treated as final — webhooks are the source of truth.
* Manual "charge now" button in admin uses the same code path (don't fork).

***

### Troubleshooting matrix

| Symptom                                           | Likely cause                                                                              | Fix                                                                                                                         |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `400` with `unitPrice must be greater than 100`   | Sent `unitPrice <= 100`                                                                   | Aggregate until total ≥ 101 cents; carry sub-dollar amounts forward.                                                        |
| `400` with `items must contain at most 1 item`    | Sent multiple line items                                                                  | Loop and POST one call per metric.                                                                                          |
| `400` with currency error                         | Currency doesn't match workspace                                                          | Read workspace currency on boot, assert.                                                                                    |
| Charge succeeded but no `payment_success` webhook | Endpoint not subscribed, or filtered `type`                                               | Check the dashboard's webhook deliveries log; ensure you handle `subscription_extra` in addition to `subscription_initial`. |
| Same period charged twice                         | Missing unique index on `usage_charges`, or two workers raced before the row was reserved | Add the unique index; reserve the row BEFORE the network call.                                                              |
| Customer charged on canceled sub                  | Race between cron and cancellation event                                                  | Re-fetch `GET /v0/subscriptions/{id}` immediately before POST and abort if `status !== "active"`.                           |
| Overage charge rejected with payment failure      | Card declined, expired, or insufficient funds                                             | Pause overage billing, email customer to update card via `[/portal](https://azzeki.com/portal)`, retry tomorrow.            |
| Need to refund an overage                         | Use Fungies dashboard refund on the `subscription_extra` payment                          | `payment_refunded` webhook will fire; reverse the local `usage_charges` row.                                                |

***

### Quick reference

|                          |                                                                                                                                            |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **Endpoint**             | `POST /v0/subscriptions/{subscriptionIdOrNumber}/charge`                                                                                   |
| **Docs**                 | [docs.fungies.io/api-reference/subscriptions/charge-subscription](https://docs.fungies.io/api-reference/subscriptions/charge-subscription) |
| **Auth**                 | `x-fngs-public-key` + `x-fngs-secret-key` (both required)                                                                                  |
| **Body shape**           | `{ description?, items: [{ name, unitPrice, currency, quantity?, offerId? }] }`                                                            |
| **Limits**               | `items` 1..1, `unitPrice > 100` (cents), `quantity ≥ 1` (double), currency = workspace                                                     |
| **Sync result**          | `payment` object, type `subscription_extra`, status PENDING/PAID/FAILED                                                                    |
| **Async confirm**        | webhook `payment_success` / `payment_failed` with `payment.type = "subscription_extra"`                                                    |
| **Subscription must be** | `status: "active"`                                                                                                                         |

### Related

* Base flow: [SaaS Subscription Tutorial](/tutorials/saas-developers-with-subscription-products)


# Payment history

You can see all payment attemps including successful and failed ones under Payments Sub-tab under Transactions in your Dashboard. Access it [here](https://app.fungies.io/txs/payments).

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FBz0TAB7L4nbnmvsda5pN%2Fimage.png?alt=media&amp;token=cd5f43a1-5524-41d3-b9a6-d9228049e8b0" alt=""><figcaption><p>See payment history including all details</p></figcaption></figure>

Accessing each payment will show all the attemps charging the chosen payment method by the customer, including:

* Last 4 digits of the card,
* Decline reasons by banks or networks,
* Risk level

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FneO5zmtMsSNFooJfnUMg%2Fimage.png?alt=media&amp;token=f56dd8d3-a620-4caf-a500-5c1442f608ad" alt=""><figcaption><p>Accessing payment details</p></figcaption></figure>


# Selling FREE products

You can offer customers FREE products including: digital downloads, game keys, game assets, gift cards, software keys:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FjiUCjrMKuuKPD0Bk6QiZ%2Fimage.png?alt=media&amp;token=3f8f74bf-55ad-41c7-a10c-aade67cccde2" alt=""><figcaption><p>Check the "Set this offer as free" to sell a FREE product</p></figcaption></figure>

Just add an Offer and you'll see it as an option under Price.

Customers will see the product as FREE to claim in the Product Page:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FapGAnRvDunjZhTPt6bQT%2Fimage.png?alt=media&amp;token=d8462d92-6f91-4bdf-95bc-c8010ea5de56" alt=""><figcaption><p>Customers can now claim FREE products</p></figcaption></figure>

When proceeding to checkout, users will just need to fill in their e-mail data:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FuUR263qosLfWQipq4Gqc%2Fimage.png?alt=media&amp;token=f63638c5-6ecf-412b-9a06-41130410049d" alt=""><figcaption><p>Claiming a FREE product</p></figcaption></figure>


# Managing Game Keys

It's important to provide Users with best possible choices for your game. Your game can have:

* Many editions
* For different platforms (PSN, Xbox Live, Steam, GOG, Epic Games)
* Different prices for different regions

So it's important to create as many products as possible to increase the chances of buying your game.

You can choose many platforms and regions.  Examples:

* Sell PSN keys for Europe
* Sell Epic Games Store keys for Asia
* Sell Steam Game Keys for EMEA

Every product should have a separate:

* Region
* Platform
* Edition

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fu1QLKvHaSwxLKSZp1ShY%2Fimage.png?alt=media&amp;token=3a6788f0-214d-4602-a573-938077764f8f" alt=""><figcaption><p>You can sell Steam game keys for Global Region</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fc0dY26zWjcppjbHSleGR%2Fimage.png?alt=media&amp;token=dc17180b-893a-4031-9c23-d717af22074a" alt=""><figcaption><p>You can sell GOG.com game keys</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fm3VgzburrZYiePNdPubf%2Fimage.png?alt=media&amp;token=4193ca10-8c90-4ccc-98ec-91fb54712ae2" alt=""><figcaption><p>You can sell PSN keys for Europe Region - it's all up to you how you set up the keys</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F0Whdwcy7RneVYbe2rlEZ%2Fimage.png?alt=media&amp;token=90cb3b40-65da-41a5-9989-f9892c9ffe38" alt=""><figcaption><p>You can add more keys when the stock is Sold Out</p></figcaption></figure>

It's important to fill out every possible information abour your game, such as:

* Gallery with screenshots
* Tags
* Pricing based on Region
* System requirements
* Description

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FCEWi337fAGHokZIJS8R9%2Fimage.png?alt=media&amp;token=44023d58-592b-4e2d-9483-5bb84aa070e8" alt=""><figcaption><p>Upload as many screenshots as possible to showcase your game</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FjQR7KxeQC3HJAaYymWtp%2Fimage.png?alt=media&amp;token=fac34864-ef68-46bf-b1e8-5575ea856358" alt=""><figcaption><p>Remember to fill out the game's description and also add YouTube trailer so that users can see it on the Product Page</p></figcaption></figure>


# Managing Game Assets

If your have have Microtransactions or IAP, then selling Game Assets through your own Web Store can be done using our platform.

Go to Game Assets in the [Dashboard ](https://app.fungies.io/projects)to start creating or managing your In-Game Assets.

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FmAcLFhaLfHKZpiR8mCyS%2Fimage.png?alt=media&amp;token=97e9fe17-919b-44ef-88a3-3e38eed8e8ef" alt=""><figcaption><p>You can have as many In-Game Assets listed as you want including Virtual Currencies and Virtual Items</p></figcaption></figure>

You can add:

* Games as Projects
* Then Add Virtual Currency or Virtual Item
* Add Variants for each Virtual Currency and Item
* Example: set Gold as new Virtual Currency, and then set 500xGold as one of the Variants

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2F1JXh2R7aKaAEKe42gm3P%2Fimage.png?alt=media&amp;token=1d998747-6a2f-4486-b2e4-d22bb26d1819" alt=""><figcaption><p>Set variants for each of your Virtual Currency or Item</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FxE01VsZ4dBaf4jcHlCV6%2Fimage.png?alt=media&amp;token=271a80da-1473-45be-ab81-6c13952d34d7" alt=""><figcaption><p>Variants are visible in your Web Store and can be chosen by the user</p></figcaption></figure>

In order for your game's back-end to recognize transactions and award players with appropriate items, you need to define at least 2 fields:

* SKU / Item\_ID - this will be sent to your game's back-end via Webhooks - so that the game knows which items to be rewarded to the player
* User\_ID field - to be filled in by the user
* Server\_ID field - to be filled in by the user

You can customize those Custom Fields in the Project Settings:

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FrDRTOadjndP1208QtmQ0%2Fimage.png?alt=media&amp;token=ad54710d-1aba-4487-8c52-f46d81ac80d5" alt=""><figcaption><p>These 2 custom fields were added for this game: User_ID and Server</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fw2cU0Tfl8KPAax4tHdyj%2Fimage.png?alt=media&amp;token=beda6700-058b-408e-9466-ea7632315e77" alt=""><figcaption><p>Click on Edit settings to see all the details for the Project</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2Fmo783Vswrg0hewrhT2QJ%2Fimage.png?alt=media&amp;token=31250c26-605b-4233-8532-a0c772512f43" alt=""><figcaption><p>Click on Edit to add Custom Fields such as User_ID</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FTabKgHo4szXg2WTe2N0i%2Fimage.png?alt=media&amp;token=616b40c6-41ae-409e-a0cc-01fd5af81939" alt=""><figcaption><p>Once done fill out all necessary information about your game's Project settings</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FJhFeGUeD93isjqwqATM7%2Fimage.png?alt=media&amp;token=61147c76-0d1b-4d87-b666-dc1ab617f2c9" alt=""><figcaption><p>You can add 1 Text Field or Multiple Options (such as Servers list)</p></figcaption></figure>

When setting up Text field, add the following:

* Label: name of the field, e.g. User ID
* Placeholder: visible by default inside the text field, e.g. "Fill in your User ID here"
* Regex:&#x20;
* Key name: this will be sent to your Webhook, e.g. user\_id

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FFUiqEta1tkPDzcClxF0r%2Fimage.png?alt=media&amp;token=3ab055b2-6a0c-4fab-996c-88896db369a2" alt=""><figcaption><p>The Game Asset page that's visible to the user: above is Text Field - User ID, and below that is Server - Multiple Options</p></figcaption></figure>


# Pricing

Below you'll find our Pricing details. Check it on our [website](https://fungies.io/pricing/):&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FgwmpB0jS1u6IPg1a3FxL%2Fimage.png?alt=media&amp;token=aba4082b-0b79-45e9-8f02-1e1ebeb6dee1" alt=""><figcaption><p>Pay only commission from everys ale</p></figcaption></figure>


# Fulfillment of Orders

With just one click you can find the information about the amount you've earned and how to pay it out. Go to Payout section and check your balance.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FZT6B2b5U6ELFPsa5UXpM%2Fimage.png?alt=media&amp;token=7f96f213-cd6a-4f42-8b99-1e7d33f93620" alt=""><figcaption></figcaption></figure>

Payouts are done automatically on daily basis. That is why the amount of Total balance may indicate 0 -> the funds are on their way to your bank account!&#x20;

For more details you can view Order history or check data on Stripe.&#x20;


# Prohibited Business and Products

Here's a list of prohibited businesses, startups, or products that cannot be sold through Fungies (Merchant of Record platform):

#### 1. **High-Risk Jurisdictions and Persons**

* **High-risk jurisdictions**: Cuba, Iran, North Korea, Syria, Crimea, Donetsk, and Luhansk regions.
* **High-risk persons**: Individuals or entities on restricted lists (e.g., US, UK, EU, UN).

#### 2. **Prohibited Services**

* Export, re-export, sell, or supply certain services to Russia, including:
  * Accounting, corporate formation, engineering, IT consultancy, and other enterprise management services.
  * Market research, advertising, auditing, and legal advisory services in Russia.
* Export or sale of prohibited goods to Russia, such as luxury goods, sensitive items, and enterprise management software.

#### 3. **Illegal Products and Services**

* **Drugs and drug paraphernalia**: Including illegal drugs, substances mimicking drugs, and related equipment.
* **Fake IDs and fraudulent services**: Services for creating fake references or IDs.
* **Telecommunications manipulation**: Equipment like jamming devices.

#### 4. **Violent or Harmful Businesses**

* Businesses promoting unlawful violence or harm, including:
  * Physical violence or harm based on race, religion, disability, gender, sexual orientation, or other characteristics.
  * Unlawful activities or celebrations of harm.

#### 5. **Adult Content and Services**

* Prohibited adult services: Escort services, prostitution, pay-per-view services, adult video stores, live chat services, and similar content.
* Pornography and explicit content (including AI-generated).
* **Adult products**: Sex toys, life-like sex toys, and similar items.

#### 6. **Debt and Financial Products**

* Debt relief companies (settlement, consolidation, negotiation).
* Certain financial services, such as ATMs, cheque cashing, money orders, peer-to-peer money transmission, shell banks, and similar products.
* Gambling and lottery-related businesses (e.g., casinos, sweepstakes, fantasy sports).

#### 7. **Gambling and Betting**

* **Games of chance**: Internet gambling, casinos, sweepstakes, lotteries, and related activities.
* **Games of skill**: Tournaments or competitions offering monetary or material prizes.
* **Forecasting**: Sports betting, odds-making, and similar activities.

#### 8. **Government-Related Services**

* Offering unauthorized or misleading government services.
* **Government economic support**: Distribution of grants or economic support without proper authorization.

#### 9. **Identity and Intellectual Property Services**

* **Identity theft protection**: Services related to identity theft protection, monitoring, and recovery.
* **IP infringement**: Sale of counterfeit goods, unauthorized sales of licensed products, or infringing on intellectual property rights.

#### 10. **Legal and Lending Services**

* **Bankruptcy lawyers**: Legal firms offering bankruptcy-related services.
* **Debt collection**: Agencies or individuals collecting debt.
* **Lending services**: Loan repayments via credit cards, and payday or high-interest loans.
* **Credit repair**: Credit monitoring, repair, or counselling services.

#### 11. **Cannabis and Related Products**

* **Cannabis**: Sale of marijuana, CBD products with high THC, and related cultivation equipment.
* **CBD products**: THC levels exceeding legal limits.

#### 12. **Nutraceuticals and Health-Related Products**

* Sale of nutraceuticals, pseudo-pharmaceuticals, or any unsafe health products with misleading claims.

#### 13. **Non-Fiat Currency**

* **Cryptocurrency**: Includes mining, staking, ICOs, and secondary NFT sales.

#### 14. **Travel and Hospitality Services**

* Commercial airlines, charter flights, private airlines, and timeshare services.
* **Tourism-related**: Services like booking, transportation, and related activities.

#### 15. **Pyramid Schemes and MLM**

* Multi-level marketing (MLM) businesses, pyramid schemes, or any "get rich quick" programs.
* **Unfair marketing**: Deceptive testimonials, fake reviews, and high-pressure sales tactics.

#### 16. **Weapons, Firearms, and Dangerous Materials**

* Guns, ammunition, explosives, and components for weapons (including 3D-printed weapons).
* Dangerous materials: Toxic, flammable, or radioactive substances.

#### 17. **Unfair or Deceptive Practices**

* Businesses engaging in unfair, deceptive, or abusive acts, including false advertising, misleading claims, or predatory practices.
* **Telemarketing** and **door-to-door sales** that use deceptive methods.

#### 18. **Research Chemicals and Restricted Goods**

* Sale of research chemicals or restricted goods for postage per USPS guidelines.

#### 19. **Prohibited Content Creation Platforms**

* Platforms hosting or distributing third-party content (e.g., creators receiving tips or selling digital goods), subject to compliance with platform rules.

#### 20. **Jurisdiction-Specific Prohibited Businesses**

* **Brazil**: Genital prosthetics, sex accessories, and lifelike sex toys.
* **Canada**: Alcohol, mortgage consulting, and charities.
* **India**: Alcohol, charities, gambling, and sex toys.
* **Japan**: Various prohibited businesses including sex toys and fortune-telling services.
* **Malaysia**: Sex toys, matchmaking, and genital prosthetics.
* **Mexico**: Adoption agencies, cross-border currency exchange, and debt collection agencies.
* **Singapore**: Sales of illegal ads or services.
* **Thailand**: Alcohol, charities, and gambling equipment.
* **United Arab Emirates**: Gambling, genital prosthetics, and sex toys.
* **United States**: Extended warranties, mortgage consulting, and shipping brokers.

This list is subject to legal and regulatory changes, so businesses should always consult with us to ensure full compliance with their platform policies.


# Invoices and Receipts

Customers will get invoices if they fill out their [B2B details](/getting-paid/billing-details) during checkout - for both One-Time Payments (such as Digital Downloads, Game Keys or simple One-Time Payments) and Subscriptions.&#x20;

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FdDvQdxstLoszM2RYaqdf%2Fimage.png?alt=media&amp;token=534deb2e-631d-4538-b4da-12ed1db41c74" alt=""><figcaption><p>Customers can fill out B2B details including their Tax ID's during checkout - when the <a href="/getting-paid/billing-details">Billing Step Info is turned on</a>.</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FuX7Yq4O8ZXPV70P8WGjv%2Fimage.png?alt=media&amp;token=d8bd449d-c0ef-4860-bc45-27d159db7a91" alt=""><figcaption><p>Invoices will be sent to B2B customers if they fill out their Tax details during checkout (if you've turned on Billing Step Info in the Dashboard).</p></figcaption></figure>

<figure><img src="https://3798839229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtTjX1Zr5bWzjMleIZro2%2Fuploads%2FFDQIDvdOv2aTEwfhhIr4%2Fimage.png?alt=media&amp;token=676058f4-52da-45c1-8351-65a3155e0236" alt=""><figcaption><p>Customer receive e-mails with the link to their invoice.</p></figcaption></figure>




---

[Next Page](/llms-full.txt/1)

