Skip to main content

GLODIPAY REFUND API SPECIFICATION

Ask AI

VERSION 2.0.0

Table of Contents

Introduction

This document describes the GLODIPAY Refund API v2, which allows merchants to initiate refunds for completed transactions, query refund status, and receive refund notifications via IPN.

Key points:

  • Refunds can be full or partial (subject to per-provider constraints -- some providers only support full-amount refunds).
  • Refunds may be auto-processed immediately or held for manual approval, depending on merchant configuration.
  • The notificationUrl from the original transaction is used for refund IPN notifications.
  • The maximum refundable amount per refund is: paidAmount minus the total already refunded for the transaction.

Endpoints

TestGet it from the API Keys page of the Sandbox Merchant Dashboard
ProductionGet it from the API Keys page of the Merchant Dashboard

Signature

All requests and responses are signed using RSA with MD5 to ensure integrity and authenticity.

Generating a Signature (Merchant -> GLODIPAY)

Sign request payloads with your RSA Private Key (obtained from the Merchant Dashboard).

Steps:

  • Collect all request parameters except signature as a flat key-value object.
  • Sort the keys in natural ascending order (SORT_NATURAL / localeCompare with numeric: true).
  • Trim whitespace from all string values (recursive).
  • Serialize to JSON string with all non-ASCII Unicode characters escaped to \uXXXX (RFC 8259).
  • Sign with md5WithRSAEncryption using your RSA Private Key.
  • Base64-encode the binary output.

Verifying a Signature (GLODIPAY -> Merchant)

Verify GLODIPAY responses and webhooks with the RSA Public Key (available in the Portal).

Steps:

  • Separate signature from the payload.
  • Sort remaining keys in natural ascending order.
  • Trim all string values (recursive).
  • Serialize to JSON string with all non-ASCII Unicode characters escaped to \uXXXX (RFC 8259).
  • Verify with md5WithRSAEncryption using your RSA Public Key.
  • Return value 1 = valid.

