DEV Community

Cover image for 2Checkout API: Complete Integration Guide for Payment Processing (2026)
Wanda
Wanda

Posted on • Originally published at apidog.com

2Checkout API: Complete Integration Guide for Payment Processing (2026)

TL;DR

The 2Checkout API (now Verifone) lets you programmatically process payments, manage subscriptions, and handle e-commerce transactions. It provides RESTful endpoints for orders, customers, products, and webhooks, using JSON-based authentication with API keys. This guide covers everything from setup to advanced webhook handling.

Try Apidog today


Introduction

Payment processing is critical for online businesses. A smooth integration increases revenue and unlocks global markets. The 2Checkout API (now Verifone Digital Commerce) is used by 45,000+ merchants and processes billions annually.

67% of shoppers abandon carts due to payment friction. A robust payment API integration can directly improve conversion rates.

This guide walks through a complete 2Checkout API integration: authentication, payment processing, subscription management, webhook handling, and error troubleshooting. Follow these steps to achieve a production-ready payment solution.

💡 Apidog streamlines API integration testing. Use it to test 2Checkout endpoints, validate webhook payloads, and debug authentication. Import the 2Checkout OpenAPI spec, mock responses, and share scenarios with your team.


What Is 2Checkout API?

2Checkout (now Verifone Digital Commerce) provides a RESTful API for:

  • One-time and recurring payments
  • Customer and product management
  • Order lifecycle tracking
  • Refund and dispute handling
  • Tax and compliance automation
  • Multi-currency support (100+ currencies)

Key Features

Feature Description
RESTful Design Standard HTTP methods (GET, POST, PUT, DELETE) with JSON payloads
Sandbox Environment Test payments without processing real transactions
Webhook Support Real-time notifications for order events
Tokenization Secure payment data handling without storing card details
Global Compliance PCI DSS Level 1, GDPR, PSD2, and 3D Secure 2.0

API Architecture Overview

2Checkout uses a versioned REST API:

https://api.2checkout.com/1/
https://api.2checkout.com/2/
Enter fullscreen mode Exit fullscreen mode

Version 2 is recommended for improved subscription management and webhook handling.


Getting Started: Authentication Setup

Step 1: Create Your 2Checkout Account

  1. Go to the 2Checkout (Verifone) signup page.
  2. Complete business verification (upload required documents).
  3. Wait for approval (24–48 hours typical).
  4. Access the Control Panel to retrieve API credentials.

Step 2: Retrieve API Keys

Navigate to Integrations > API Keys in your Control Panel:

  • Private API Key: For server-side authentication (keep secret).
  • Public API Key: For client-side tokenization (safe to expose).
  • Webhook Secret: For webhook signature verification.

Security: Never commit API keys to version control. Use environment variables:

# .env file
TWOCHECKOUT_PRIVATE_KEY="your_private_key_here"
TWOCHECKOUT_PUBLIC_KEY="your_public_key_here"
TWOCHECKOUT_WEBHOOK_SECRET="your_webhook_secret_here"
Enter fullscreen mode Exit fullscreen mode

Step 3: Sandbox vs Production

Environment Base URL Use Case
Sandbox https://sandbox.2checkout.com/api/ Development and testing
Production https://api.2checkout.com/ Live transactions

Use sandbox credentials for development. Switch to production keys only when ready for real payments.

Step 4: Authentication Methods

Method 1: API Key Authentication (Recommended)

Add your private key to the request header:

