Payment Gateway - Partner Integration Guide

Complete documentation for integrating multi-gateway payment solution (Cards + Meal Vouchers)

Quick Start

Get started in 3 steps:
  1. Download Postman collection and YAML spec
  2. Configure your notification webhook URL
  3. Integrate the Wrapper API (4 endpoints only)

PayGlobe.js - JavaScript Library

Simplified Integration: Use our JavaScript library for easy client-side integration with modern payment gateways

1. Include the Library

Include PayGlobe.js HTML โ–ผ
<!-- Include PayGlobe.js in your HTML -->
<script src="https://api.payglobe.it/paymentgw/js/payglobe.js"></script>

2. Initialize with Your API Key

Initialize PayGlobe JS โ–ผ
// Initialize PayGlobe with your publishable key
const payglobe = PayGlobe('pk_test_PayGlobe123456789TestPublishable');

3. Create a Payment

Create Payment JS โ–ผ
// Create a new payment
const payment = await payglobe.payments.create({
    amount: 50.00,
    email: 'customer@example.com', // Customer email for payment receipt
    description: 'Order #12345' // optional
});

console.log('Payment created:', payment.id);
๐Ÿ“ง Email Parameter: The customer's email address is used to send payment confirmation receipts. This field is recommended for a better customer experience. If not provided, a default email will be used.

4. Redirect to Checkout

Redirect to Checkout JS โ–ผ
// Option A: Full page redirect
payglobe.redirectToCheckout({
    paymentId: payment.id
});

// Option B: Load in iframe
payglobe.redirectToCheckout({
    paymentId: payment.id,
    element: '#payment-container' // CSS selector for iframe container
});

5. Check Payment Status

Check Payment Status JS โ–ผ
// Retrieve payment status
const status = await payglobe.payments.retrieve(payment.id);

console.log('Payment status:', status.status);
console.log('Amount:', status.totalAmount);
console.log('Gateway Payment ID:', status.paymentId);
console.log('Voucher Amount:', status.voucherAmount);

Complete Example

Full HTML Example HTML โ–ผ
<!DOCTYPE html>
<html>
<head>
    <title>PayGlobe Checkout</title>
    <script src="https://api.payglobe.it/paymentgw/js/payglobe.js"></script>
</head>
<body>
    <button id="checkout-button">Pay 50.00 EUR</button>
    <div id="payment-container"></div>

    <script>
        const payglobe = PayGlobe('pk_test_PayGlobe123456789TestPublishable');

        document.getElementById('checkout-button').addEventListener('click', async () => {
            try {
                // Create payment
                const payment = await payglobe.payments.create({
                    amount: 50.00,
                    email: 'customer@example.com', // Customer email for receipt
                    description: 'Order #12345'     // Your internal order number
                });

                // Redirect to checkout (in iframe)
                await payglobe.redirectToCheckout({
                    paymentId: payment.id,
                    element: '#payment-container'
                });
            } catch (error) {
                console.error('Payment error:', error);
                alert('Payment failed: ' + error.message);
            }
        });
    </script>
</body>
</html>
Note: PayGlobe.js handles all API communication and error handling automatically. You only need your publishable key (starts with pk_test_ or pk_live_).
Try the Live Example

See the above code in action with a working demo:

Open Live Demo โ†’

This example demonstrates a simple payment flow using PayGlobe.js with a working payment button.

High-Level Architecture

