Skip to content

Developer notes

Technical reference for developers who customize Redsys for CS-Cart and Multi-Vendor.

Item Value
Add-on id kv_redsys
Function prefix fn_kv_redsys_
Language variables kv_redsys.*
CSS scope .kv-redsys
PHP namespace Tygh\Addons\KvRedsys
Preset payment (generated by kv new --kind integration)
Class Role
Signature Message signing, pure functions: HMAC_SHA512_V2 and HMAC_SHA256_V1, per-order key, Base64 / Base64URL, verification of notifications and REST answers
Codes Ds_Response and SIS error texts, ISO 4217 numeric currency table, Ds_Merchant_ConsumerLanguage values
Client\BaseClient HTTP (cURL, TLS verification, timeouts), JSON, error mapping, masked logging (no OAuth for Redsys: $oauth = false)
Client\Api The Redsys calls: signed redirection fields, notification verification, REST refund (type 3), connection probe
PaymentService Order number, redirect parameters, notification handling (applyNotification), order status, refunds (refund, resolveRefund)
Client Client per company, the connection test
Accounts, Secret Merchant code, terminal numbers and signature version per account; terminal keys sealed with AES-256-GCM; one account per store owner or per vendor
Config, Access Settings, owner mode, who may see and manage what
Queue, Jobs, JobException Job queue: back-off 5 min / 15 min / 1 h / 3 h / 12 h, per-job isolation, overlap lock; handlers in Jobs::handle()
Log Event log with masking, filters, CSV, retention
Webhook Reads the notification form fields, idempotency id, the fields that are kept (no card data)
  1. payments/kv_redsys.php (start): PaymentService::initialize() creates a unique 12-character Redsys order number, stores the transaction row (status pending) and only then prints a self-submitting POST form (fn_create_payment_form) to .../sis/realizarPago with Ds_SignatureVersion, Ds_MerchantParameters, Ds_Signature.
  2. Redsys calls the notification URL (kv_redsys.webhook, HTTP POST, form encoded). The controller finds the transaction by Ds_Order, takes the terminal key of the account that owns it, verifies the signature and calls PaymentService::applyNotification() (per-transaction lock, never downgrades a paid payment, amount and currency of an authorization must match). If processing fails the verified data is queued as a webhook job.
  3. The customer returns on Ds_Merchant_URLOK or Ds_Merchant_URLKO (payment_notification.return|cancel). These carry nothing that is trusted (the guide says never to validate an order from them). The handler waits up to 5 s for the notification; when the payment is still pending it empties the cart and the saved cart rows (?:user_session_products) and shows the order, so a signed-in customer cannot pay the same cart twice.
  4. Refunds: PaymentService::refund() locks per payment, stores a refund row (creating) before the REST call, and sends operation type 3 with the order number of the payment. A clear Redsys refusal (errorCode, or Ds_Response other than 900) is recorded as failed; a timeout, an unreadable answer or Ds_Response 912 is recorded as unconfirmed: the amount stays reserved, nothing repeats it, and an administrator confirms in the order tab whether it was executed (after checking the Redsys portal).

All documents were downloaded from the Redsys developer area (pagosonline.redsys.es/desarrolladores-inicio/integrate-con-nosotros/area-de-descargas-y-documentacion/) on 2026-11-07:

