# How to Accept Payments for a Desktop App (macOS and Windows)

> Complete guide to selling desktop applications with payment processing, license key delivery, and activation. Covers Electron, Tauri, and native apps with Dodo Payments.
- **Author**: Ayush Agarwal
- **Published**: 2026-03-24
- **Category**: Payments, License Keys, How-To
- **URL**: https://dodopayments.com/blogs/accept-payments-desktop-app

---

Native development for macOS with Swift and Windows with C# or C++ remains as powerful as ever for high-performance tools.

However, once you have built your masterpiece, you face a significant hurdle: how do you actually get paid? Unlike the web, where you can just drop a checkout button on a page, desktop apps require a bridge between the purchase and the software itself. You might consider the Mac App Store or the Microsoft Store, but they come with heavy restrictions and a 30% revenue cut. Selling directly to your users is the best way to maximize your margins and maintain a direct relationship with your customers.

In this guide, we will explore how to accept payments for your desktop app, manage license keys, and handle global tax compliance without losing your mind. We will focus on using Dodo Payments to automate the entire lifecycle from purchase to activation.

## The Desktop App Payment Problem

Selling a desktop app is fundamentally different from selling a SaaS subscription. When a user buys a web app, you simply update a row in your database to grant them access. With a desktop app, the software lives on the user's machine, often running offline or in restricted environments. This creates several unique challenges that you must solve.

> The biggest mistake founders make when setting up payments is treating it as a solved problem. You wire up a gateway, add a checkout button, and assume you are done. Six months later, you are dealing with tax notices, failed renewals, and checkout abandonment from missing local payment methods.
>
> \- Ayush Agarwal, Co-founder & CPTO at Dodo Payments

First, there is no built-in checkout system for standalone binaries. You need a way to collect money securely and then link that payment to a specific installation of your software. This is typically handled through license keys. A user buys the software on your website, receives a key, and enters it into the app to unlock features.

Second, you have to handle license activation and validation. You need an API that your app can call to verify that a key is valid and hasn't been used on too many machines. This API must be reliable and fast, as it is often the first thing a user interacts with after downloading your app.

Third, users expect some level of offline functionality. If a user is on a plane or has a spotty internet connection, your app shouldn't suddenly stop working just because it can't reach your validation server. You need a strategy for local license storage and periodic re-validation.