Note (Node.js): Convert all numeric values to strings before sorting/serializing. Escape forward slashes in the JSON string: .replace(///g, '/').

Note (Unicode / RFC 8259): The JSON payload must escape all non-ASCII Unicode characters (e.g., "a with accent" must become "\u00e1") before signing -- this is required by RFC 8259. In PHP, json_encode($data) does this by default -- do not use JSON_UNESCAPED_UNICODE. In Node.js, JSON.stringify() does not escape Unicode by default -- apply: .replace(/[^\\x00-\\x7F]/g, c => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0")) after serializing.

REFUND API

Initiate a refund for a completed transaction.

Endpoint: POST /v2/refund Method: POST Content-Type: application/json

Request

transactionIdString (ULID)MThe transactionId received from the checkout IPN or transaction query
amountFloatMRefund amount. Minimum: 0.10. Maximum: remaining refundable amount (paidAmount minus already refunded)
reasonString(max:1000)OShort description of the refund reason
signatureString(max:750)MRSA-MD5 signature

Note: Certain providers (e.g. PayAgency, SmartPay, ClisaPay, FinvyPay, WPay) only support full-amount refunds. The system enforces the minimum refund amount accordingly.

Response

Content-Type: application/json

statusStringsuccess
messageStringHuman-readable message
dataJSONRefund details. See data object below

data object:

refundIdString (ULID)GLODIPAY refund ID
refundNumberStringGLODIPAY human-readable refund number

Refund created and processed immediately (auto-refund enabled):

{
"status": "success",
"message": null,
"data": {
"refundId": "01jzabk09xc4pbgwe8hyg4cwbf",
"refundNumber": "2507-1751420414"
}
}

Refund created and pending manual approval:

{
"status": "success",
"message": "Refund created and waiting for approval.",
"data": {
"refundId": "01jzabk09xc4pbgwe8hyg4cwbf",
"refundNumber": "2507-1751420414"
}
}

Validation error (HTTP 422):

{
"status": "error",
"message": "Invalid request data.",
"errors": [
{
"field": "amount",
"message": ["The amount must be between 0.1 and 100."]
}
]
}

REFUND QUERY

Query the latest status of a refund.

Endpoint: POST /v2/refund/query Method: POST Content-Type: application/json

Request

refundIdString (ULID)MGLODIPAY refund ID (from Refund API response or Refund IPN)
signatureString(max:750)MRSA-MD5 signature

Response

Content-Type: application/json

statusStringsuccess
messageStringHuman-readable message
dataJSONRefund details object. See fields below

data object fields:

transactionIdStringGLODIPAY original transaction ID
refStringMerchant's orderRef
refundIdStringGLODIPAY refund ID
currencyStringISO 4217 currency code
refundAmountFloatRefund amount
statusStringRefund status. See Refund Status Values
statusCodeNumberNumeric status code. See Status Codes
metadataJSONKey-value pairs from the original checkout session
reasonStringRefund reason
messageStringHuman-readable status message
originalRefundCreatedAtISO 8601 datetimeRefund creation time at the PSP
refundCreatedAtISO 8601 datetimeRefund creation time in GLODIPAY system
transactionCreatedAtISO 8601 datetimeOriginal transaction creation time
signatureStringRSA-MD5 signature -- verify with GLODIPAY public key

Example:

{
"status": "success",
"message": "",
"data": {
"transactionId": "01jza90dy6w82dfrrqvadn5vs4",
"ref": "ORDER-001",
"refundId": "01jzabk09xc4pbgwe8hyg4cwbf",
"currency": "USD",
"refundAmount": 50.00,
"status": "refund_successful",
"statusCode": 11,
"metadata": { "orderId": "12345" },
"reason": "Customer request",
"message": null,
"originalRefundCreatedAt": "2026-04-14T11:00:00+00:00",
"refundCreatedAt": "2026-04-14T11:00:01+00:00",
"transactionCreatedAt": "2026-04-14T10:00:00+00:00",
"signature": "base64-encoded-rsa-signature"
}
}

REFUND NOTIFICATION

GLODIPAY sends an HTTP POST to the notificationUrl of the original transaction when a refund status changes.

Method: POST Content-Type: application/json

Retry policy: If your server does not return {"returnCode":"100"} within 30 seconds, GLODIPAY will retry delivery.

Payload

transactionIdStringMGLODIPAY original transaction ID
refStringMMerchant's orderRef
refundIdStringMGLODIPAY refund ID
currencyStringMISO 4217 currency code
refundAmountFloatMRefund amount
statusStringMRefund status. See Refund Status Values
statusCodeNumberMNumeric status code. See Status Codes
metadataJSONOKey-value pairs from the original checkout session
reasonStringORefund reason
messageStringOHuman-readable status message
originalRefundCreatedAtISO 8601 datetimeMRefund creation time at the PSP
refundCreatedAtISO 8601 datetimeMRefund creation time in GLODIPAY system
transactionCreatedAtISO 8601 datetimeMOriginal transaction creation time
signatureStringMRSA-MD5 signature -- verify with GLODIPAY public key

Example IPN Payload:

{
"transactionId": "01jza90dy6w82dfrrqvadn5vs4",
"ref": "ORDER-001",
"refundId": "01jzabk09xc4pbgwe8hyg4cwbf",
"currency": "USD",
"refundAmount": 50.00,
"status": "refund_successful",
"statusCode": 11,
"metadata": { "orderId": "12345" },
"reason": "Customer request",
"message": null,
"originalRefundCreatedAt": "2026-04-14T11:00:00+00:00",
"refundCreatedAt": "2026-04-14T11:00:01+00:00",
"transactionCreatedAt": "2026-04-14T10:00:00+00:00",
"signature": "base64-encoded-rsa-signature"
}

Response (Merchant -> GLODIPAY)

Your server must respond within 30 seconds:

{
"returnCode": "100",
"description": "Received"
}
returnCodeStringRMust be "100" to acknowledge receipt
descriptionString(1,1500)OOptional description

Appendix

Refund Status Values

String values returned in the status field of refund IPN payloads and refund query responses.

refund_initiatedRefund request initiated
refund_under_reviewRefund under review
refund_successfulRefund completed successfully
refund_failedRefund failed
refund_partially_successfulPartial refund completed
refund_partially_failedPartial refund failed
void_initiatedVoid initiated
void_under_reviewVoid under review
void_successfulVoid completed successfully
void_failedVoid failed
void_partially_successfulPartial void completed
void_partially_failedPartial void failed

Status Codes

Numeric code in the statusCode field of refund IPN payloads and refund query responses.

8refund_initiatedRefund initiated
9refund_failedRefund failed
10refund_under_reviewRefund under review
11refund_successfulRefund successful
12refund_partially_failedPartial refund failed
13refund_partially_successfulPartial refund successful
18void_initiatedVoid initiated
19void_under_reviewVoid under review
20void_successfulVoid successful
21void_failedVoid failed
22void_partially_successfulPartial void successful
23void_partially_failedPartial void failed

Code Examples

PHP

<?php

function generateSignature(array $data): string
{
$privateKey = openssl_pkey_get_private("-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY_HERE
-----END PRIVATE KEY-----
");

foreach ($data as $k => $v) {
if (is_array($v)) $data[$k] = json_encode($v);
}
ksort($data, SORT_NATURAL);
array_walk_recursive(
$data,
static function (&$field) {
$field = trim($field);
}
);

openssl_sign(json_encode($data), $signature, $privateKey, 'md5WithRSAEncryption');

return base64_encode($signature);
}

function verifySignature(array $data): bool
{
$publicKey = openssl_pkey_get_public("-----BEGIN PUBLIC KEY-----
YOUR_GLODIPAY_PUBLIC_KEY_HERE
-----END PUBLIC KEY-----
");

$dataWithoutSignature = array_filter($data, static function ($key) {
return $key !== 'signature';
}, ARRAY_FILTER_USE_KEY);

$signature = $data['signature'];

ksort($dataWithoutSignature, SORT_NATURAL);
array_walk_recursive(
$dataWithoutSignature,
static function (&$field) {
$field = trim($field);
}
);

$result = openssl_verify(
json_encode($dataWithoutSignature),
base64_decode($signature),
$publicKey,
'md5WithRSAEncryption'
);

return $result === 1;
}

// Example: create a refund
$payload = [
'transactionId' => '01jza90dy6w82dfrrqvadn5vs4',
'amount' => '50.00',
'reason' => 'Customer request',
];

$payload['signature'] = generateSignature($payload);

$ch = curl_init('https://payment-sandbox.gpayprocessing.com/v2/refund');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
echo 'Refund ID: ' . $result['data']['refundId'];

Node.js

// Save as script.mjs and run: node script.mjs
import { createSign } from 'crypto';
import https from 'https';

const PRIVATE_KEY = `-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY_HERE
-----END PRIVATE KEY-----`;

function phpCast(v) {
if (typeof v === 'number') return String(v);
if (typeof v === 'boolean') return v ? '1' : '';
if (typeof v === 'string') return v.trim();
if (Array.isArray(v)) return v.map(phpCast);
if (v && typeof v === 'object') return Object.fromEntries(Object.entries(v).map(([k, val]) => [k, phpCast(val)]));
return v;
}

function generateSignature(data) {
const sorted = {};
Object.keys(data)
.filter(k => k !== 'signature')
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }))
.forEach(k => { sorted[k] = data[k]; });

const canonical = JSON.stringify(phpCast(sorted))
.replace(/\//g, '\\/')
.replace(/[\u0080-\uffff]/g, c => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'));

const sign = createSign('md5WithRSAEncryption');
sign.update(canonical);
return sign.sign(PRIVATE_KEY, 'base64');
}

// Example: create a refund
const payload = {
transactionId: '01jza90dy6w82dfrrqvadn5vs4',
amount: '50.00',
reason: 'Customer request',
};

payload.signature = generateSignature(payload);

const postData = JSON.stringify(payload);
const options = {
hostname: 'payment-sandbox.gpayprocessing.com',
path: '/v2/refund',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
},
};

const req = https.request(options, (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
const result = JSON.parse(body);
console.log('Refund ID:', result.data.refundId);
});
});

req.on('error', console.error);
req.write(postData);
req.end();

Bookmarks

No bookmarks yet.
Hover over a heading and click to save a section.