Short name Document
REDIR Guia de Integracion por Redireccion, ref. RS.TE.CEL.MAN.0039, v4.2 (04/02/2026)
REST Guia de integracion por REST, v4.0.1 (Annex 2 = HMAC_SHA256_V1)
BIZUM Guia de Integracion BIZUM comercios SIS, ref. RS.TE.CEL.MAN.0033, v2.6
IO “Parametros de entrada y salida” page of the developer area (the spreadsheet itself is not public)
TEST “Tarjetas y entornos de prueba” page of the developer area
REFUND “Devolver o anular un pago” page of the developer area
PHPLIB Redsys PHP integration library 2.0.1: read only to confirm algorithm details and the REST request shape. Its licence forbids redistribution, so none of its code is shipped; Signature is written from the guides.
Use URL Source
Redirection, test https://sis-t.redsys.es:25443/sis/realizarPago REDIR section “Entorno de pruebas”, TEST
Redirection, live https://sis.redsys.es/sis/realizarPago PHPLIB Endpoints, “Autorizacion” page of the developer area
REST refund, test https://sis-t.redsys.es:25443/sis/rest/trataPeticionREST REST “Transacciones directas”, REFUND
REST refund, live https://sis.redsys.es/sis/rest/trataPeticionREST REST, REFUND

Redirection form (HTTP POST from the customer’s browser)

Section titled “Redirection form (HTTP POST from the customer’s browser)”
Field Value Source
Ds_SignatureVersion HMAC_SHA512_V2 (default) or HMAC_SHA256_V1 REDIR section 5 (V2 is “el valor actual”); REST Annex 2 (V1)
Ds_MerchantParameters JSON of the DS_MERCHANT_* parameters, UTF-8, Base64URL without padding (V2) or standard Base64 (V1) REDIR section 6.1.4 and “Error SIS0430”; REST Annex 2 step 2
Ds_Signature see “Signature” REDIR 6.1.3; REST Annex 2
Parameter What the add-on sends Source
DS_MERCHANT_AMOUNT Minor units as an integer string (43.45 EUR = 4345); decimals per currency (0 for JPY, 3 for KWD …) via Money IO
DS_MERCHANT_ORDER 12 characters: 4 digits (order id modulo 10000) + 8 random base-36 characters, new for every attempt IO (“first 4 characters numeric, the rest ASCII letters or digits, max 12”); BIZUM ^[a-zA-Z0-9]{4,12}$; REDIR “SIS0051” (never reuse a number, also not for unfinished attempts)
DS_MERCHANT_MERCHANTCODE Merchant code (FUC), up to 9 digits IO, TEST
DS_MERCHANT_TERMINAL Terminal number as configured (default 1) IO, TEST (“001” and “1” both appear in the guides)
DS_MERCHANT_CURRENCY ISO 4217 numeric code (978 EUR, 840 USD …) from the table in Codes (140 ISO 4217 currency codes taken from List One, published 2026-09-17, not every code of the list; a currency outside the table is refused; the amount uses the ISO exponent from Money: 0 for XOF, XAF, XPF, PYG, JPY, KRW …, 3 for BHD, IQD, JOD, KWD, LYD, OMR, TND) IO
DS_MERCHANT_TRANSACTIONTYPE 0 (authorization) IO, BIZUM 2.2.1
DS_MERCHANT_MERCHANTURL Notification URL, https, max 250 characters IO, REDIR section 7
DS_MERCHANT_URLOK / DS_MERCHANT_URLKO Return URLs, max 250 characters IO, REDIR “Mostrar Recibo”
DS_MERCHANT_PAYMETHODS z (lower case) only for the Bizum payment method; omitted otherwise BIZUM 2.2.1; IO
DS_MERCHANT_PRODUCTDESCRIPTION Payment description + #order id, cut to 125 characters name: PHPLIB Parameters; length 125 not verified in a public document
DS_MERCHANT_CONSUMERLANGUAGE 001 es, 002 en, 003 ca, 010 va, 012 gl, 013 eu; other languages omit it (Redsys detects the browser language) name: REDIR page; values: PHPLIB Utils; the full table is in the non-public spreadsheet
DS_MERCHANT_EMV3DS {"email": ..., "cardholderName": ...} when the setting is on REDIR 6.1.4 example (keys email, cardholderName); field lengths not verified (name cut at 45, e-mail at 254 as in EMV 3DS)
Step HMAC_SHA512_V2 (REDIR 6.1.2, 6.1.3) HMAC_SHA256_V1 (REST Annex 2)
Terminal key first 16 characters of the key text, right-padded with 0 Base64-decode the key (24 bytes)
Per-order key AES-128-CBC, zero IV, encrypt the order number with that key; the Base64 string of the result is the HMAC key 3DES-CBC, zero IV, encrypt the order number zero-padded to a multiple of 8 bytes
Signature HMAC-SHA512 over the Ds_MerchantParameters string, Base64URL without padding HMAC-SHA256 over the Ds_MerchantParameters string, Base64
Verification of a notification / answer Decode Ds_MerchantParameters only to read Ds_Order; sign the string exactly as received; compare (REDIR 6.1.3 “Respuesta”; REST “Estructura de respuesta”) same

