PG Params
Every payment gateway returns transaction results in its own format — different field names, different nesting structures, even different response shapes for the same gateway depending on the transaction type. Ottu sits in front of 60+ payment gateways and normalizes all of these varied responses into a consistent set of fields called pg_params.
When your webhook handler reads pg_params.card_number, you get the masked card number regardless of whether the transaction was processed by KNET, MPGS, Cybersource, Tap, or any other gateway. No gateway-specific parsing required.
Why PG Params Matter
If you parse the raw gateway_response directly, your code is tightly coupled to one gateway's format. The moment you add a second gateway or switch providers, your webhook handler breaks and requires new development work.
pg_params eliminates this problem. Ottu does the heavy lifting of extracting and normalizing fields from every gateway's unique response format, so your code stays the same regardless of which gateway processed the transaction.
Without PG Params — parsing raw gateway responses:
{ "auth": "A83921", "tranid": "9201831", "trackid": "TRK001", "ref": "REF001" }
{
"transaction": [{ "transaction": { "authorizationCode": "A83921" } }],
"order": { "id": "9201831", "reference": "REF001" }
}
Two completely different structures. Your code would need separate parsing logic for each.
With PG Params — same fields, every gateway:
{ "auth_code": "A83921", "transaction_id": "9201831", "ref": "REF001" }
Always build your webhook handling logic against pg_params. When you add a new payment connection or switch from one gateway to another, your code keeps working — Ottu handles the extraction and normalization behind the scenes.
Where PG Params Appear
pg_params is included in:
- Payment webhooks — the
pg_paramsobject in every payment notification - Operation webhooks — the
pg_paramsobject in refund, capture, and void notifications - Payment Status Query — the response includes the same normalized fields
The raw gateway_response is also included in webhook payloads for audit purposes, but you should not rely on it for business logic.
Field Reference
Search or filter all normalized fields below. Click any field name to get a shareable link.
| Field | Category | Description | Example |
|---|---|---|---|
| card_number# | Card Information | Masked card number (PAN) used for the transaction. Always masked for PCI compliance — only the first six and last four digits are visible.Format varies by gateway. Some return 4111-11**-****-1111, others 411111******1111. | 411111******1111 |
| card_type# | Card Information | Type or brand of the card used for the transaction, such as credit, debit, or prepaid. Some gateways return the scheme name (Visa, Mastercard) instead. | credit |
| card_issuer# | Card Information | The issuing bank or financial institution of the card. Useful for analytics and routing decisions. | National Bank of Kuwait |
| card_holder# | Card Information | Full name of the cardholder as provided by the payment gateway. | Ahmed Al-Sabah |
| cardholder_email# | Card Information | Email address of the cardholder, if provided by the payment gateway during the transaction. | [email protected] |
| card_expiry_month# | Card Information | Expiry month of the card, zero-padded to two digits. | 01 |
| card_expiry_year# | Card Information | Expiry year of the card. Format varies — some gateways return two digits, others four.May be "26" or "2026" depending on gateway. | 2026 |
| full_card_expiry# | Card Information | Full card expiry date in MM/YY or MM/YYYY format, as a single combined string. | 01/26 |
| card_details# | Card Information | Additional card details object returned by the payment gateway. Contains gateway-specific card metadata not covered by other fields.Structure varies by gateway. Use the specific card_* fields for consistent access. | |
| auth_code# | Transaction Identifiers | Authorization code returned by the payment gateway for the transaction. This is the approval code from the issuing bank confirming the transaction was authorized.Always present for successful transactions. This is the only mandatory PG param. | A83921 |
| transaction_id# | Transaction Identifiers | Unique transaction identifier assigned by the payment gateway. Use this when communicating with the gateway about a specific transaction. | TXN-2024-0839210 |
| payment_id# | Transaction Identifiers | Payment identifier from the payment gateway, used for tracking and reconciliation. May differ from transaction_id on gateways that separate payment and transaction concepts. | PAY-4829103 |
| ref# | Transaction Identifiers | Gateway-specific reference identifier for the transaction. Often used as the merchant's reference on the gateway side. | REF-20240315-001 |
| track_id# | Transaction Identifiers | Tracking identifier assigned by the payment gateway for reconciliation purposes. | TRK-9281034 |
| receipt_no# | Transaction Identifiers | Receipt number generated by the payment gateway for the transaction. Useful for customer-facing receipts and records. | 429103821 |
| transaction_no# | Transaction Identifiers | Transaction number assigned by the gateway. On some gateways this is different from transaction_id and serves as a secondary identifier. | 000000382910 |
| rrn# | Transaction Identifiers | Retrieval Reference Number — a banking-standard unique identifier used for transaction lookups, dispute resolution, and chargeback processing.Essential for disputes. Store this value and include it in any communication with the gateway or acquiring bank. | 430215829103 |
| order_id# | Transaction Identifiers | Order identifier as assigned by the payment gateway. Represents the gateway's internal order record. | ORD-58392 |
| result# | Transaction Status | Normalized transaction result from the payment gateway, indicating the outcome of the transaction.Common values: CAPTURED, APPROVED, DECLINED, ERROR. Values vary by gateway — use Ottu's top-level 'state' field for standardized status. | CAPTURED |
| decision# | Transaction Status | The gateway's final decision on the transaction. Indicates whether the transaction was accepted, rejected, or flagged for review.Common values: ACCEPT, REJECT, REVIEW. Not all gateways provide this field. | ACCEPT |
| pg_message# | Transaction Status | Human-readable message from the payment gateway describing the transaction outcome. Useful for logging and debugging. | Transaction approved successfully |
| post_date# | Transaction Status | The date the transaction was posted or settled by the payment gateway. | 2024-03-15 |
| dcc_payer_amount# | Currency Conversion | The amount in the payer's local currency when Dynamic Currency Conversion (DCC) is applied. This is the amount the cardholder actually pays.Only present when DCC is active. Compare with the transaction amount to see the conversion difference. | 28.50 |
| dcc_payer_currency# | Currency Conversion | The payer's local currency code when DCC is applied, in ISO 4217 format. | USD |
| dcc_payer_exchange_rate# | Currency Conversion | The exchange rate applied for the Dynamic Currency Conversion between the merchant's currency and the payer's local currency.Multiply the transaction amount by this rate to get the payer amount. | 3.3012 |
If you need a gateway response field that isn't currently in pg_params, contact us at [email protected] and we'll add it. New parameters are added regularly as merchants request them.
pg_params vs gateway_response
Both fields are included in webhook payloads. Here's when to use each:
pg_params | gateway_response | |
|---|---|---|
| Format | Consistent across all gateways | Varies by gateway |
| Structure | Flat key-value object | Nested, gateway-specific |
| Stability | Field names are fixed | Can change when a gateway updates their API |
| Use for | Business logic, display, reconciliation | Audit trails, debugging, gateway support tickets |
| Recommended | Yes — primary integration field | Store for audit, don't build logic on it |
The raw gateway_response format can change without notice when a payment gateway updates their API. Building business logic on raw gateway responses means your integration can break at any time. Use pg_params for all programmatic decisions.
Code Examples
Here's how to extract pg_params from a webhook payload:
- Python
- Node.js
- PHP
import json
from flask import Flask, request
app = Flask(__name__)
@app.route("/webhook", methods=["POST"])
def handle_webhook():
payload = request.get_json()
# Use pg_params for normalized gateway fields
pg_params = payload.get("pg_params", {})
auth_code = pg_params.get("auth_code", "")
card_number = pg_params.get("card_number", "")
rrn = pg_params.get("rrn", "")
transaction_id = pg_params.get("transaction_id", "")
# Use the top-level 'state' for payment status
state = payload.get("state")
print(f"Payment {state}: card={card_number}, auth={auth_code}, rrn={rrn}")
# Store the raw gateway_response for audit purposes only
gateway_response = payload.get("gateway_response", {})
save_audit_log(gateway_response)
return "OK", 200
const express = require("express");
const app = express();
app.use(express.json());
app.post("/webhook", (req, res) => {
const payload = req.body;
// Use pg_params for normalized gateway fields
const pgParams = payload.pg_params || {};
const authCode = pgParams.auth_code || "";
const cardNumber = pgParams.card_number || "";
const rrn = pgParams.rrn || "";
const transactionId = pgParams.transaction_id || "";
// Use the top-level 'state' for payment status
const state = payload.state;
console.log(`Payment ${state}: card=${cardNumber}, auth=${authCode}, rrn=${rrn}`);
// Store the raw gateway_response for audit purposes only
const gatewayResponse = payload.gateway_response || {};
saveAuditLog(gatewayResponse);
res.sendStatus(200);
});
<?php
$payload = json_decode(file_get_contents('php://input'), true);
// Use pg_params for normalized gateway fields
$pgParams = $payload['pg_params'] ?? [];
$authCode = $pgParams['auth_code'] ?? '';
$cardNumber = $pgParams['card_number'] ?? '';
$rrn = $pgParams['rrn'] ?? '';
$transactionId = $pgParams['transaction_id'] ?? '';
// Use the top-level 'state' for payment status
$state = $payload['state'];
error_log("Payment {$state}: card={$cardNumber}, auth={$authCode}, rrn={$rrn}");
// Store the raw gateway_response for audit purposes only
$gatewayResponse = $payload['gateway_response'] ?? [];
saveAuditLog($gatewayResponse);
http_response_code(200);
echo 'OK';
FAQ
What's Next?
- Payment Events — Full webhook payload reference for payment notifications
- Operation Events — Webhook notifications for refunds, captures, and voids
- Verify Signatures — Validate webhook authenticity with HMAC-SHA256
- Webhooks Overview — Setup, delivery guarantees, and configuration