PREAUTH + CAPTURE with Meal Vouchers
Payment Flow (5 Steps)
1. PREAUTHORIZATION
Your System โ†’ Gateway โ†’ Card Processor
Preauthorize full amount on card (hold funds)
2. USER CHOICE
Customer decides:
โ€ข Pay with card only
โ€ข Use meal vouchers (partial/full)
3. VOUCHER PROCESSING Optional
Gateway โ†’ Voucher Provider
VALIDATE โ†’ SPEND โ†’ NOTIFY
4. FINALIZATION
Gateway โ†’ Card Processor:
โ€ข No vouchers: Capture full amount
โ€ข Partial vouchers: Capture difference
โ€ข Full vouchers: Void preauth
5. NOTIFICATION
Gateway โ†’ Your Webhook
JSON with card + voucher details
โœ“ Best for: Restaurants, food delivery, meal voucher acceptance
SALE DIRECT Fast Checkout
Payment Flow (3 Steps)
1. AUTHORIZATION + CAPTURE
Your System โ†’ Gateway โ†’ Card Processor
Single call: Auth + Capture in one step
2. USER CHOICE
Not applicable - no voucher option
3. VOUCHER PROCESSING
Not applicable - card only
4. FINALIZATION
Already captured in step 1
2. NOTIFICATION
Gateway โ†’ Your Webhook
JSON with payment details
โœ“ Best for: E-commerce, subscriptions, fast checkout
Feature PREAUTH + CAPTURE SALE DIRECT
Steps 5 steps (complex flow) 2-3 steps (simple flow)
Meal Vouchers โœ… Supported โŒ Not available
Card Operation Preauth โ†’ Capture/Void Single Sale (Auth+Capture)
User Interaction Voucher choice page Direct payment
Settlement After capture Immediate
Payment Mode Config PREAUTH_VOUCHER_CAPTURE SALE_DIRECT

Integration Flow

Step 1: Initialize Payment

POST/api/payment/init

{
  "amount": 150.00,
  "notifyUrl": "https://yourserver.com/api/igfs-callback",
  "errorUrl": "https://yourserver.com/payment/error",
  "callbackUrl": "https://yourserver.com/payment/{transactionId}/voucher-choice"
}

Response:
{
  "success": true,
  "transactionId": "abc-123-def-456",
  "totalAmount": 150.00,
  "redirectUrl": "https://paymentpage.igfs.payglobe.com?paymentID=XYZ",
  "igfs": {
    "paymentId": "XYZ",
    "status": "PENDING"
  }
}

Step 2: Get Transaction Info

GET/api/payment/transaction/{transactionId}

Response:
{
  "success": true,
  "transactionId": "abc-123-def-456",
  "status": "CARD_PREAUTH_SUCCESS",
  "cardGateway": {
    "paymentId": "XYZ",
    "preauthorizedAmount": 150.00,
    "status": "SUCCESS"
  },
  "breakdown": {
    "cardAmount": 150.00,
    "voucherAmount": 0.00,
    "paymentMethod": "CARD_ONLY"
  }
}
Automatic Process
After Step 1, the system automatically handles:
  • Card Preauthorization (via configured payment gateway)
  • Voucher selection page for the customer
  • Meal voucher processing (if customer enters OTP)
  • Final capture on card (total amount or difference)
  • Notification to your webhook with complete details

For advanced integrations requiring granular control, use the Direct API endpoints.

Note: Direct API requires managing transaction state yourself. Use Wrapper API unless you need specific control.

See Postman collection for complete Direct API examples.

Webhook Notifications (HMAC Signature)

PayGlobe sends server-to-server webhooks to notify you of payment events using HMAC-SHA256 signatures for security.

