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 PaymentId record, 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.

  1. Read the cart

    Load products, variations, totals and customer details from WooCommerce.

  2. Create an order

    Add line items, addresses and delivery, calculate the total and leave the order pending payment.

  3. Build the receipt

    Provide item names, prices, quantities, amounts, tax settings and customer contacts.

  4. 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.

The boundary of the old example
IncludedMissing
Local order creationPaymentId persistence and control
Total and receipt preparationServer-to-server bank notifications
Payment form launchNotification signature verification
Customer contact fieldsTransaction status tracking
Customer return flowIdempotent order confirmation
A single payment attemptRetries, 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

  1. Persist the order server-side

    Calculate the amount, currency and items from trusted order data, not hidden browser fields.

  2. Initialize payment server-side

    Create the bank operation and store its identifier and payment URL next to the local order.

  3. Keep a status history

    Store the current state and an audit trail of transitions, timestamps and event sources.

  4. Process notifications

    A public callback verifies the signature, resolves the expected operation and applies the update inside a database transaction.

  5. Guarantee idempotency

    A repeated notification or network retry must not confirm the order or execute the business action twice.

  6. Check stalled payments

    A scheduled job requests the current state when a notification is missing or processing failed.

  7. 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


Let’s discuss your project

Tell me what you would like to build. I will reply by email.

Or message me on Telegram @ifwcom