The comparison ignores the Base64 / Base64URL spelling and padding (Signature::same) and uses hash_equals.

Vector Value Source
Test terminal key sq7HjrUOBfKmC576ILgskD5srU870gJ7 (merchant 999008881, terminal 001) TEST, REDIR
V2 derived key, order 1234567890 RWt3/IPTzYRMXsQtkiGRKg== REDIR 6.1.2
V2 signature of the guide’s Ds_MerchantParameters Vjo02eSWq249IeZZp3R-ArFnGLhKY0OuzDDlx1BuVtZDC2yhczA7_11uZhsYzLZBCMFAz8u8uzGDX3AErHKmmw REDIR 6.1.3
V1 derived key (hex), order 06080232580 a5334014a4f010c8779cef789886c123 REST Annex 2
V1 signature of the guide’s refund request GmHwTovthyrztLs7D77GflclBzsANderHe3zFF6JiZQ= REST Annex 2

All four are asserted in tests/unit.php; the mock server (an independent JavaScript implementation) verifies the PHP signatures of both versions.

Notification (Redsys -> Ds_Merchant_MerchantURL, HTTP POST)

Section titled “Notification (Redsys -> Ds_Merchant_MerchantURL, HTTP POST)”
Field Use Source
Ds_SignatureVersion, Ds_MerchantParameters, Ds_Signature verified as above REDIR section 7
Ds_Order finds the transaction (the number we generated) IO
Ds_Response 0000 to 0099 = authorized payment; 9915 = cancelled by the customer (Codes, PHPLIB response table); 8210, 8220, 9998, 9999 = operation still under way (not a failure); anything else = denied REDIR “Resultado de la Operacion”; PHPLIB response table
Ds_Amount, Ds_Currency must equal the amount and numeric currency sent, otherwise the authorization is not accepted IO
Ds_TransactionType only type 0 changes the payment; others are logged and ignored IO
Ds_AuthorisationCode, Ds_SecurePayment, Ds_ProcessedPayMethod stored / logged; no card data is kept IO

The guide states that the result must be taken only from this POST and never from the data of the HTTP GET on the OK/KO URLs.

Request Content-Type: application/json, body {"Ds_SignatureVersion", "Ds_MerchantParameters", "Ds_Signature"} (REST “Estructura de una peticion REST”; the key names are the same in the PHPLIB RequestData). Parameters: DS_MERCHANT_ORDER (the order number of the payment), DS_MERCHANT_MERCHANTCODE, DS_MERCHANT_TERMINAL, DS_MERCHANT_TRANSACTIONTYPE=3, DS_MERCHANT_CURRENCY, DS_MERCHANT_AMOUNT (REFUND, REST “Peticion de Confirmacion/Devolucion/Anulacion”). Total or partial; the sum of refunds never exceeds the authorized amount (REFUND). Ds_Response 0900 = refunded (REFUND, REDIR). Bizum payments are refunded the same way (BIZUM 2.3). A failure is {"errorCode":"SIS...."} (REST). Timeout: Redsys answers within 30 s (code 912 / 9912 “issuer unavailable”); the client timeout is 50 s; “for refunds the request may be repeated” (REST “Timeout”), which is why the add-on never repeats it by itself but asks the administrator to check the portal.