const response = await fetch('https://api.2checkout.com/1/orders', {
  method: 'GET',
  headers: {
    'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  }
});
Enter fullscreen mode Exit fullscreen mode

Method 2: HMAC Signature Authentication

Sign requests with HMAC-SHA256 for enhanced security:

const crypto = require('crypto');

function generateSignature(payload, privateKey) {
  const hash = crypto
    .createHmac('sha256', privateKey)
    .update(JSON.stringify(payload))
    .digest('hex');
  return hash;
}

// Usage
const payload = { order_id: '12345', amount: 99.99 };
const signature = generateSignature(payload, privateKey);

const response = await fetch('https://api.2checkout.com/1/orders', {
  method: 'POST',
  headers: {
    'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
    'X-Signature': signature,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(payload)
});
Enter fullscreen mode Exit fullscreen mode

2Checkout API Authentication Flow


Processing Payments: Core Endpoints

Creating a One-Time Order

Create a single payment via the /orders endpoint:

const createOrder = async (customerData, productData) => {
  const payload = {
    currency: 'USD',
    customer: {
      email: customerData.email,
      first_name: customerData.firstName,
      last_name: customerData.lastName,
      phone: customerData.phone,
      billing_address: {
        address1: customerData.address,
        city: customerData.city,
        state: customerData.state,
        zip: customerData.zip,
        country: customerData.country
      }
    },
    items: [
      {
        name: productData.name,
        quantity: productData.quantity,
        price: productData.price,
        product_code: productData.sku
      }
    ],
    payment_method: {
      type: 'card',
      card_token: customerData.cardToken // From client-side tokenization
    }
  };

  const response = await fetch('https://api.2checkout.com/1/orders', {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Expected Response

{
  "order_id": "ORD-2026-001234",
  "status": "approved",
  "amount": 99.99,
  "currency": "USD",
  "customer_id": "CUST-789456",
  "transaction_id": "TXN-9876543210",
  "created_at": "2026-03-20T10:30:00Z"
}
Enter fullscreen mode Exit fullscreen mode

Handling Payment Errors

Always implement granular error handling:

try {
  const result = await createOrder(customer, product);

  if (result.error) {
    switch (result.error.code) {
      case 'CARD_DECLINED':
        // Prompt for a different card
        break;
      case 'INSUFFICIENT_FUNDS':
        // Show an appropriate message
        break;
      case 'INVALID_CVV':
        // Request CVV re-entry
        break;
      default:
        // Log and show generic error
        console.error('Payment failed:', result.error);
    }
  }
} catch (error) {
  // Network or server error
  console.error('API request failed:', error);
}
Enter fullscreen mode Exit fullscreen mode

Common Error Codes

Error Code HTTP Status Description Resolution
CARD_DECLINED 402 Card was declined Ask for different payment
INVALID_CARD 400 Invalid card number Validate card input
EXPIRED_CARD 400 Card has expired Request updated expiration
INVALID_CVV 400 CVV verification failed Re-request CVV
INSUFFICIENT_FUNDS 402 Not enough funds Suggest alternative payment
DUPLICATE_ORDER 409 Order already processed Check for duplicates
INVALID_CURRENCY 400 Unsupported currency Verify currency code
API_KEY_INVALID 401 Authentication failed Check API key

Customer Management

Leverage the customer API for subscription businesses or repeat purchases.

Creating a Customer

const createCustomer = async (customerData) => {
  const payload = {
    email: customerData.email,
    first_name: customerData.firstName,
    last_name: customerData.lastName,
    phone: customerData.phone,
    company: customerData.company,
    billing_address: {
      address1: customerData.address,
      address2: customerData.address2 || '',
      city: customerData.city,
      state: customerData.state,
      zip: customerData.zip,
      country: customerData.country
    },
    shipping_address: customerData.shippingAddress || null,
    tax_exempt: false,
    language: 'en'
  };

  const response = await fetch('https://api.2checkout.com/1/customers', {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Customer Response Example

{
  "customer_id": "CUST-2026-123456",
  "email": "john.doe@example.com",
  "first_name": "John",
  "last_name": "Doe",
  "created_at": "2026-03-20T10:00:00Z",
  "updated_at": "2026-03-20T10:00:00Z",
  "payment_methods": [],
  "subscriptions": [],
  "order_history": []
}
Enter fullscreen mode Exit fullscreen mode

Retrieving Customer Details

const getCustomer = async (customerId) => {
  const response = await fetch(
    `https://api.2checkout.com/1/customers/${customerId}`,
    {
      method: 'GET',
      headers: {
        'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
        'Content-Type': 'application/json'
      }
    }
  );

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Updating Customer Information

const updateCustomer = async (customerId, updates) => {
  const response = await fetch(
    `https://api.2checkout.com/1/customers/${customerId}`,
    {
      method: 'PUT',
      headers: {
        'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updates)
    }
  );

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Deleting a Customer

const deleteCustomer = async (customerId) => {
  const response = await fetch(
    `https://api.2checkout.com/1/customers/${customerId}`,
    {
      method: 'DELETE',
      headers: {
        'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY
      }
    }
  );

  return response.status === 204;
};
Enter fullscreen mode Exit fullscreen mode

Note: Deleting customers with active subscriptions or balances will fail. Cancel subscriptions first.


Advanced Integration Patterns

Idempotency for Safe Retries

Support idempotent requests to avoid duplicate charges:

const createIdempotentOrder = async (payload, idempotencyKey) => {
  const response = await fetch('https://api.2checkout.com/1/orders', {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
      'Content-Type': 'application/json',
      'X-Idempotency-Key': idempotencyKey // Unique per order
    },
    body: JSON.stringify(payload)
  });

  return await response.json();
};

// Example key: store this in your DB
const idempotencyKey = `order_${userId}_${Date.now()}`;
Enter fullscreen mode Exit fullscreen mode

Handling 3D Secure 2.0 (EU Compliance)

3D Secure 2.0 is required for many EU payments:

const createOrderWith3DS = async (payload) => {
  const response = await fetch('https://api.2checkout.com/1/orders', {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      ...payload,
      three_ds: {
        enabled: true,
        challenge_required: 'preferred', // or 'mandatory'
        notification_url: 'https://your-site.com/3ds-callback'
      }
    })
  });

  const result = await response.json();

  // Redirect customer for authentication if needed
  if (result.three_ds_redirect_url) {
    res.redirect(result.three_ds_redirect_url);
  }

  return result;
};
Enter fullscreen mode Exit fullscreen mode

Multi-Currency Pricing

Show localized prices while settling in your base currency:

const getLocalizedPrice = async (basePrice, targetCurrency) => {
  const response = await fetch(
    `https://api.2checkout.com/1/rates?from=USD&to=${targetCurrency}`,
    {
      headers: {
        'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY
      }
    }
  );

  const rates = await response.json();
  return basePrice * rates.rate;
};

// Usage
const eurPrice = await getLocalizedPrice(99.99, 'EUR');
console.log(`Price: EUR ${eurPrice.toFixed(2)}`);
Enter fullscreen mode Exit fullscreen mode

Proration for Subscription Upgrades

Charge customers the prorated difference on plan upgrade:

const upgradeSubscription = async (subscriptionId, newPlanId) => {
  const response = await fetch(
    `https://api.2checkout.com/1/subscriptions/${subscriptionId}/upgrade`,
    {
      method: 'POST',
      headers: {
        'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        plan_id: newPlanId,
        proration: 'immediate',
        invoice_proration: true
      })
    }
  );

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Troubleshooting Common Issues

Webhooks Not Arriving

Symptoms: Orders process, but your system doesn't update.

Check:

// Review webhook delivery logs in the 2Checkout dashboard
// Look for failed deliveries or non-200 responses
Enter fullscreen mode Exit fullscreen mode

Solutions:

  1. Ensure endpoint returns 200 OK within 5 seconds.
  2. Check SSL certificate validity (HTTPS required).
  3. Whitelist 2Checkout IPs in your firewall.
  4. Review signature verification logic.
  5. Test with webhook simulator before production.

Test Payments Fail in Sandbox

Symptoms: All test cards are declined in sandbox.

Solutions:

  1. Use sandbox API keys.
  2. Verify base URL: https://sandbox.2checkout.com/api/
  3. Use correct test card numbers.
  4. Check sandbox account status (may expire after inactivity).

Subscription Renewals Silent Fail

Symptoms: Subscriptions active, but renewals not processed.

Check:

// Query subscription payment history
const history = await fetch(
  `https://api.2checkout.com/1/subscriptions/${subId}/payments`,
  { headers: { 'X-Api-Key': privateKey } }
);
Enter fullscreen mode Exit fullscreen mode

Solutions:

  1. Check payment method expiration.
  2. Review dunning settings.
  3. Verify webhook delivery for subscription.payment_failed.
  4. Confirm auto_renew flag is enabled.

Currency Conversion Discrepancies

Symptoms: Charged amount differs from expected.

Cause: 2Checkout uses daily rates.

Solution:

  • Display “approximate” conversion with disclaimer.
  • Lock rates at cart creation for 15 minutes.
  • Store transactions in customer’s local currency.

AVS (Address Verification) Failures

Symptoms: Legitimate cards decline due to address mismatch.

Solutions:

  1. Use address autocomplete (Google Places, Lob).
  2. Require ZIP/postal code at checkout.
  3. Implement soft AVS (warn instead of decline).
  4. Allow customer to update billing address.

Subscription Management

Use these endpoints to handle recurring billing.

Creating a Subscription

const createSubscription = async (customerId, planId) => {
  const payload = {
    customer_id: customerId,
    plan_id: planId,
    start_date: new Date().toISOString(),
    billing_cycle: 'monthly', // or 'annual', 'weekly'
    payment_method: {
      type: 'card',
      card_token: 'tok_card_tokenized'
    },
    options: {
      trial_days: 14,
      auto_renew: true
    }
  };

  const response = await fetch('https://api.2checkout.com/1/subscriptions', {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Subscription Response Example

{
  "subscription_id": "SUB-2026-567890",
  "status": "active",
  "plan_id": "PLAN-PREMIUM-MONTHLY",
  "customer_id": "CUST-789456",
  "current_period_start": "2026-03-20T00:00:00Z",
  "current_period_end": "2026-04-20T00:00:00Z",
  "trial_end": "2026-04-03T00:00:00Z",
  "amount": 29.99,
  "currency": "USD"
}
Enter fullscreen mode Exit fullscreen mode

Updating a Subscription

Update plan, payment method, or quantity:

const updateSubscription = async (subscriptionId, updates) => {
  const payload = {
    ...updates
    // Examples:
    // plan_id: 'PLAN-ENTERPRISE-MONTHLY',
    // quantity: 5,
    // payment_method: { card_token: 'new_token' }
  };

  const response = await fetch(
    `https://api.2checkout.com/1/subscriptions/${subscriptionId}`,
    {
      method: 'PUT',
      headers: {
        'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    }
  );

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Canceling a Subscription

const cancelSubscription = async (subscriptionId, reason = '') => {
  const payload = {
    cancel_at_period_end: false, // true = cancel after current period, false = immediate
    reason: reason
  };

  const response = await fetch(
    `https://api.2checkout.com/1/subscriptions/${subscriptionId}/cancel`,
    {
      method: 'POST',
      headers: {
        'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    }
  );

  return await response.json();
};
Enter fullscreen mode Exit fullscreen mode

Webhook Integration: Real-Time Event Handling

Webhooks notify your system of payment events without polling. Essential for subscription renewals, failed payments, and refunds.

Step 1: Configure Webhook Endpoint

In your 2Checkout Control Panel:

  1. Go to Integrations > Webhooks
  2. Add your HTTPS endpoint URL
  3. Select events to subscribe to
  4. Save and note your Webhook Secret

Step 2: Create Webhook Handler

const express = require('express');
const crypto = require('crypto');
const app = express();

app.post('/webhooks/2checkout', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const payload = req.body;

  // Verify webhook signature
  const isValid = verifyWebhookSignature(payload, signature, process.env.TWOCHECKOUT_WEBHOOK_SECRET);

  if (!isValid) {
    console.error('Invalid webhook signature');
    return res.status(401).send('Unauthorized');
  }

  const event = JSON.parse(payload.toString());

  // Route to appropriate handler
  switch (event.type) {
    case 'order.created':
      await handleOrderCreated(event.data);
      break;
    case 'order.approved':
      await handleOrderApproved(event.data);
      break;
    case 'order.declined':
      await handleOrderDeclined(event.data);
      break;
    case 'subscription.created':
      await handleSubscriptionCreated(event.data);
      break;
    case 'subscription.renewed':
      await handleSubscriptionRenewed(event.data);
      break;
    case 'subscription.cancelled':
      await handleSubscriptionCancelled(event.data);
      break;
    case 'refund.processed':
      await handleRefundProcessed(event.data);
      break;
    default:
      console.log('Unhandled event type:', event.type);
  }

  res.status(200).send('OK');
});

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature, 'hex'),
    Buffer.from(expectedSignature, 'hex')
  );
}
Enter fullscreen mode Exit fullscreen mode

Critical Webhook Events

Event Type Trigger Action Required
order.created New order placed Send confirmation email
order.approved Payment successful Fulfill order, grant access
order.declined Payment failed Notify customer, retry
subscription.renewed Recurring payment Extend access period
subscription.payment_failed Renewal failed Dunning sequence
subscription.cancelled Customer canceled Revoke access at end
refund.processed Refund issued Update user balance
chargeback.received Dispute filed Gather evidence

Webhook Best Practices

  1. Always verify signatures – Prevent spoofing.
  2. Return 200 OK quickly – 2Checkout retries on non-200.
  3. Process asynchronously – Queue background jobs.
  4. Implement idempotency – Handle duplicate deliveries.
  5. Log all events – For debugging and audit trails.

Testing Your Integration

Using the Sandbox Environment

Test without real charges:

// Use sandbox base URL
const BASE_URL = 'https://sandbox.2checkout.com/api/1';

// Test card numbers
const TEST_CARDS = {
  APPROVED: '4111111111111111',
  DECLINED: '4000000000000002',
  INSUFFICIENT_FUNDS: '4000000000009995',
  EXPIRED_CARD: '4000000000000069'
};

// Test addresses
const TEST_ADDRESS = {
  country: 'US',
  zip: '90210' // Triggers AVS checks
};
Enter fullscreen mode Exit fullscreen mode

Testing Webhooks Locally

Expose your local server using ngrok:

# Install ngrok
npm install -g ngrok

# Start your server on port 3000
node server.js

# Expose to internet
ngrok http 3000

# Copy the ngrok URL to 2Checkout webhook settings
Enter fullscreen mode Exit fullscreen mode

Apidog for API Testing

Apidog streamlines 2Checkout API testing:

  1. Import OpenAPI Spec – Load 2Checkout’s API definition.
  2. Create Test Scenarios – Build collections for each endpoint.
  3. Mock Responses – Test workflows without calling the API.
  4. Validate Webhooks – Inspect payloads and signatures.
  5. Share with Team – Collaborate on integration testing.

Set up environment variables for sandbox and production keys, then switch contexts with one click.


Production Deployment Checklist

Before going live, verify:

  • [ ] Switch from sandbox to production API keys
  • [ ] Update base URL to https://api.2checkout.com/
  • [ ] Enable webhook signature verification
  • [ ] Monitor failed payments
  • [ ] Configure retry logic for failures
  • [ ] Test refund and chargeback flows
  • [ ] Ensure PCI DSS compliance (use tokenization)
  • [ ] Enable 3D Secure 2.0 for EU customers
  • [ ] Set up logging/audit trails
  • [ ] Create runbook for payment issues

Monitoring and Alerting

Track key metrics and alert on anomalies:

// Example: Payment success rate
const successRate = approvedOrders / totalOrders * 100;

if (successRate < 95) {
  sendAlert('Payment success rate dropped below 95%');
}

// Error tracking
const errorBreakdown = errors.reduce((acc, err) => {
  acc[err.code] = (acc[err.code] || 0) + 1;
  return acc;
}, {});

if (errorBreakdown['CARD_DECLINED'] > threshold) {
  sendAlert('Spike in card declines detected');
}
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

E-commerce Store Integration

A fashion retailer integrated 2Checkout for global payments:

  • Supported 100+ currencies
  • Reduced cart abandonment by 23%
  • Automated EU VAT compliance
  • Processed $2M+ in first year

Implementation: Started with hosted checkout, then migrated to direct API for custom UX.

SaaS Subscription Business

A SaaS company managed 5,000+ subscriptions via 2Checkout:

  • Supported proration for upgrades
  • Automated dunning for failed payments
  • Reduced churn by 15% with smart retries

Key: Webhook-driven access control—extend access on subscription.renewed, revoke on subscription.cancelled.


Conclusion

The 2Checkout API provides the tools you need for robust payment processing and subscription management. To deploy successfully:

  • Use the sandbox for all development and testing
  • Implement HMAC signature verification on webhooks
  • Handle errors with specific code logic
  • Test subscription flows (trial, renewal, cancellation)
  • Monitor payment metrics in production
  • Use Apidog to speed up API testing and team collaboration

FAQ Section

What is the 2Checkout API?

The 2Checkout API (now Verifone) is a RESTful interface for processing payments, managing subscriptions, handling refunds, and automating e-commerce transactions. It supports JSON payloads, HMAC authentication, and real-time webhooks.

Is 2Checkout the same as Verifone?

Yes. 2Checkout was acquired by Verifone in 2020 and rebranded as Verifone Digital Commerce. API endpoints and features remain unchanged.

How do I get my 2Checkout API key?

Log into your 2Checkout Control Panel, navigate to Integrations > API Keys, and generate a new key. You get a private key (server-side) and public key (for tokenization).

Does 2Checkout have a sandbox environment?

Yes. Use https://sandbox.2checkout.com/api/ for testing. Create a separate sandbox account for test API keys and transactions.

What payment methods does 2Checkout support?

2Checkout supports credit cards (Visa, Mastercard, Amex, Discover), PayPal, Apple Pay, Google Pay, bank transfers, and local methods in 100+ countries.

How do I handle webhooks securely?

Always verify the X-Webhook-Signature header using HMAC-SHA256 with your webhook secret. Process events asynchronously and return 200 OK immediately.

What happens when a subscription payment fails?

2Checkout sends a subscription.payment_failed webhook. Implement retry logic (e.g., 3 attempts over 7 days). If all retries fail, a subscription.cancelled webhook is sent.

Is 2Checkout PCI DSS compliant?

Yes, 2Checkout is PCI DSS Level 1 certified. Use client-side tokenization to avoid handling raw card data.

Can I test subscriptions in sandbox?

Yes. Sandbox supports full subscription lifecycle testing: trials, renewals, upgrades, downgrades, and cancellations. Use test card 4111111111111111.

How do I handle refunds via API?

Send a POST to /refunds with the order ID and refund amount. 2Checkout processes partial or full refunds and sends a refund.processed webhook on completion.


Top comments (0)