PayPal Integration Guide

Connect your PayPal account to ExisOne to automatically generate and email license keys when customers purchase on your website.

How it works: You integrate PayPal directly on your website using PayPal's API. When a customer pays, PayPal sends a webhook to ExisOne, which generates a license key and emails it to your customer automatically.

1. Create a PayPal REST App

  1. Log into PayPal Developer Dashboard.
  2. Go to Apps & Credentials.
  3. Select Sandbox for testing (switch to Live later for production).
  4. Click Create App and give it a name.
  5. Copy your Client ID and Secret (click "Show" to reveal).

2. Configure PayPal Webhook

  1. In your PayPal app, scroll down to Webhooks and click Add Webhook.
  2. Set the Webhook URL to: https://www.exisone.com/api/paypal/webhook
  3. Select these events:
    • PAYMENT.CAPTURE.COMPLETED - Triggers license generation for one-time payments
    • BILLING.SUBSCRIPTION.ACTIVATED - Triggers license generation for new subscriptions
    • PAYMENT.SALE.COMPLETED - Triggers license generation for subscription renewals
  4. Save the webhook and copy the Webhook ID (shown in the webhook list).
Note: The Webhook ID is how ExisOne identifies your account when PayPal sends events. Each webhook has a unique ID.

3. Register Your PayPal App in ExisOne

  1. In ExisOne, go to PayPal Integration > PayPal Apps and Events.
  2. Click New App and enter:
    • Webhook ID - from step 2
    • Client ID - from step 1
    • Client Secret - from step 1
  3. Set Is Live to match your credentials (unchecked for Sandbox, checked for Live).
  4. Check Active and Default.
  5. Save the app.

ExisOne uses the Webhook ID to match incoming webhooks to your account.

4. Configure Your Product in ExisOne

For each product you sell, configure these settings on the Products page:

5. Find Your Product ID

You'll need your Product ID to include in PayPal orders. Find it on the Products page - it's displayed in the ID column.

Example: If your "Pro License" product shows ID 42, you'll use "custom_id": "42" in your PayPal order.

6. How the Payment Flow Works

Your Website                        PayPal                         ExisOne
      |                                 |                               |
      |-- Create order --------------->|                               |
      |   (using PayPal API directly)   |                               |
      |   custom_id: "42"               |                               |
      |                                 |                               |
      |   Customer approves payment     |                               |
      |                                 |                               |
      |-- Capture order -------------->|                               |
      |                                 |                               |
      |                                 |-- Webhook ------------------ >|
      |                                 |   PAYMENT.CAPTURE.COMPLETED   |
      |                                 |                               |
      |                                 |   Match app by Webhook ID --->|
      |                                 |   Extract productId from      |
      |                                 |   custom_id or item sku       |
      |                                 |                               |
      |                                 |   Generate license key        |
      |                                 |                               |
      |                                 |   Email key to customer       |
      |                                 |                               |

7. Integrate PayPal on Your Website

Use PayPal's API directly on your website. The key is to include your ExisOne productId in the order's custom_id field or item sku.

Server-Side: Create Order (Node.js Example)
const paypal = require('@paypal/checkout-server-sdk');

// Configure PayPal environment
const environment = new paypal.core.SandboxEnvironment(
    'YOUR_CLIENT_ID',
    'YOUR_CLIENT_SECRET'
);
const client = new paypal.core.PayPalHttpClient(environment);

app.post('/create-paypal-order', async (req, res) => {
    const request = new paypal.orders.OrdersCreateRequest();
    request.prefer("return=representation");
    request.requestBody({
        intent: 'CAPTURE',
        purchase_units: [{
            custom_id: '42',           // Your ExisOne Product ID - REQUIRED
            amount: {
                currency_code: 'USD',
                value: '29.99',
                breakdown: {
                    item_total: { currency_code: 'USD', value: '29.99' }
                }
            },
            items: [{
                name: 'Pro License',
                sku: '42',             // Alternative: Product ID in SKU
                quantity: '1',
                unit_amount: { currency_code: 'USD', value: '29.99' }
            }]
        }]
    });

    const order = await client.execute(request);
    res.json({ id: order.result.id });
});

app.post('/capture-paypal-order', async (req, res) => {
    const { orderID } = req.body;
    const request = new paypal.orders.OrdersCaptureRequest(orderID);
    const capture = await client.execute(request);
    res.json({ status: capture.result.status });
});
Client-Side: PayPal Buttons (JavaScript)
<div id="paypal-button-container"></div>

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>
<script>
paypal.Buttons({
    createOrder: async () => {
        const response = await fetch('/create-paypal-order', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' }
        });
        const order = await response.json();
        return order.id;
    },
    onApprove: async (data) => {
        const response = await fetch('/capture-paypal-order', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ orderID: data.orderID })
        });
        const result = await response.json();
        if (result.status === 'COMPLETED') {
            alert('Payment successful! Check your email for your license key.');
        }
    }
}).render('#paypal-button-container');
</script>
Important: The custom_id field (or item sku) must contain your ExisOne Product ID. Without it, ExisOne cannot determine which product to generate a license for.
Where to Put the Product ID (One-Time Payments)
FieldLocationDescription
custom_idpurchase_units[0].custom_idPreferred method - ExisOne Product ID
skupurchase_units[0].items[0].skuAlternative - ExisOne Product ID in item SKU
quantitypurchase_units[0].items[0].quantityNumber of licenses to generate

