Step-by-step traces of payment operations with Gateway commands
When order is placed with payment_action = "authorize"
Sales\Model\Order\Payment::place() is called during order save.
// Order\Payment::place()
$this->_authorize(true, $baseTotalDue);
// Calls MethodInterface::authorize()
Method\Adapter::authorize() resolves "authorize" command from CommandPool.
// Method\Adapter::authorize()
$this->executeCommand('authorize', [
'payment' => $paymentDataObject,
'amount' => $amount
]);
BuilderComposite chains multiple builders to create the API request.
// Example builder output
[
'amount' => 99.99,
'currency' => 'USD',
'card' => ['number' => '4111...', 'exp' => '12/25'],
'billing_address' => [...],
'merchant_id' => 'abc123'
]
TransferFactory creates transfer object, ClientInterface sends request.
// Gateway\Http\Client\Zend or Curl
POST https://api.gateway.com/authorize
Content-Type: application/json
Authorization: Bearer {token}
{"amount": 99.99, "currency": "USD", ...}
HandlerInterface extracts transaction ID and stores in payment.
// Response handler
$payment->setTransactionId($response['transaction_id']);
$payment->setIsTransactionClosed(false);
$payment->setAdditionalInformation('auth_code', $response['auth_code']);
ValidatorInterface checks response codes and throws exception on failure.
// Validator checks
if ($response['status'] !== 'approved') {
throw new CommandException(__('Payment authorization failed'));
}
return $this->createResult(true, []);
When invoice is created with "Capture Online" option
Sales\Model\Order\Payment::capture() called from invoice creation.
// InvoiceService triggers
$payment->capture($invoice);
// For previously authorized payments:
$this->_capture($invoice);
Request builder includes original transaction ID for reference.
// Capture request builder
[
'transaction_id' => $payment->getParentTransactionId(),
'amount' => $invoice->getBaseGrandTotal(),
'currency' => $order->getBaseCurrencyCode()
]
Capture transaction linked to authorization as parent.
// Response handler creates transaction
$payment->setTransactionId($response['capture_id']);
$payment->setParentTransactionId($response['auth_id']);
// Transaction type: capture
When order is cancelled before capture
Order\Payment::cancel() checks if void is possible.
// Order\Payment::cancel()
if ($this->canVoid()) {
$this->void(new \Magento\Framework\DataObject());
}
Sends void request with original authorization transaction ID.
// Void request
[
'transaction_id' => $payment->getLastTransId(),
'reason' => 'Order cancelled'
]
Original auth transaction marked as closed.
// After void
$authTransaction->setIsClosed(true);
// New void transaction created
$payment->setTransactionId($response['void_id'] . '-void');
When credit memo is created with "Refund" option
Order\Payment::refund() called from creditmemo service.
// Creditmemo service
$payment->refund($creditmemo);
// Triggers MethodInterface::refund()
References capture transaction for partial or full refund.
// Refund request builder
[
'transaction_id' => $payment->getRefundTransactionId(),
'amount' => $creditmemo->getBaseGrandTotal(),
'invoice_id' => $invoice->getIncrementId()
]
New refund transaction linked to capture as parent.
// Response handler
$payment->setTransactionId($response['refund_id']);
$creditmemo->setTransactionId($response['refund_id']);
// If full refund, capture transaction closed
When checkout page loads available payment methods
CompositeConfigProvider collects all payment config.
// checkout/index/index renders
window.checkoutConfig = {
payment: {
// Each method adds its config here
}
}
PaymentMethodList::getActiveList() filters by availability rules.
// Filtering criteria:
// - isActive() for current store
// - isAvailable($quote) checks:
// - min/max order total
// - allowed countries
// - specific customer groups
// - SpecificationInterface rules
RequireJS components render each payment method in checkout.
// Magento_Checkout/js/view/payment/list
// Iterates over available methods
// Each method has its own component:
// Magento_Payment/js/view/payment/cc-form
Observed by SalesOrderBeforeSaveObserver to validate payment data before order save.
UpdateOrderStatusForPaymentMethodsObserver updates status mapping when status unassigned.
Dispatched during method availability check. Allows plugins to enable/disable methods dynamically.
Various events for payment operations: _place_start, _place_end, _cancel, _void, etc.
Gateway Response → Validator → ErrorMessageMapper → Exception
// 1. Validator checks response
$result = $validator->validate($response);
if (!$result->isValid()) {
$errorCodes = $result->getFailsDescription();
}
// 2. ErrorMessageMapper translates codes
// Configured in error_mapping.xml:
<error_messages>
<message code="1001" translate="true">Card declined</message>
<message code="1002" translate="true">Insufficient funds</message>
</error_messages>
// 3. CommandException thrown with customer-friendly message
throw new CommandException(__($mappedMessage));
Best Practice: Always implement error_mapping.xml for your payment gateway. Raw gateway error codes should never be shown to customers. Map them to localized, user-friendly messages.