SIS0042 signature, SIS0054 no operation exists for the refund, SIS0057 refund above the limit, SIS0051 repeated order number, SIS0026 merchant / terminal unknown, SIS0027 currency, SIS0430 parameters not decodable (texts from the PHPLIB resource file, rewritten in Codes::sisText).

Redsys has no read-only credentials call. The probe sends a type-3 refund of the non-existing order 0000KVPROBE0 for 0.01: Redsys answers SIS0054 when merchant code, terminal and signature are accepted, SIS0042 / SIS0026 / SIS0027 otherwise. The meaning of SIS0054 for this probe is inferred from the error table, not documented as a connection test. The daily automatic probe runs only in test mode.

Flagged: not verifiable from public documents

Section titled “Flagged: not verifiable from public documents”
  • The meaning of Ds_Merchant_PayMethods values other than z (the table is not public); the “card only” choice is therefore not offered, “all methods enabled on the terminal” omits the parameter.
  • Field lengths of DS_MERCHANT_PRODUCTDESCRIPTION and DS_MERCHANT_EMV3DS; language codes other than the six listed.
  • Whether the live sis.redsys.es accepts both signature versions for a terminal: it depends on the terminal configuration at the bank; the guides call V2 current. Use V1 only for older terminals.
  • Bizum test data: BIZUM and TEST give user 700000000, e-mail [email protected], PIN 1234, SMS code 123456, amounts up to 10 EUR; not exercised here because the sandbox is not reachable from CI.
  • REST refunds are signed with the account’s signature version. The REST guide 4.0.1 documents HMAC_SHA256_V1 (Annex 2); if a terminal’s REST interface refuses V2 (Test connection answers SIS0042 with V2), switch the account to HMAC_SHA256_V1.
  • Which IP addresses Redsys notifies from (not published): do not IP-filter the notification URL; the signature is the protection. The URL must use the standard HTTPS port.
Table Purpose
?:kv_redsys_accounts Merchant code, sealed terminal keys, terminals and signature version (in extra), last connection check
?:kv_redsys_log Log
?:kv_redsys_jobs Queue
?:kv_redsys_transactions One row per payment attempt: Redsys order number (provider_ref, unique), status, answer code, authorization code, method (card / bizum), the order total at the start (order_total, compared when the money arrives). Multi-Vendor owner mode: a cart with several vendors is one row on the parent order
?:kv_redsys_refunds Refund rows: creating, done, failed, unconfirmed
Hook Why
prepare_checkout_payment_methods hides the method while the add-on is disabled, unlicensed or has no credentials
change_order_status_post optional full refund when an order reaches the configured status (never from a vendor in owner mode)
init_templater_post upgrade synchronizer
Template hooks orders:tabs_extra (admin), addons:manage, addons:tabs_content, index:styles order tab, add-on badge and styles

The base URL can be overridden for tests in config.local.php (development only):

$config['kv_redsys_base_url'] = 'http://127.0.0.1:11830';

node tests/mock-server/server.js 11830 starts a local stand-in of the TPV Virtual that verifies both signature versions, refuses repeated order numbers, posts signed notifications on request and answers REST refunds; node tests/e2e/e2e.mjs runs the HTTP end-to-end test against it; php tests/unit.php runs the unit tests. This proves the add-on against the documentation, not against the Redsys test environment.

Admin templates live in design/backend/templates/addons/kv_redsys/. Do not edit them in a store; they are replaced on update.

Redsys is a trademark of Redsys Servicios de Procesamiento, S.L.; Bizum is a trademark of Bizum. This add-on is not affiliated with or endorsed by either. No Redsys or Bizum logo is bundled: the Bizum guide provides official buttons in the “Botones Bizum” package of the merchant administration portal, which a store owner may upload as the payment method image.