diff --git a/CHANGELOG.md b/CHANGELOG.md
index 846e986..2614bec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [3.6.2] - 2026-09-02
+### Added
+- Add support for the `session_id` parameter in `cardWallet/authorize`.
+- Add support for the `RedirectResponse` of `PaymentRequestResponse`, used for 3D Secure redirects.
+- Add support for `MethodConfigurations` and `Schemes` of a terminal in `getTerminals`.
+
+### Fixes
+- Fix reading of child elements that carry only attributes.
+
## [3.6.1] - 2026-06-23
### Added
- Add support for new parameters in `cardWallet/session` and `cardWallet/authorize`.
diff --git a/docs/index.md b/docs/index.md
index 6198b8b..31c96c8 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -34,6 +34,8 @@ Docs: https://testgateway.altapaysecure.com/merchant.php/help/Merchant_API
| x [Credit](payments/credit.md) | This will create a Credit payment. The payment can be made with a credit card, or a credit card token and the CVV |
| x [Update Order](payments/update_order.md) | This method is used to update the order amount and add, remove or update order lines |
| - [Invoice reservation](payments/invoice_reservation.md) | |
+| [Card wallet session](payments/card_wallet_session.md) | This endpoint initiates a new payment using the Card Wallet flow and retrieves merchant session data. |
+| [Card wallet authorize](payments/card_wallet_authorize.md) | This step finalizes the Card Wallet payment by authorizing the previously registered payment. |
### Subscription
diff --git a/docs/payments/card_wallet_authorize.md b/docs/payments/card_wallet_authorize.md
new file mode 100644
index 0000000..570e798
--- /dev/null
+++ b/docs/payments/card_wallet_authorize.md
@@ -0,0 +1,84 @@
+[<](../index.md) Altapay - PHP Api - Card wallet authorize
+================================================================
+
+This step finalizes the Card Wallet payment by authorizing the previously registered payment.
+
+The payment is registered beforehand with [card wallet session](card_wallet_session.md).
+
+- [Request](#request)
+ + [Required](#required)
+ + [Optional](#optional)
+ + [Example](#example)
+- [Response](#response)
+
+# Request
+
+```php
+$request = new \Altapay\Api\Payments\CardWalletAuthorize($auth);
+// Do the call
+try {
+ $response = $request->call();
+ // See Response below
+} catch (\Altapay\Exceptions\ClientException $e) {
+ // Could not connect
+} catch (\Altapay\Exceptions\ResponseHeaderException $e) {
+ // Response error in header
+ $e->getHeader()->ErrorMessage
+} catch (\Altapay\Exceptions\ResponseMessageException $e) {
+ // Error message
+ $e->getMessage();
+}
+```
+
+### Required
+
+| Method | Description | Type |
+|---|---|---|
+| setProviderData(string) | The payment token of the wallet, passed on as the wallet provided it. | string
+| setTerminal(string) | The title of your terminal
It is also possible to pass in a terminal name with the currency as wildcard. Ex. 'My {currency} Terminal' would use the 'My EUR Terminal' if you also pass EUR along as the currency. | string
+| setShopOrderId(string) | The id of the order in your webshop. This is what we will post back to you so you know which order a given payment is associated with. | [a-zA-Z0-9]{1,100} |
+| setAmount(float) | The amount of the payment in english notation (ex. 89.95)
For a subscription the amount is the default amount for each capture.
Amount is limited to 2 decimals, an error will be returned if more decimals is supplied. | int, float
+| setCurrency(string) | The currency of the payment in ISO-4217 format. Either the 3-digit numeric code, or the 3-letter character code. | string, int - [See currencies](../types/currencies.md)
+
+### Optional
+
+| Method | Description | Type |
+|---|---|---|
+| setPaymentId(string) | The `payment_id` of the payment the wallet session registered. | string
+| setSessionId(string) | The `session_id` the payment was registered with, required by terminals that expect an external session id. | string
+
+The optional parameters of [payment request](../ecommerce/payment_request.md) apply here as well.
+
+### Example
+
+```php
+$request = new \Altapay\Api\Payments\CardWalletAuthorize($auth);
+$request->setTerminal('my terminal');
+$request->setShopOrderId('123456');
+$request->setAmount(200.45);
+$request->setCurrency('SEK');
+$request->setProviderData($walletToken);
+$request->setSessionId('session id');
+$request->setPaymentId('payment id');
+```
+
+# Response
+
+Object of `\Altapay\Response\PaymentRequestResponse`
+
+| Method | Description | Type |
+|---|---|---|
+| `$response->Result` | | string
+| `$response->Transactions` | | array
+| `$response->RedirectResponse` | | `\Altapay\Response\Embeds\InitiatePaymentRedirectResponse`
+
+A result of `Redirect` means the payment has to be continued somewhere else before it is authorized, for instance to authenticate the cardholder with 3D Secure. This happens for the cards a wallet provides without a cryptogram.
+
+### `\Altapay\Response\Embeds\InitiatePaymentRedirectResponse`
+
+| Method | Description | Type |
+|---|---|---|
+| `$object->Url` | | string
+| `$object->Method` | | string
+| `$object->Data` | | array
+| `$object->FlowType` | | string
diff --git a/docs/payments/card_wallet_session.md b/docs/payments/card_wallet_session.md
new file mode 100644
index 0000000..7b55cc0
--- /dev/null
+++ b/docs/payments/card_wallet_session.md
@@ -0,0 +1,81 @@
+[<](../index.md) Altapay - PHP Api - Card wallet session
+================================================================
+
+This endpoint initiates a new payment using the Card Wallet flow and retrieves merchant session data.
+
+The payment is authorized afterwards with [card wallet authorize](card_wallet_authorize.md).
+
+- [Request](#request)
+ + [Required](#required)
+ + [Optional](#optional)
+ + [Example](#example)
+- [Response](#response)
+
+# Request
+
+```php
+$request = new \Altapay\Api\Payments\CardWalletSession($auth);
+// Do the call
+try {
+ $response = $request->call();
+ // See Response below
+} catch (\Altapay\Exceptions\ClientException $e) {
+ // Could not connect
+} catch (\Altapay\Exceptions\ResponseHeaderException $e) {
+ // Response error in header
+ $e->getHeader()->ErrorMessage
+} catch (\Altapay\Exceptions\ResponseMessageException $e) {
+ // Error message
+ $e->getMessage();
+}
+```
+
+### Required
+
+| Method | Description | Type |
+|---|---|---|
+| setTerminal(string) | The title of your terminal
It is also possible to pass in a terminal name with the currency as wildcard. Ex. 'My {currency} Terminal' would use the 'My EUR Terminal' if you also pass EUR along as the currency. | string
+| setShopOrderId(string) | The id of the order in your webshop. This is what we will post back to you so you know which order a given payment is associated with. | [a-zA-Z0-9]{1,100} |
+| setAmount(float) | The amount of the payment in english notation (ex. 89.95)
For a subscription the amount is the default amount for each capture.
Amount is limited to 2 decimals, an error will be returned if more decimals is supplied. | int, float
+| setCurrency(string) | The currency of the payment in ISO-4217 format. Either the 3-digit numeric code, or the 3-letter character code. | string, int - [See currencies](../types/currencies.md)
+
+### Optional
+
+| Method | Description | Type |
+|---|---|---|
+| setSessionId(string) | The `session_id` the payment is registered with, required by terminals that expect an external session id. | string
+| setApplePayRequestData(array) | The `validationUrl` and `domain` of the merchant validation. Apple Pay only. | array
+| setValidationUrl(string) | The validation url of the event. Apple Pay only, of the legacy flow. | string
+| setDomain(string) | The domain initiating the request. Apple Pay only, of the legacy flow. | string
+
+The optional parameters of [payment request](../ecommerce/payment_request.md) apply here as well.
+
+Google Pay requires no provider specific parameters here, as it is configured on the frontend.
+
+### Example
+
+```php
+$request = new \Altapay\Api\Payments\CardWalletSession($auth);
+$request->setTerminal('my terminal');
+$request->setShopOrderId('123456');
+$request->setAmount(200.45);
+$request->setCurrency('SEK');
+$request->setSessionId('session id');
+```
+
+# Response
+
+Object of `\Altapay\Response\CardWalletSessionResponse`
+
+| Method | Type |
+|---|---|
+| `$response->Result` | string
+| `$response->Transactions` | array
+| `$response->WalletData` | `\Altapay\Response\Embeds\WalletData`
+| `$response->ApplePaySession` | string
+
+### `\Altapay\Response\Embeds\WalletData`
+
+| Method | Type |
+|---|---|
+| `$object->Session` | string
diff --git a/docs/types/terminal.md b/docs/types/terminal.md
index 89d3865..6566fb8 100644
--- a/docs/types/terminal.md
+++ b/docs/types/terminal.md
@@ -12,6 +12,8 @@
| `$object->Methods` | array of `\Altapay\Response\Embeds\Method` objects | array
| `$object->Products` | array of `\Altapay\Response\Embeds\Product` objects | array
| `$object->PrimaryMethod` | | `\Altapay\Response\Embeds\PrimaryMethod`
+| `$object->MethodConfigurations` | array of `\Altapay\Response\Embeds\MethodConfig` objects | array
+| `$object->Schemes` | array of `\Altapay\Response\Embeds\Scheme` objects | array
| `$object->CanUseCredit` | | boolean
| `$object->CanIssueNewCredit` | | boolean
| `$object->LogoUrl` | | string
@@ -43,6 +45,27 @@
| `$object->Identifier` | | string
| `$object->SupportedAgreementTypes` | | array of `\Altapay\Response\Embeds\AgreementType` objects
+### `\Altapay\Response\Embeds\MethodConfig`
+
+The configuration of one of the acquirers of the terminal. The details a wallet needs on the frontend, such as the environment and the merchant identity, are found here.
+
+| Method | Description | Type |
+|---|---|---|
+| `$object->method` | | string
+| `$object->identifier` | | string
+| `$object->WalletEnvironment` | | string
+| `$object->MerchantId` | | string
+| `$object->MerchantName` | | string
+| `$object->ClientId` | | string
+| `$object->SupportedCustomerType` | | string
+
+### `\Altapay\Response\Embeds\Scheme`
+
+| Method | Description | Type |
+|---|---|---|
+| `$object->code` | | string
+| `$object->Scheme` | | string
+
### `\Altapay\Response\Embeds\AgreementType`
| Method | Description | Type |
diff --git a/src/AbstractApi.php b/src/AbstractApi.php
index d7da726..0127be4 100644
--- a/src/AbstractApi.php
+++ b/src/AbstractApi.php
@@ -55,7 +55,7 @@ abstract class AbstractApi
/**
* PHP API version
*/
- const PHP_API_VERSION = '3.6.1';
+ const PHP_API_VERSION = '3.6.2';
/**
* Event dispatcher
diff --git a/src/Api/Payments/CardWalletAuthorize.php b/src/Api/Payments/CardWalletAuthorize.php
index b55cd7f..ab93ec1 100644
--- a/src/Api/Payments/CardWalletAuthorize.php
+++ b/src/Api/Payments/CardWalletAuthorize.php
@@ -270,6 +270,18 @@ public function setPaymentId($paymentId)
return $this;
}
+ /**
+ * @param string $sessionId
+ *
+ * @return $this
+ */
+ public function setSessionId($sessionId)
+ {
+ $this->unresolvedOptions['session_id'] = $sessionId;
+
+ return $this;
+ }
+
/**
* Configure options
*
@@ -299,6 +311,7 @@ protected function configureOptions(OptionsResolver $resolver)
'organisation_number',
'account_offer',
'payment_id',
+ 'session_id',
]);
$resolver->addAllowedTypes('provider_data', 'string');
$resolver->setAllowedValues('language', Types\LanguageTypes::getAllowed());
@@ -327,6 +340,7 @@ protected function configureOptions(OptionsResolver $resolver)
return $value ? 'required' : 'disabled';
});
$resolver->addAllowedTypes('payment_id', 'string');
+ $resolver->addAllowedTypes('session_id', 'string');
}
/**
diff --git a/src/Response/Embeds/MethodConfig.php b/src/Response/Embeds/MethodConfig.php
new file mode 100644
index 0000000..65ab729
--- /dev/null
+++ b/src/Response/Embeds/MethodConfig.php
@@ -0,0 +1,50 @@
+ PrimaryMethod::class,
'array' => false
],
+ 'MethodConfigurations' => [
+ 'class' => MethodConfig::class,
+ 'array' => 'MethodConfig'
+ ],
+ 'Schemes' => [
+ 'class' => Scheme::class,
+ 'array' => 'Scheme'
+ ],
];
/** @var string */
@@ -103,4 +111,14 @@ class Terminal extends AbstractResponse
/** @var bool */
public $CanIssueNewCredit;
+
+ /**
+ * @var MethodConfig[]
+ */
+ public $MethodConfigurations = [];
+
+ /**
+ * @var Scheme[]
+ */
+ public $Schemes = [];
}
diff --git a/src/Response/PaymentRequestResponse.php b/src/Response/PaymentRequestResponse.php
index 4c338e3..c47bbeb 100644
--- a/src/Response/PaymentRequestResponse.php
+++ b/src/Response/PaymentRequestResponse.php
@@ -24,6 +24,7 @@
namespace Altapay\Response;
use Altapay\Response\Embeds\Transaction;
+use Altapay\Response\Embeds\InitiatePaymentRedirectResponse;
class PaymentRequestResponse extends AbstractResponse
{
@@ -37,6 +38,10 @@ class PaymentRequestResponse extends AbstractResponse
'class' => Transaction::class,
'array' => 'Transaction'
],
+ 'RedirectResponse' => [
+ 'class' => InitiatePaymentRedirectResponse::class,
+ 'array' => false
+ ],
];
/**
@@ -78,4 +83,7 @@ class PaymentRequestResponse extends AbstractResponse
/** @var string */
public $CardHolderMessageMustBeShown;
+
+ /** @var string */
+ public $RedirectResponse = null;
}
diff --git a/src/Serializer/ResponseSerializer.php b/src/Serializer/ResponseSerializer.php
index ecb0908..4a4f95c 100644
--- a/src/Serializer/ResponseSerializer.php
+++ b/src/Serializer/ResponseSerializer.php
@@ -72,7 +72,7 @@ public static function serializeChildren(
) {
$documents = [];
- if (! empty($data) && ! empty($data->{$childKey}) && $data->{$childKey} instanceof \SimpleXMLElement) {
+ if (! empty($data) && isset($data->{$childKey}) && $data->{$childKey} instanceof \SimpleXMLElement) {
foreach ($data->{$childKey} as $d) {
$object = new $objectName();
$documents[] = $object->deserialize($d);