Finally, there is the nightmare of global tax compliance. If you sell your app to a user in Germany, you need to collect VAT. If you sell to someone in New York, you might need to collect sales tax. Handling this manually for every country and state is impossible for a small team. This is where a [merchant of record for SaaS](https://dodopayments.com/blogs/merchant-of-record-for-saas) becomes essential.

## 3 Approaches to Desktop App Payments

There are three primary ways to structure your payment flow for a desktop application. The right choice depends on your product type and how you want users to discover it.

### 1. Landing Page + License Key (Most Common)

This is the classic "indie" approach. You build a marketing website that explains the benefits of your app. When a user clicks "Buy Now," they are taken to a checkout page. After a successful purchase, a license key is generated and emailed to them. The user then downloads the app, installs it, and enters the key to activate it.

This approach is excellent for SEO because your landing page can rank for relevant keywords. It also allows you to use a full-featured checkout experience with multiple payment methods. It is the most common model for professional tools and creative software.

### 2. In-App Purchase via Web Checkout

In this model, the user downloads a "trial" or "lite" version of your app first. When they try to use a premium feature, you open a web view or a system browser window that points to your checkout page. Once the purchase is complete, the app detects the change (usually via a webhook or a polling API) and unlocks the features immediately.

This reduces friction because the user is already inside your app when they decide to buy. However, it requires more complex integration to ensure the app knows exactly when the purchase has finished.

### 3. Hybrid Model

The hybrid model uses a landing page for the initial purchase but allows users to manage their subscription or buy upgrades from within the app. This is common for apps that have moved to a [subscription vs license model](https://dodopayments.com/blogs/subscription-vs-license-model). It gives you the best of both worlds: high-intent traffic from the web and low-friction upgrades for existing users.

## Why Dodo Payments for Desktop Apps?

Dodo Payments is uniquely suited for desktop app developers because it solves the two hardest parts of the process: global tax and license management.

When you use Dodo, we act as your Merchant of Record. This means we handle all the tax collection, remittance, and compliance for every country in the world. You don't have to worry about VAT, GST, or US Sales Tax. We also handle fraud detection and chargebacks, so you can focus on building your app.

Beyond payments, Dodo has a built-in [software license management](https://dodopayments.com/blogs/software-license-management) system. When you create a product in Dodo, you can enable license keys with a single toggle. Dodo will automatically generate a unique key for every purchase and email it to the customer. You can then use our License API to validate these keys directly from your app.

## Step-by-Step: Landing Page + License Key Approach

Let's walk through the implementation of the most common model using Dodo Payments. This workflow works for Electron, Tauri, and native apps.

### 1. Create Your Product in Dodo

Log in to your Dodo Payments dashboard and create a new product. You can choose between a one-time purchase or a subscription. In the product settings, make sure to enable "License Keys." You can configure how many activations are allowed per key (for example, allowing a user to use the app on two machines).

### 2. Build Your Marketing Page

Create a landing page for your app. You can use any framework like Next.js, Astro, or even a simple HTML file. Use [embedded payments for SaaS](https://dodopayments.com/blogs/embedded-payments-saas) to add a checkout button. When the user clicks it, Dodo's checkout overlay will appear, allowing them to pay via credit card, Apple Pay, Google Pay, or local methods like UPI.

### 3. Automatic License Delivery

Once the payment is successful, Dodo takes over. We send a professional receipt to the customer that includes their unique license key. You don't need to write any code to generate or email these keys. If you want to show the key on your "Thank You" page, you can also retrieve it via our API or webhooks.

### 4. Add License Input in Your App

In your desktop application, create a simple screen that asks the user for their license key. This is usually shown on the first launch or when the user tries to access a locked feature.

### 5. Validate via Dodo License API

When the user enters their key, your app should call the Dodo License API. The great thing about this API is that it is public, meaning you can call it directly from your client-side code (Electron or Tauri) without needing a backend server or exposing your private API keys.

### 6. Store Validation Result Locally

To support offline use, you should store the validation result on the user's machine. A common pattern is to store an encrypted JSON file or a value in the system's secure keychain. This allows the app to verify the license on subsequent launches even if there is no internet connection.

### 7. Handle Machine Deactivation

If a user reaches their activation limit, they might want to move the license to a new machine. You can provide a "Deactivate" button in your app that calls the Dodo License API to free up an activation slot.

## Activation Flow Diagram

Here is how the entire process looks from the user's perspective:

```mermaid
flowchart TD
    A[User visits Website] --> B[User purchases via Dodo Checkout]
    B --> C[Dodo generates License Key]
    C --> D[Dodo emails Key to User]
    D --> E[User downloads & opens Desktop App]
    E --> F[User enters License Key in App]
    F --> G[App calls Dodo License API]
    G --> H{Is Key Valid?}
    H -- Yes --> I[App activates & stores token locally]
    H -- No --> J[App shows error message]
    I --> K[User uses App offline]
```

## Code Examples

Let's look at how to implement the technical parts of this flow.

### License Key Validation (Node.js / Electron)

If you are using Electron, you can use the Dodo Payments SDK to validate keys. Since the validation endpoint is public, you don't need to worry about leaking secrets.

```javascript
import DodoPayments from 'dodopayments';

// No API key needed for public license validation
const dodo = new DodoPayments();

async function activateApp(licenseKey) {
  try {
    const response = await dodo.licenses.activate({
      license_key: licenseKey,
      name: 'User's MacBook Pro' // Optional: identify the device
    });

    if (response.id) {
      console.log('Activation successful!');
      // Store response.id or a success token locally
      return true;
    }
  } catch (error) {
    console.error('Activation failed:', error.message);
    return false;
  }
}
```

### License Key Validation (Rust / Tauri)

For Tauri apps, you can call the API directly using the `reqwest` crate or similar.

```rust
use serde::{Deserialize, Serialize};

#[derive(Serialize)]
struct ActivateRequest {
    license_key: String,
    name: String,
}

#[derive(Deserialize)]
struct ActivateResponse {
    id: String,
}

async fn validate_license(key: &str) -> Result<bool, reqwest::Error> {
    let client = reqwest::Client::new();
    let res = client.post("https://test.dodopayments.com/licenses/activate")
        .json(&ActivateRequest {
            license_key: key.to_string(),
            name: "User Device".to_string(),
        })
        .send()
        .await?;

    Ok(res.status().is_success())
}
```

### Local License Storage

Storing the license securely is important to prevent simple "copy-paste" piracy. On macOS, you should use the Keychain. On Windows, the Credential Manager is a good choice. For Electron apps, libraries like `keytar` make this easy.

```javascript
import keytar from "keytar";

const SERVICE_NAME = "MyAwesomeDesktopApp";
const ACCOUNT_NAME = "LicenseToken";

async function saveLicenseToken(token) {
  await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, token);
}

async function getLicenseToken() {
  return await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);
}
```

### Webhook Handler for Subscriptions

If you sell your app as a subscription, you need to know when a user cancels or their payment fails so you can revoke access. Dodo sends webhooks for these events.

```javascript
// Example Express.js webhook handler
app.post("/webhooks/dodo", (req, res) => {
  const event = req.body;

  if (event.type === "subscription.cancelled") {
    const subscriptionId = event.data.id;
    // Find the license key associated with this subscription
    // and mark it as invalid in your database or call Dodo API to revoke
    revokeLicenseForSubscription(subscriptionId);
  }

  res.status(200).send("OK");
});
```

## Advanced Licensing Strategies

Once you have the basics working, you can implement more advanced strategies to protect your revenue and improve the user experience.

### Machine-Based Activation Limits

One of the biggest fears for desktop developers is a single license key being shared on a public forum. Dodo allows you to set a hard limit on activations. When a user tries to activate on a third machine (if your limit is two), the API will return an error. You can then prompt the user to upgrade their plan or deactivate an old machine.

### Subscription Licensing

The "Pay once, use forever" model is great, but many developers are moving to subscriptions to fund ongoing development. Dodo handles this perfectly. You can link a license key to a subscription. If the subscription lapses, the license validation API will return `valid: false`, and your app can automatically lock features until the user renews. This is a powerful way to [build predictable revenue](https://dodopayments.com/blogs/build-predictable-revenue).

### Automatic Updates Gate

You can use the License API to gate access to your update server. When your app checks for a new version, it can send the license key. Your server validates the key with Dodo before serving the download link. This ensures that only paying customers get the latest features and security patches.

## Conclusion

Accepting payments for a desktop app doesn't have to be a complex engineering project. By separating the purchase flow (on your website) from the activation flow (in your app), you can create a seamless experience for your users while keeping your code clean.

Dodo Payments takes the burden of global tax compliance and license management off your shoulders. Whether you are building a small utility or a massive creative suite, our tools help you [how to sell software online](https://dodopayments.com/blogs/how-to-sell-software-online) with confidence.

By following the steps in this guide, you can have a fully functional, tax-compliant payment and licensing system running in your macOS or Windows app in a matter of hours.

## FAQ

### How do I sell a desktop app without the Mac App Store or Microsoft Store?

You can sell directly to users by creating a marketing website and using a payment processor like Dodo Payments. You provide a download link for the installer (DMG for macOS, EXE or MSI for Windows) on your site. After the user purchases a license key through your checkout, they enter it into the app to unlock full functionality. This allows you to avoid the 30% platform fee and maintain direct control over your customer data.

### How do license keys work with Dodo Payments?

When you enable license keys for a product in Dodo Payments, our system automatically generates a unique key for every successful transaction. This key is included in the automated email sent to the customer. You can then use the Dodo License API to activate, validate, and deactivate these keys from within your desktop application. The entire lifecycle is managed by Dodo, so you don't need to build your own licensing database.

### Can I limit how many devices a license key can activate?

Yes, Dodo Payments allows you to set an activation limit for each license key. For example, you can allow a single key to be used on up to three different machines. When the user attempts to activate the key on a fourth device, the API will return an error. You can also allow users to deactivate old machines through your app to free up slots for new ones.

### Should I use a subscription or one-time purchase for my desktop app?

The choice depends on your development costs and target audience. One-time purchases are popular for utility apps and are often easier for users to understand. Subscriptions are better for apps that require ongoing server costs or frequent updates. Dodo Payments supports both models and even allows you to offer a hybrid approach where users pay for a year of updates but can keep using the version they have forever.

### Does Dodo Payments handle international tax for desktop app sales?

Absolutely. Dodo Payments acts as a Merchant of Record, which means we are legally responsible for calculating, collecting, and remitting sales tax, VAT, and GST in over 220+ countries and regions. When a user from any part of the world buys your desktop app, Dodo ensures the correct tax is applied based on their location. This removes the massive administrative burden of global tax compliance from your business.

For more information on setting up your integration, check out our [License Keys documentation](https://docs.dodopayments.com/features/license-keys), [Webhook Guide](https://docs.dodopayments.com/developer-resources/webhooks/intents/webhook-events-guide), and [API Reference](https://docs.dodopayments.com/api-reference/introduction). You can also follow our [Integration Guide](https://docs.dodopayments.com/developer-resources/integration-guide) to get started today. Learn more about our [pricing](https://dodopayments.com/pricing) and how we can help you scale your software business globally.
---
- [More Payments articles](https://dodopayments.com/blogs/category/payments)
- [All articles](https://dodopayments.com/blogs)