Self-Service Configuration: Configure your webhook URL in the Merchant Dashboard and receive a unique webhookSecret (e.g., whsec_test_...) for signature verification.
Step 1: Configure Webhook in Merchant Dashboard
  1. Go to Merchant Login and authenticate with your API key
  2. In the Webhook Configuration section, enter your webhook URL (e.g., https://yourdomain.com/api/payment-webhook)
  3. Copy the Webhook Secret (shown once, format: whsec_test_abc123...)
  4. Save the secret in your backend environment variables
Step 2: Verify HMAC Signature (Java Example)
// Receive webhook
String signature = request.getHeader("X-PayGlobe-Signature");
String rawBody = request.getBody(); // RAW JSON string

// Verify signature with your webhook secret
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(webhookSecret.getBytes(), "HmacSHA256");
mac.init(secretKey);
byte[] hash = mac.doFinal(rawBody.getBytes());
String expectedSignature = Base64.getEncoder().encodeToString(hash);

if (expectedSignature.equals(signature)) {
    // โœ… Webhook authentic - process payment
    PaymentNotification payment = objectMapper.readValue(rawBody, PaymentNotification.class);
    System.out.println("Payment received: " + payment.transactionId);
} else {
    // โŒ Invalid signature - reject
    return Response.status(401).entity("Invalid signature").build();
}
Step 3: Verify HMAC Signature (Node.js Example)
const crypto = require('crypto');

app.post('/api/payment-webhook', express.raw({type: 'application/json'}), (req, res) => {
    const signature = req.headers['x-payglobe-signature'];
    const rawBody = req.body.toString(); // RAW body string

    // Verify signature
    const hmac = crypto.createHmac('sha256', process.env.PAYGLOBE_WEBHOOK_SECRET);
    hmac.update(rawBody);
    const expectedSignature = hmac.digest('base64');

    if (expectedSignature !== signature) {
        return res.status(401).send('Invalid signature');
    }

    // โœ… Webhook verified - process payment
    const payment = JSON.parse(rawBody);
    console.log('Payment received:', payment.transactionId);

    res.status(200).send('OK');
});
Webhook Payload Example:
POSThttps://yourdomain.com/api/payment-webhook

Headers:
  X-PayGlobe-Signature: Kx7j9mP4vR2nQ8sT... (HMAC-SHA256 signature)
  Content-Type: application/json

{
  "transactionId": "TXN_20251107_123456",
  "totalAmount": 150.00,
  "cardAmount": 100.00,
  "voucherAmount": 50.00,
  "paymentMethod": "CARD_AND_VOUCHER",
  "status": "SUCCESS",
  "sessionStart": "2025-11-07T10:00:00Z",
  "sessionEnd": "2025-11-07T10:05:23Z",
  "sessionDurationSeconds": 323,
  "vouchersUsed": 1,
  "cardGatewayDetails": {
    "paymentId": "PAY_789",
    "transactionId": "IGFS_123456789",
    "operationType": "CAPTURE",
    "preauthorizedAmount": 150.00,
    "capturedAmount": 100.00,
    "responseCode": "00",
    "responseMessage": "Transaction approved"
  },
  "voucherDetails": {
    "serialNumber": "2189CA1L7823",
    "operationNumber": "OP123456",
    "spentAmount": 50.00,
    "responseCode": "000",
    "responseMessage": "Transaction OK"
  },
  "createdAt": "2025-11-07T10:00:00Z",
  "completedAt": "2025-11-07T10:05:23Z"
}
โš ๏ธ Important:
  • Always verify the signature before processing webhooks
  • Use the RAW request body for signature verification (not parsed JSON)
  • Store webhookSecret securely (environment variable, secrets manager)
  • Return 200 OK quickly; process payment asynchronously if needed
  • Webhooks are sent for: PREAUTH success/fail, CAPTURE success/fail, VOID, Voucher processing
Testing Webhooks:

Use webhook.site or ngrok to test webhook delivery:

  1. Go to webhook.site and copy unique URL
  2. Configure this URL as webhook in Admin Panel
  3. Copy webhook secret shown
  4. Make a test payment
  5. Verify webhook received with X-PayGlobe-Signature header

Stripe Webhook Compatibility

100% Stripe-Compatible Webhooks

PayGlobe webhooks follow Stripe's Event object structure, allowing you to reuse existing Stripe webhook code and libraries without modifications.

Why Stripe-Compatible?
  • Standard Format: Same JSON structure as Stripe webhook events
  • Event Types: Uses Stripe naming conventions (payment_intent.succeeded, payment_intent.payment_failed, etc.)
  • Drop-in Replacement: Works with existing Stripe webhook libraries (Node.js stripe, Python stripe, etc.)
  • Enhanced Data: Includes additional PayGlobe features like voucher details and multi-gateway support
Webhook Event Structure:

PayGlobe wraps payment data in a Stripe-compatible Event object:

{
  "id": "evt_1a2b3c4d5e6f7g8h9i0j",          // Unique event ID (evt_...)
  "object": "event",                         // Always "event"
  "api_version": "2023-10-16",               // API version
  "created": 1699372800,                     // Unix timestamp
  "type": "payment_intent.succeeded",        // Event type
  "livemode": false,                         // Test/live mode
  "pending_webhooks": 0,                     // Delivery queue count
  "data": {
    "object": {
      // Your payment data here (PaymentNotificationDto)
      "transactionId": "TXN_20251107_123456",
      "totalAmount": 150.00,
      "cardAmount": 100.00,
      "voucherAmount": 50.00,
      "paymentMethod": "CARD_AND_VOUCHER",
      "status": "SUCCESS",
      "cardGatewayDetails": { ... },
      "voucherDetails": { ... }
    }
  },
  "request": null                            // Null for automatic events
}
Event Types:
Event Type When Triggered Status
payment_intent.succeeded Payment completed successfully Active
payment_intent.payment_failed Payment failed (preauth/capture/voucher failed) Active
payment_intent.processing Payment in progress Active
charge.refunded Refund processed (full or partial) Active
checkout.session.completed Checkout session completed (payment page closed) Active
Using Stripe Libraries (Node.js Example):
const stripe = require('stripe');

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
    const sig = req.headers['stripe-signature'] || req.headers['x-payglobe-signature'];

    let event;
    try {
        // Works with Stripe's constructEvent method!
        event = stripe.webhooks.constructEvent(
            req.body,
            sig,
            process.env.WEBHOOK_SECRET  // whsec_test_...
        );
    } catch (err) {
        return res.status(400).send(`Webhook Error: ${err.message}`);
    }

    // Handle event types
    switch (event.type) {
        case 'payment_intent.succeeded':
            const payment = event.data.object;
            console.log('Payment succeeded:', payment.transactionId);
            console.log('Card amount:', payment.cardAmount);
            console.log('Voucher amount:', payment.voucherAmount);
            break;

        case 'payment_intent.payment_failed':
            console.log('Payment failed:', event.data.object);
            break;

        case 'charge.refunded':
            const refund = event.data.object;
            console.log('Refund processed:', refund.transactionId);
            console.log('Refund amount:', refund.refundAmount);
            break;

        case 'checkout.session.completed':
            console.log('Checkout completed:', event.data.object);
            break;

        default:
            console.log(`Unhandled event type: ${event.type}`);
    }

    res.status(200).send('OK');
});
Using Stripe Libraries (Python Example):
import stripe