7b. Subscription Licenses

For subscription-based licensing (e.g., annual renewals), ExisOne generates a new license key on each billing cycle - both on initial signup and every renewal.

Important: For subscriptions, you must set the custom_id when creating the subscription. This is where ExisOne reads the Product ID from. Format: "productId" or "productId:quantity" for multiple licenses.
PayPal Subscription Setup
  1. In PayPal, create a Product under Products & Plans
  2. Create a Billing Plan for that product (e.g., $99/year)
  3. When creating subscriptions, include custom_id with your ExisOne Product ID
Server-Side: Create Subscription (Node.js Example)
const paypal = require('@paypal/checkout-server-sdk');

app.post('/create-subscription', async (req, res) => {
    const request = new paypal.subscriptions.SubscriptionsCreateRequest();
    request.requestBody({
        plan_id: 'P-XXXXXXXXXXXXXXXXXXXXXXXX',  // Your PayPal Plan ID
        custom_id: '42',                         // ExisOne Product ID - REQUIRED
        // Or for multiple licenses: '42:5' (productId:quantity)
        subscriber: {
            email_address: req.body.email
        },
        application_context: {
            return_url: 'https://yoursite.com/success',
            cancel_url: 'https://yoursite.com/cancel'
        }
    });

    const subscription = await client.execute(request);
    res.json({ id: subscription.result.id, approvalUrl: subscription.result.links.find(l => l.rel === 'approve').href });
});
How Subscription Licensing Works
Initial Subscription                          Renewals (Annual)
        |                                            |
        |-- BILLING.SUBSCRIPTION.ACTIVATED -->       |-- PAYMENT.SALE.COMPLETED ------->
        |                                            |
        |   ExisOne fetches subscription from        |   ExisOne fetches subscription
        |   PayPal API, reads custom_id              |   from PayPal, reads custom_id
        |                                            |
        |   Generates license key(s)                 |   Generates NEW license key(s)
        |   Emails to subscriber                     |   Emails to subscriber
        |                                            |
Where to Put the Product ID (Subscriptions)
FieldFormatDescription
custom_id"42"ExisOne Product ID only (1 license)
custom_id"42:5"ExisOne Product ID with quantity (5 licenses)
Tip: You can also encode quantity in the PayPal Plan name (e.g., "5-License Annual Plan") and ExisOne will parse it as a fallback.

8. Test Your Integration

  1. Make sure you're using Sandbox credentials.
  2. Trigger a purchase from your website.
  3. Log into PayPal Sandbox with a test buyer account to complete payment.
  4. Check PayPal Apps and Events in ExisOne - you should see the webhook event.
  5. Verify the license key appears under License Keys in the ExisOne dashboard.
  6. Confirm the customer received the license key email (if Auto Email is enabled).

You can also use ExisOne's built-in Test Purchase page to verify webhook connectivity before integrating with your website.

PayPal Sandbox Test Accounts

In PayPal Developer Dashboard, go to Sandbox > Accounts to find or create test buyer/seller accounts for testing.

9. Notes

Troubleshooting

Webhook not received
License not generated (one-time payments)
Subscription renewals not generating license keys
Event log

10. Setup Checklist

Before going live, verify all items are complete:

StepWhereStatus
PayPal REST app createdPayPal Developer Dashboard
Webhook created pointing to ExisOnePayPal Developer Dashboard
PayPal app registered with Webhook ID and credentialsExisOne > PayPal Apps
Product created in ExisOneExisOne > Products
Product has Auto Email enabledExisOne > Products
Email template configuredExisOne > Products > Email Template
Website integration includes productId in custom_id or skuYour website code
Test purchase completed successfully (Sandbox)Your website
Webhook received in ExisOneExisOne > PayPal Events
License key generated and emailedExisOne > License Keys

11. Go Live

  1. In PayPal Developer Dashboard, switch to Live mode.
  2. Create a new webhook pointing to https://www.exisone.com/api/paypal/webhook with live credentials.
  3. In ExisOne, add a new PayPal app with your Live credentials and Webhook ID. Check Is Live and Active.
  4. Update your website to use your Live Client ID.
  5. Make a real purchase (you can refund it) to verify the complete flow works in production.