Protecting customers and operations by separating product-safe failures from provider diagnostics.
External providers frequently return messages intended for merchant operators. Passing them directly to customers can expose credentials, account permissions, liquidity information, or internal provider restrictions.
Store two error representations:
PaymentFailure(
customer_message="Unable to complete this transaction. Please try again later.",
provider_code=response.code,
provider_reason=response.message,
provider_payload=sanitized_payload,
)
The customer message should be clear and actionable without revealing infrastructure details. Operations staff need the exact provider reason, request identifier, and sanitized response for investigation.
Apply this rule consistently across API responses, transaction details, push notifications, emails, logs, and staff dashboards. Mask account numbers and never log credentials or complete authorization tokens.
Error normalization also prevents one provider's vocabulary from leaking into the product. Customers should experience a consistent QuickerPay failure model even when the underlying payment rails differ.
Build a small error taxonomy
Map provider responses into internal categories such as invalid recipient, temporarily unavailable, insufficient platform funds, authorization failure, limit exceeded, and unknown provider error. Categories allow the product to choose consistent HTTP statuses and customer messages without depending on unstable provider wording.
Some errors are actionable for customers. An invalid account number can ask them to check the details. Others are operational and should use a neutral retry message. Never claim a refund unless the ledger confirms that a refund occurred.
Preserve diagnostics safely
Operations usually need the provider code, request identifier, endpoint operation, response status, and sanitized payload. They do not need secrets, authorization headers, complete account numbers, or personal identity data in general logs.
Use structured logging so incidents can be searched by internal transaction reference and provider attempt. Keep detailed payloads in access-controlled records with an appropriate retention policy.
Make notifications use the same mapping
It is easy to sanitize the API response while a background task later inserts the raw provider message into a push notification. Centralize customer-facing failure text and require notifications, emails, and transaction serializers to use it.
Do not destroy the original evidence
Normalization should add an internal category; it should not overwrite the original provider response. Provider details are essential for support escalation and reconciliation.
A mature error system serves three audiences at once: customers need clarity, operators need evidence, and engineers need enough context to diagnose systemic failures.
Implementation checklist
Create a provider-error registry with internal category, retryability, customer message, operator guidance, and alert severity. Unknown errors should fall back safely while preserving sanitized diagnostics. Review the registry as providers introduce new responses.
Test the complete communication chain. Confirm that raw messages cannot escape through serializer fields, background notifications, email templates, or staff-written resend actions. Add automated tests using realistic provider payloads containing sensitive-looking content.
The objective is not to hide every failure. It is to communicate what the customer can do while routing technical evidence to the people who can act on it.
Choose retry behavior deliberately
Retry policy should follow the failure category. A timeout after submission calls for a status lookup because the provider may already have accepted the transfer. A validation error should usually fail immediately because repeating the same request changes nothing. Rate limits call for delayed retries with jitter, while authentication failures should alert operators instead of generating more traffic. Persist the attempt count, next retry time, and last failure category so workers resume safely after a restart. After exhausting the retry budget, move the transaction into a visible review state rather than leaving it indefinitely in processing.
Top comments (0)