@app.route('/webhook', methods=['POST'])
def webhook():
    payload = request.get_data()
    sig_header = request.headers.get('Stripe-Signature') or \
                 request.headers.get('X-PayGlobe-Signature')

    try:
        # Works with Stripe's construct_event method!
        event = stripe.Webhook.construct_event(
            payload, sig_header, webhook_secret
        )
    except ValueError as e:
        return 'Invalid payload', 400
    except stripe.error.SignatureVerificationError as e:
        return 'Invalid signature', 400

    # Handle event
    if event['type'] == 'payment_intent.succeeded':
        payment = event['data']['object']
        print(f"Payment succeeded: {payment['transactionId']}")
        print(f"Card: {payment['cardAmount']}, Voucher: {payment['voucherAmount']}")

    elif event['type'] == 'payment_intent.payment_failed':
        print(f"Payment failed: {event['data']['object']}")

    elif event['type'] == 'charge.refunded':
        refund = event['data']['object']
        print(f"Refund processed: {refund['transactionId']}")
        print(f"Refund amount: {refund.get('refundAmount', 0)}")

    elif event['type'] == 'checkout.session.completed':
        print(f"Checkout completed: {event['data']['object']}")

    return '', 200
Signature Headers:

PayGlobe sends both signature headers for maximum compatibility:

  • X-PayGlobe-Signature - PayGlobe standard header
  • Stripe-Signature - Stripe-compatible header (same value)

This allows Stripe libraries to work without modifications!

PayGlobe Advantages Over Stripe:
Feature Stripe PayGlobe
Webhook Format Event object Same Event object
Signature Verification HMAC-SHA256 HMAC-SHA256 (same)
Library Compatibility Stripe libraries only Works with Stripe libraries
Voucher Support None Yes (Assiopay/Monni)
Multi-Gateway Stripe only IGFS, Stripe, Nexi, Worldline, etc.
Detailed Gateway Info Limited Full details (cardGatewayDetails, voucherDetails)
Automatic Retries Limited attempts 10 attempts, 5 min intervals
Delivery Tracking Basic dashboard Full audit trail in database
Migration from Stripe:

If you're migrating from Stripe, your existing webhook code will work with PayGlobe with minimal changes:

  1. Replace STRIPE_WEBHOOK_SECRET with PayGlobe's webhookSecret
  2. Update webhook URL in your configuration
  3. That's it! Your code continues to work.

Merchant Configuration & Onboarding

Managed Service

PayGlobe provides API keys and manages all backend configurations for you. You don't need to access any admin panel.

