Skip to main content

Vault capture deep-dive

For the admin-facing config and trigger choices, see Vault capture configuration. This page documents the service architecture and extension seams.

The pipeline at a glance

Order placement


VaultTokenResolver
│ resolves the order's vault token (vault_payment_token row)
│ stores it on the byte8_preorder row at `vault_token_id`


[ wait for trigger ]

├─ shipment_create → ShipmentPlugin marks vault_capture_pending
├─ shipment_track → TrackPlugin marks vault_capture_pending
└─ manual → admin grid action marks vault_capture_pending


Cron/ProcessVaultCaptures (every 5 min)


VaultMethodResolver → VaultCaptureService → gateway charge API

├─ success → status = succeeded → completion email
└─ failure → attempts++ → schedule retry

└─ if attempts ≥ max → fallback email + status = fallback_sent

Service classes

ClassRole
Model/Service/VaultTokenResolverAt order placement, finds the vault token used to pay the deposit. Stores vault_token_id and vault_method_code on the pre-order.
Model/Service/VaultMethodResolverMaps the order's payment method code to the right gateway adapter for vault charge. Pluggable.
Model/Service/VaultCaptureServiceThe actual charge call. Wraps Magento Vault's CommandPool to execute the gateway's vault_authorize_capture command.
Cron/ProcessVaultCapturesThe background worker that picks up vault_capture_pending pre-orders and retries with backoff.

Plugin / extension points

Add a custom gateway adapter

If your gateway isn't auto-resolved by VaultMethodResolver, plugin around its resolveForOrder method:

public function aroundResolveForOrder(
VaultMethodResolver $subject,
callable $proceed,
OrderInterface $order
): VaultMethodInterface {
$methodCode = $order->getPayment()->getMethod();
if ($methodCode === 'my_custom_gateway_vault') {
return $this->myCustomAdapter;
}
return $proceed($order);
}

Override the retry schedule

The default schedule is attempts × retry_backoff_minutes. To change, plugin Cron/ProcessVaultCaptures::scheduleNextAttempt:

public function aroundScheduleNextAttempt(
ProcessVaultCaptures $subject,
callable $proceed,
PreorderInterface $preorder
): \DateTimeInterface {
// exponential backoff
return new \DateTimeImmutable("+{$preorder->getVaultCaptureAttempts() ** 2} hours");
}

Hook the success / failure events

VaultCaptureService dispatches:

  • byte8_preorder_vault_capture_success — after a successful charge, with preorder and transaction_id in the event data.
  • byte8_preorder_vault_capture_failure — after a failed charge, with preorder and error_message.

Subscribe in etc/events.xml to wire alerts, Slack notifications, ERP updates, etc.

Schema

The byte8_preorder table carries:

ColumnTypeNotes
vault_token_idintFK to vault_payment_token.entity_id
vault_method_codevarcharPayment method code for resolver dispatch
vault_capture_statusvarcharEnum — see Model/Config/Source/VaultCaptureStatus
vault_capture_attemptsintRetry counter
vault_capture_last_errortextLast gateway error
vault_capture_next_attempt_atdatetimeWhen the cron should next try
vault_capture_completed_atdatetimeSuccess timestamp

Plus quote_item.preorder_id so the pre-order context survives quote-to-order conversion.

Gateway-specific notes

  • Stripe — works with stripe_payments and the Stripe Magento connector's vault variants. Token format is the standard pm_... payment method ID.
  • Adyen — works with both adyen_cc and adyen_oneclick variants. Recurring contract reference must be present on the token.
  • Braintree — Vault stored as braintree payment method nonce → token. Both the standard and PayPal-via-Braintree flows are covered.
  • Authorize.net — Vault works via authorizenet_directpost with the CIM extension enabled. The vault token is the CIM customer profile ID.
  • PayPal Express — does NOT support vault capture. Pre-orders paid with PayPal Express are flagged vault_capture_status = unsupported at order placement and routed to the manual completion fallback automatically.

Failure modes

ModeWhat it looks likeWhat to do
Token expiredGateway returns "Token not found"Send the customer to the manual completion link via fallback email.
Customer card declinedGateway returns insufficient funds / card-declinedCron retries up to max_attempts. After that, fallback email.
Gateway outageNetwork errors / 5xxCron retries automatically; usually clears within an hour.
Vault method changedCustomer deleted their stored cardvault_capture_status = unsupported, fallback email immediately.