Best Practices
General recommendations for building robust, secure integrations with Zenith Payments. These apply across every integration path — Hosted Checkout, Payment Links, and the REST API.
For Hosted Checkout specific guidance (fingerprint handling, plugin initialisation errors, callbackUrl validation), see Hosted Checkout — Best Practices.
Security
Rate Limiting and Velocity Checks
Rate limiting should be implemented at both the IP and session levels. You should restrict the number of payment attempts a single user can make within a specific timeframe (e.g. no more than 3 attempts per 15 minutes). Furthermore, implement velocity checks on your backend to monitor for spikes in overall transaction volume or a high frequency of "Declined" responses. If your system detects an unusual pattern — such as 50 declines in 60 seconds — it should automatically trigger a temporary "circuit breaker" to halt all processing until the threat is mitigated.
Secure Credential Management
Merchant-specific credentials — API keys, usernames, passwords, and payment tokens — must be stored securely on your infrastructure (e.g. environment variables or a secrets manager) and never transmitted to the client. Treat your backend as the source of truth for all secrets; the frontend should never hold or log authentication material.
This principle applies regardless of integration path:
- Hosted Checkout — server generates the fingerprint, frontend only receives the launch-safe payload
- Payment Links — no client-side secrets at all; the link is the only thing customers see
- REST API — all calls originate server-to-server from your trusted backend, never from browser code
Validating Payments
We provide multiple avenues to validate payments, depending on payment method, including redirectUrl, callbackUrl, webhook, API response, and GET calls. In general, we recommend using multiple data points to ensure validity and reduce the chance of not reconciling correctly.
Post-Payment Verification
Whilst API payments will result in an immediate response, both API and plugin payments can be additionally verified, or additional details checked with our webhook, which will trigger when the paymentStatus, payToStatus, and/or isPaymentSettledToMerchant parameters change. This can be useful in tracking payment state or PayTo token updates/settlement.
These parameters can also be checked with a GET call to the /v2/payments API endpoint.
Parameter Field Validation
Zenith Payments performs basic field validation for parameters, but it is vital to validate all data before it is sent to Zenith Payments. This includes:
- ensuring emails and phone numbers are formatted correctly
- payment amounts are passed as numbers (floats usually) and not strings which can be ambiguous to type-cast (
3456.99is preferred over"3,456.99"which may cause validation issues) - ensuring customer references do not contain special characters
By enforcing strict validation on the frontend and backend, you ensure that the data returned in your post-payment callbacks is predictable and matches your internal records. This proactive approach minimises unexpected "edge case" errors and ensures that your automated reporting and reconciliation processes remain accurate.
Error Handling
Whilst Zenith Payments performs its own data validation, it is important to have logic to handle unexpected data from responses, and error handling for all payment outcomes, including Successful, Failure, Error, In Progress, and Pending transactions. There should be logic to handle any non-success responses gracefully — including unknown or unrecognised fields — to ensure system stability and the best user experience for customers.
Some error messaging we provide is passed along from upstream providers and can depart from regular error messaging. This means it is important to not hard-code error responses as they change from time to time, often without being communicated.
We also recommend having robust and helpful logs to aid in troubleshooting internally, and when working with us to cover any unexpected behaviour. The following details will greatly aid in getting to the bottom of any issues:
- Exact time in UTC
- IP address of user
- Payment payload
- Any returned responses
- Screenshots of the error
Common Pitfalls
Common mistakes that surface during integration or after deployment, and how to avoid them.
Hardcoding Parameter Responses
Whilst some errors are generated by our system, others are generated by upstream payment partners (like messages from card issuers and banks). Due to this, and other factors, we do not recommend hard-coding any error messages into your system without the ability to gracefully handle unexpected responses in those fields.
We endeavour to keep breaking changes to a bare minimum, but parameter responses may change from time to time, and that should be factored in for graceful failures.
Webhook Parameter Casing
In our current version of our webhook (as of February 2026), there are a couple of spelling mistakes in our webhook parameter names. The parameter labels in this documentation are correct, and we have noted these in the description as well.
The other thing to note is that webhooks use upper camel case (VariableName) while API and callback responses use lower camel case (variableName). Your integration should account for this casing difference when parsing payloads from each surface.
Assuming Callback, Webhook, and API responses will have identical payloads
Callbacks, Webhooks, and API responses all have subtley different payloads. Callbacks and Webhooks are largely the same data with the main change being camelCase vs UpperCamelCase. API responses see Payment and Transaction Codes for more detail on some parameters and where they differ.