How It Works:
  1. Contact PayGlobe to open a merchant account
  2. Provide your business details and integration requirements
  3. PayGlobe configures all payment gateway credentials (IGFS, Stripe, Assiopay, etc.) on your behalf
  4. Receive your API keys:
    • pk_test_... - Publishable key (safe for frontend)
    • sk_test_... - Secret key (backend only)
  5. Configure your webhook via Merchant Dashboard (self-service)
  6. Start accepting payments using our APIs
Admin Panel Access: The Admin Panel is exclusively for PayGlobe internal use to configure merchant accounts, gateway credentials, and system settings. Merchants manage their own webhooks and view transactions through the Merchant Dashboard.
Need Help? Contact PayGlobe support at support@payglobe.it for account setup, configuration changes, or technical assistance.

Error Handling

Error Type Status Action
Card Preauth Failed CARD_PREAUTH_FAILED Inform user, retry or cancel
Voucher Invalid VOUCHER_FAILED Allow retry with different voucher or proceed without
Capture Failed CARD_CAPTURE_FAILED Contact support, transaction will auto-rollback
Transaction Timeout FAILED Check status, may need manual intervention

API Endpoints & Authentication

Authentication with API Keys

๐Ÿ” API Key Authentication
All API requests require authentication using API keys. You will receive two keys:
  • Publishable Key (pk_test_xxx or pk_live_xxx): Safe to use in frontend code
  • Secret Key (sk_test_xxx or sk_live_xxx): Must be kept secret, use only on your server
How to Authenticate
Include API key in Authorization header:

Authorization: Bearer pk_test_PayGlobe123456789TestPublishable

Example with JavaScript:

const response = await fetch('https://api.payglobe.it/paymentgw/api/payment/initiate', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer pk_test_PayGlobe123456789TestPublishable'
    },
    body: JSON.stringify({
        amount: 150.00,
        email: 'customer@example.com',
        description: 'Order #12345'
    })
});

Example with cURL:

curl -X POST https://api.payglobe.it/paymentgw/api/payment/initiate \
  -H "Authorization: Bearer pk_test_PayGlobe123456789TestPublishable" \
  -H "Content-Type: application/json" \
  -d '{"amount": 150.00, "email": "customer@example.com", "description": "Order #12345"}'
Test Keys: Use test keys (pk_test_*) for development. No real charges will be made. Contact support@payglobe.com to receive your API keys.

Production Environment

  • Base URL: https://api.payglobe.it/paymentgw
  • Protocol: HTTPS only (TLS 1.2+)
  • Content-Type: application/json
Testing
  • Test Cards: Use test merchant credentials provided by PayGlobe
  • Test Vouchers: Contact support for test voucher codes
  • Sandbox: Contact support for test environment access

API Keys: Security & Permissions

๐Ÿ”‘ Two Types of API Keys

PayGlobe provides two distinct API keys with different permission levels:

Publishable Key (pk_test_* / pk_live_*)

โœ… Safe for client-side (JavaScript)

Allowed Operations:

  • Create new payments
  • Check payment status
  • Get checkout URLs

โŒ Cannot perform:

  • Refunds/Storni
  • Capture operations
  • Access sensitive data
  • Modify configurations

Usage: Embed in your frontend JavaScript code

Secret Key (sk_test_* / sk_live_*)

โš ๏ธ Server-side ONLY - Never expose publicly

Full Permissions:

  • All Publishable Key operations
  • Refunds & Storni
  • Manual captures
  • Void preauthorizations
  • Webhook signature validation
  • Access transaction details

Usage: Store in environment variables on your backend server

Refunds & Storni (Reversals)

๐Ÿ”’ Security Note: Refund operations require the Secret Key for authentication. These operations can ONLY be performed from your backend server, never from client-side JavaScript.

1. Full Refund (Storno Totale)

Refund the entire payment amount:

Endpoint: POST /api/payment/refund/{transactionId}

Headers:
Authorization: Bearer sk_test_YourSecretKeyHere    โ† Secret Key required!
Content-Type: application/json

Request Body:
{
  "reason": "Customer requested refund"
}

Example with cURL:
curl -X POST https://api.payglobe.it/paymentgw/api/payment/refund/abc123 \
  -H "Authorization: Bearer sk_test_YourSecretKeyHere" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Customer requested refund"}'

Response (Success):
{
  "success": true,
  "transactionId": "abc123",
  "refundAmount": 150.00,
  "status": "REFUNDED",
  "refundedAt": "2025-11-05T20:15:00Z"
}

