Basic Tinkoff (T-Bank) Acquiring Integration for WooCommerce
Practice · WooCommerce · acquiring · PHP
A historical example of connecting a Tinkoff payment form to a custom WooCommerce checkout flow. The code created an order, prepared receipt data and redirected the customer to payment. This is a simple and primitive integration: it launches the payment form but does not track the transaction afterwards.
Important: this approach is not a complete production payment integration. It has no server-side
PaymentIdrecord, bank notifications, final status verification, idempotent order update or automated reconciliation.
What the original code did
The project used WooCommerce but bypassed the standard plugin checkout flow. It had to read products and customer details from the current cart, create an order programmatically, build receipt data and open the bank's payment form.
Read the cart
Load products, variations, totals and customer details from WooCommerce.
Create an order
Add line items, addresses and delivery, calculate the total and leave the order pending payment.
Build the receipt
Provide item names, prices, quantities, amounts, tax settings and customer contacts.
Open the bank form
Fill hidden fields and redirect the customer through the client-side payment script.
What was implemented
Cart connection
The WooCommerce cart was converted into a local order.
Customer details
Name, phone number and email were passed to the form.
Receipt data
A JSON receipt contained items, prices, quantities and tax parameters.
Payment redirect
The payment JavaScript submitted the form and opened the bank page.
Why this is only a basic connection
Redirecting a customer to a payment page does not mean that money was received. The customer may close the tab, receive a decline, retry later or revisit an old return URL.
The original implementation did not store the bank operation identifier or maintain a payment state machine. The order was linked to the browser in a simplified way, and the final result was not verified independently of the return page.
| Included | Missing |
|---|---|
| Local order creation | PaymentId persistence and control |
| Total and receipt preparation | Server-to-server bank notifications |
| Payment form launch | Notification signature verification |
| Customer contact fields | Transaction status tracking |
| Customer return flow | Idempotent order confirmation |
| A single payment attempt | Retries, cancellation, refunds and reconciliation |
A return page must not mark an order as paid
A success page is useful for the interface, but it is not proof of payment. The customer might never open it, and its query parameters are not a trusted data source.
The order status should change only after bank-side confirmation: a verified server notification or an explicit payment status request. Replaying the same notification must not issue goods, balance or bonuses twice.
local order: pending_payment
↓
create bank payment → save PaymentId
↓
customer pays on the bank page
↓
verified notification / status request
↓
paid | failed | cancelled | refunded
Building a complete integration
Persist the order server-side
Calculate the amount, currency and items from trusted order data, not hidden browser fields.
Initialize payment server-side
Create the bank operation and store its identifier and payment URL next to the local order.
Keep a status history
Store the current state and an audit trail of transitions, timestamps and event sources.
Process notifications
A public callback verifies the signature, resolves the expected operation and applies the update inside a database transaction.
Guarantee idempotency
A repeated notification or network retry must not confirm the order or execute the business action twice.
Check stalled payments
A scheduled job requests the current state when a notification is missing or processing failed.
Reconcile
Orders, bank operations, refunds and actual settlements are compared, with mismatches routed for review.
Minimum production checklist
- SecretsThe terminal password remains server-side and never enters HTML, JavaScript or the repository.
- AmountCalculated from trusted server-side order data.
- LinkageThe local order is linked to every bank payment attempt and
PaymentId. - CallbackNotifications are cryptographically verified and handled idempotently.
- StatusesAllowed transitions are explicit; unexpected transitions are not silently applied.
- RetriesNetwork errors use bounded retries without duplicate business effects.
- ReconciliationIncomplete and inconsistent operations are checked periodically.
- ObservabilityLogs contain order and operation IDs, but no payment details or secrets.
When the simplified version is acceptable
This approach can serve as a prototype for testing the interface, demonstrating the payment redirect or supporting a temporary workflow with manual verification. Even then, submitting the form alone must never trigger automatic fulfilment or mark the order as paid.
A store, subscription, digital product, internal balance or any financially important process needs a server-side transaction lifecycle. The payment form starts an operation; it does not confirm the outcome.
WooCommerce · PHP · Acquiring · Payment Status · Webhooks · Idempotency