2. Partial Refund (Storno Parziale)

Refund only a portion of the payment:

Endpoint: POST /api/payment/refund/{transactionId}

Headers:
Authorization: Bearer sk_test_YourSecretKeyHere    โ† Secret Key required!
Content-Type: application/json

Request Body:
{
  "amount": 50.00,
  "reason": "Partial refund for damaged item"
}

Example with Node.js:
const response = await fetch(
  `https://api.payglobe.it/paymentgw/api/payment/refund/${transactionId}`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.PAYGLOBE_SECRET_KEY}`,  // sk_test_...
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      amount: 50.00,
      reason: 'Partial refund for damaged item'
    })
  }
);

const refund = await response.json();
console.log('Refund processed:', refund);

Response (Success):
{
  "success": true,
  "transactionId": "abc123",
  "refundAmount": 50.00,
  "remainingAmount": 100.00,
  "status": "PARTIALLY_REFUNDED",
  "refundedAt": "2025-11-05T20:15:00Z"
}

3. Get Refund History

Retrieve all refunds for a transaction:

Endpoint: GET /api/payment/refunds/{transactionId}

Headers:
Authorization: Bearer sk_test_YourSecretKeyHere    โ† Secret Key required!

Example:
curl https://api.payglobe.it/paymentgw/api/payment/refunds/abc123 \
  -H "Authorization: Bearer sk_test_YourSecretKeyHere"

Response:
{
  "transactionId": "abc123",
  "originalAmount": 150.00,
  "totalRefunded": 50.00,
  "remainingAmount": 100.00,
  "refunds": [
    {
      "refundId": "ref_xyz789",
      "amount": 50.00,
      "reason": "Partial refund for damaged item",
      "status": "SUCCESS",
      "createdAt": "2025-11-05T20:15:00Z"
    }
  ]
}

Backend Implementation Example (Node.js/Express)

// Store secret key in environment variable
const PAYGLOBE_SECRET_KEY = process.env.PAYGLOBE_SECRET_KEY;  // sk_test_...

// Refund endpoint on your server
app.post('/admin/refund/:transactionId', async (req, res) => {
  try {
    const { transactionId } = req.params;
    const { amount, reason } = req.body;

    // Call PayGlobe API with SECRET KEY
    const response = await fetch(
      `https://api.payglobe.it/paymentgw/api/payment/refund/${transactionId}`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${PAYGLOBE_SECRET_KEY}`,  // SECRET!
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ amount, reason })
      }
    );

    const refund = await response.json();

    if (refund.success) {
      // Log the refund in your database
      await logRefund(transactionId, refund);
      res.json({ success: true, refund });
    } else {
      res.status(400).json({ error: refund.message });
    }
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});
โš ๏ธ Security Best Practices
  • NEVER expose your Secret Key in client-side code (JavaScript, mobile apps)
  • ALWAYS store Secret Keys in environment variables or secure secret managers
  • NEVER commit Secret Keys to version control (Git)
  • Use Publishable Keys for frontend operations only
  • Implement refund operations only on your backend server with proper authentication
  • Rotate keys immediately if a Secret Key is compromised

Summary: Which Key to Use?

Frontend (JavaScript - Publishable Key):
const payglobe = PayGlobe('pk_test_...');  โœ… Public, safe to expose
await payglobe.payments.create({
    amount: 100,
    email: 'customer@example.com',  // Customer email for receipt
    description: 'Order #12345'      // Your internal order number
});

Backend (Server - Secret Key):
const secretKey = process.env.PAYGLOBE_SECRET_KEY;  โœ… Private, server-only
Authorization: Bearer sk_test_...

Operations Requiring Secret Key:
- POST /api/payment/refund/{id}         โ†’ Full or partial refund
- GET  /api/payment/refunds/{id}        โ†’ Get refund history
- POST /api/payment/capture/{id}        โ†’ Manual capture
- POST /api/payment/void/{id}           โ†’ Void preauthorization
- Webhook signature validation          โ†’ Verify HMAC

Dispute & Chargeback Management

What are Disputes? A dispute (chargeback) occurs when a customer contacts their bank to contest a charge. PayGlobe receives these automatically from PSPs and lets you respond with evidence.

How Disputes Work

1. Customer Contests
Customer contacts their bank to dispute a transaction
2. PSP Notifies PayGlobe
IGFS, Stripe, or PayPal sends webhook to our /webhook/psp/dispute endpoint
3. Dispute Appears in Dashboard
The dispute is visible in Merchant Dashboard โ†’ Disputes tab (you don't create it manually)
4. Merchant Responds
Submit evidence (receipts, delivery proof, etc.) before the deadline
5. Resolution
Bank decides: WON (funds returned) or LOST (funds kept by customer)

Dispute API Endpoints

1. List Disputes
GET/api/merchant/disputes

Headers:
Authorization: Bearer sk_test_YourSecretKey

Query Parameters:
  ?status=OPEN           - Filter by status (OPEN, UNDER_REVIEW, WON, LOST, EXPIRED)
  ?startDate=2025-01-01  - Filter from date
  ?endDate=2025-12-31    - Filter to date
  ?page=0                - Page number (0-indexed)
  ?size=20               - Page size

Response:
{
  "disputes": [
    {
      "disputeId": "dp_1abc123def456",
      "originalTransactionId": "TXN_20251107_123456",
      "amountDisputed": 50.00,
      "currency": "EUR",
      "reasonCode": "FRAUDULENT",
      "reasonDescription": "Customer claims unauthorized charge",
      "status": "OPEN",
      "pspSource": "IGFS",
      "responseDeadline": "2025-12-15T23:59:59Z",
      "daysUntilDeadline": 12,
      "isUrgent": false,
      "createdAt": "2025-12-01T10:30:00Z"
    }
  ],
  "currentPage": 0,
  "totalPages": 1,
  "totalItems": 1
}
2. Get Dispute Statistics
GET/api/merchant/disputes/stats

Headers:
Authorization: Bearer sk_test_YourSecretKey

Response:
{
  "open": 3,
  "underReview": 1,
  "won": 5,
  "lost": 2,
  "totalAtRisk": 150.00,
  "totalLost": 75.00
}
3. Respond to Dispute
POST/api/merchant/disputes/{disputeId}/respond

Headers:
Authorization: Bearer sk_test_YourSecretKey
Content-Type: application/json

Request Body:
{
  "response": "This transaction was legitimate. Customer placed order on 2025-11-01 and received delivery confirmation on 2025-11-03. Attached: order receipt, shipping tracking, delivery signature."
}

Response:
{
  "success": true,
  "disputeId": "dp_1abc123def456",
  "status": "UNDER_REVIEW",
  "message": "Response submitted successfully"
}
Dispute Status Values
Status Description Action Required
OPEN New dispute requiring response Submit evidence before deadline
UNDER_REVIEW Evidence submitted, awaiting bank decision Wait for resolution
EVIDENCE_REQUIRED Additional evidence requested Submit more documentation
WON Dispute resolved in your favor None - funds returned
LOST Customer won the dispute None - funds not recovered
CANCELLED Dispute withdrawn by customer/bank None
EXPIRED Response deadline passed Automatically lost
Dispute Reason Codes
Reason Code Description Recommended Evidence
FRAUDULENT Customer claims unauthorized charge IP address, device info, order history
PRODUCT_NOT_RECEIVED Customer didn't receive goods/services Shipping tracking, delivery signature
PRODUCT_UNACCEPTABLE Product differs from description Product photos, description, communications
DUPLICATE Customer charged multiple times Transaction logs, refund records
SUBSCRIPTION_CANCELLED Customer cancelled but still charged Cancellation policy, terms of service
CREDIT_NOT_PROCESSED Refund not received Refund confirmation, bank records
GENERAL Other/unspecified reason Any relevant documentation
Important Notes:
  • Disputes appear automatically - You don't create them; they come from PSP webhooks
  • Response deadlines are critical - Missing the deadline usually means automatic loss
  • isUrgent flag - Set to true when less than 3 days remain
  • Secret Key required - All dispute endpoints require sk_test_* or sk_live_*
Webhook: Receive Dispute Updates

When a dispute status changes, PayGlobe sends a webhook to your configured URL:

POSThttps://your-server.com/webhook/payglobe

Event Type: charge.dispute.created | charge.dispute.updated | charge.dispute.closed

Payload:
{
  "id": "evt_dispute_123",
  "type": "charge.dispute.created",
  "created": 1701432000,
  "data": {
    "object": {
      "disputeId": "dp_1abc123def456",
      "originalTransactionId": "TXN_20251107_123456",
      "amountDisputed": 50.00,
      "status": "OPEN",
      "reasonCode": "FRAUDULENT",
      "responseDeadline": "2025-12-15T23:59:59Z"
    }
  }
}

Token Payments (Card on File)

Save customer cards for one-click payments and recurring billing. Supports both IGFS and Shift4 gateways.

Payment Modes: Configure your merchant account payment mode to enable tokenization:
  • PREAUTH_VOUCHER_CAPTURE - Classic flow with meal vouchers (default)
  • SALE_DIRECT - Direct sale without vouchers
  • SALE_WITH_TOKENIZATION - Direct sale + save card for future payments
1. List Saved Cards

Get all saved cards for a customer:

GET/api/token-payment/cards?customerId={customerId}

Headers:
Authorization: Bearer sk_test_YourSecretKey

Response:
{
  "success": true,
  "customerId": "cust_123",
  "cards": [
    {
      "id": 1,
      "alias": "VISA ****4242",
      "brand": "VISA",
      "last4": "4242",
      "expiry": "12/26",
      "gateway": "IGFS",
      "isDefault": true,
      "lastUsedAt": "2025-12-08T10:00:00",
      "usageCount": 5
    }
  ],
  "count": 1
}
2. Pay with Saved Card (One-Click)

Charge a saved card without requiring customer to re-enter details:

POST/api/token-payment/pay

Headers:
Authorization: Bearer sk_test_YourSecretKey
Content-Type: application/json

Request Body:
{
  "cardId": 1,
  "amount": 50.00,
  "customerId": "cust_123",
  "customerEmail": "customer@example.com",
  "description": "Subscription renewal"
}

Response (Success):
{
  "success": true,
  "transactionId": "TKN_ABC123DEF456",
  "paymentId": "IGFS_PAY_789",
  "gateway": "IGFS",
  "status": "COMPLETED",
  "cardAlias": "VISA ****4242",
  "amount": 50.00
}

Response (Failed):
{
  "success": false,
  "transactionId": "TKN_ABC123DEF456",
  "status": "FAILED",
  "error": "Card declined"
}
3. Save Card from Transaction

After a successful payment with tokenization enabled, save the card:

POST/api/token-payment/save-card

Headers:
Authorization: Bearer sk_test_YourSecretKey
Content-Type: application/json

Request Body:
{
  "transactionId": "TXN_20251208_123456",
  "customerId": "cust_123",
  "gateway": "IGFS"
}

Response:
{
  "success": true,
  "cardId": 1,
  "alias": "VISA ****4242",
  "brand": "VISA",
  "last4": "4242",
  "isDefault": true
}
4. Set Default Card
POST/api/token-payment/cards/{cardId}/set-default?customerId={customerId}

Headers:
Authorization: Bearer sk_test_YourSecretKey

Response:
{
  "success": true,
  "cardId": 1,
  "alias": "VISA ****4242",
  "isDefault": true
}
5. Delete Saved Card
DELETE/api/token-payment/cards/{cardId}

Headers:
Authorization: Bearer sk_test_YourSecretKey

Response:
{
  "success": true,
  "message": "Card deleted successfully"
}
Integration Flow
First Payment (with tokenization):
1. Create payment with paymentMode = SALE_WITH_TOKENIZATION
2. Customer completes payment on gateway page
3. Gateway returns card token
4. Call POST /api/token-payment/save-card to store card
5. Card is now available for future payments

Subsequent Payments (one-click):
1. Call GET /api/token-payment/cards to get customer's cards
2. Display saved cards to customer
3. Customer selects a card
4. Call POST /api/token-payment/pay with cardId
5. Payment is processed server-to-server (no redirect)
Security Notes:
  • Card tokens are gateway-specific (IGFS or Shift4)
  • Tokens can only be used with the same merchant that created them
  • Always obtain customer consent before saving cards (GDPR compliance)
  • Implement proper customer authentication before showing saved cards

Support

๐Ÿ“š Documentation

OpenAPI YAML specification with complete API reference

๐Ÿงช Postman Collection

Ready-to-use API tests for all integration scenarios

๐Ÿ’ฌ Technical Support

Contact: support@payglobe.com