mirrorps / yii2-taler
Yii2 extension for GNU Taler REST API integration
Requires
- php: >=8.1
- guzzlehttp/guzzle: ^7.0
- mirrorps/taler-php: dev-main
- psr/http-client: ^1.0
- yiisoft/yii2: ^2.0
Requires (Dev)
- phpunit/phpunit: ^10.0
- roave/security-advisories: dev-latest
This package is auto-updated.
Last update: 2026-04-27 15:40:45 UTC
README
Notice: This package is under active development, and the code may change.
Yii2 extension for GNU Taler REST API integration.
Installation
composer require mirrorps/yii2-taler
Configuration
Add the Taler component to your application configuration:
'components' => [ 'taler' => [ 'class' => \mirrorps\Yii2Taler\Taler::class, 'baseUrl' => 'https://backend.demo.taler.net/instances/sandbox', 'token' => 'Bearer secret-token:sandbox', // OR credential-based auth: // 'username' => 'merchant', // 'password' => 'secret', // 'instance' => 'sandbox', ], ],
Config API
The Config API is accessible via Yii::$app->taler->configs().
Get Merchant Config
use Taler\Api\Config\Dto\MerchantVersionResponse; $config = Yii::$app->taler->configs()->getConfig(); if ($config instanceof MerchantVersionResponse) { echo $config->name . PHP_EOL; // taler-merchant echo $config->version . PHP_EOL; // libtool format current:revision:age echo $config->currency . PHP_EOL; // default currency foreach ($config->currencies as $code => $spec) { echo $code . ' => ' . $spec->name . PHP_EOL; } foreach ($config->exchanges as $exchange) { echo $exchange->base_url . PHP_EOL; } }
Async Config Call
$promise = Yii::$app->taler->configs()->getConfigAsync(); $config = $promise->wait();
Credential Health Check
$report = Yii::$app->taler->configCheck(); if ($report['ok']) { echo "All checks passed" . PHP_EOL; } else { print_r($report); }
Order API
The Order API is accessible via Yii::$app->taler->orders().
List Orders
use Taler\Api\Order\Dto\GetOrdersRequest; // List all orders (default limit) $orderHistory = Yii::$app->taler->orders()->getOrders(); foreach ($orderHistory->orders as $entry) { echo $entry->order_id . ' — ' . $entry->summary . ' — ' . $entry->amount . PHP_EOL; } // With filters $orderHistory = Yii::$app->taler->orders()->getOrders( new GetOrdersRequest(paid: true, limit: 10) );
Get Order Details
use Taler\Api\Order\Dto\GetOrderRequest; use Taler\Api\Order\Dto\CheckPaymentPaidResponse; use Taler\Api\Order\Dto\CheckPaymentUnpaidResponse; use Taler\Api\Order\Dto\CheckPaymentClaimedResponse; $order = Yii::$app->taler->orders()->getOrder('my-order-id-2025-1'); if ($order instanceof CheckPaymentPaidResponse) { echo 'Paid! Deposit total: ' . $order->deposit_total . PHP_EOL; } elseif ($order instanceof CheckPaymentUnpaidResponse) { echo 'Unpaid. Payment URI: ' . $order->taler_pay_uri . PHP_EOL; } elseif ($order instanceof CheckPaymentClaimedResponse) { echo 'Claimed by wallet.' . PHP_EOL; }
Create Order
use Taler\Api\Order\Dto\Amount; use Taler\Api\Order\Dto\OrderV0; use Taler\Api\Order\Dto\PostOrderRequest; $order = new OrderV0( summary: 'T-Shirt (GNU Taler demo)', amount: new Amount('KUDOS:10.00'), fulfillment_message: 'Thank you for purchasing a T-Shirt!', ); $response = Yii::$app->taler->orders()->createOrder( new PostOrderRequest(order: $order) ); echo 'Created order: ' . $response->order_id . PHP_EOL; if ($response->token !== null) { echo 'Claim token: ' . $response->token . PHP_EOL; }
Refund Order
use Taler\Api\Order\Dto\RefundRequest; $refundResponse = Yii::$app->taler->orders()->refundOrder( 'my-order-id-2025-1', new RefundRequest( refund: 'KUDOS:5.00', reason: 'Customer requested refund', ) ); echo 'Refund URI: ' . $refundResponse->taler_refund_uri . PHP_EOL;
Delete Order
Yii::$app->taler->orders()->deleteOrder('my-order-id-2025-1'); echo 'Order deleted.' . PHP_EOL;
Forget Order Fields
use Taler\Api\Order\Dto\ForgetRequest; Yii::$app->taler->orders()->forgetOrder( 'my-order-id-2025-1', new ForgetRequest(fields: ['$.delivery_location']) ); echo 'Fields forgotten.' . PHP_EOL;
Instance API
The Instance API is accessible via Yii::$app->taler->instances().
List Instances
$list = Yii::$app->taler->instances()->getInstances(); foreach ($list->instances as $instance) { echo $instance->id . ' — ' . $instance->name . PHP_EOL; }
NOTE: If your backend returns
404, you are likely using a per-instance base URL such ashttps://backend.demo.taler.net/instances/sandbox. In that setup, use the single-instance private endpoint instead:GET https://backend.demo.taler.net/instances/sandbox/private
Get Instance Details
$details = Yii::$app->taler->instances()->getInstance('shop-1'); echo $details->name; // e.g., "My Shop" echo $details->merchant_pub; // EddsaPublicKey
Create Instance
use Taler\Api\Instance\Dto\InstanceConfigurationMessage; use Taler\Api\Instance\Dto\InstanceAuthConfigToken; use Taler\Api\Dto\Location; use Taler\Api\Dto\RelativeTime; $config = new InstanceConfigurationMessage( id: 'shop-1', name: 'My Shop', auth: new InstanceAuthConfigToken(password: 'super-secret'), address: new Location(country: 'DE', town: 'Berlin'), jurisdiction: new Location(country: 'DE', town: 'Berlin'), use_stefan: true, default_wire_transfer_delay: new RelativeTime(3600_000_000), default_pay_delay: new RelativeTime(300_000_000), email: 'merchant@example.com', ); Yii::$app->taler->instances()->createInstance($config);
Update Instance
use Taler\Api\Instance\Dto\InstanceReconfigurationMessage; use Taler\Api\Dto\Location; use Taler\Api\Dto\RelativeTime; $patch = new InstanceReconfigurationMessage( name: 'My Shop GmbH', address: new Location(country: 'DE', town: 'Berlin'), jurisdiction: new Location(country: 'DE', town: 'Berlin'), use_stefan: true, default_wire_transfer_delay: new RelativeTime(7200_000_000), default_pay_delay: new RelativeTime(600_000_000), website: 'https://shop.example.com', ); Yii::$app->taler->instances()->updateInstance('shop-1', $patch);
Delete Instance
use Taler\Api\TwoFactorAuth\Dto\ChallengeResponse; // Disable instance $result = Yii::$app->taler->instances()->deleteInstance('shop-1'); if ($result instanceof ChallengeResponse) { echo '2FA required. Challenge ID: ' . $result->getChallengeId() . PHP_EOL; } // Purge instance (irreversible) Yii::$app->taler->instances()->deleteInstance('shop-1', purge: true);
Authentication & Access Tokens
use Taler\Api\Instance\Dto\LoginTokenRequest; use Taler\Api\Instance\Dto\GetAccessTokensRequest; use Taler\Api\Dto\RelativeTime; // Request a login token $token = Yii::$app->taler->instances()->getAccessToken( 'shop-1', new LoginTokenRequest( scope: 'order-full', duration: new RelativeTime(3_600_000_000), description: 'Backoffice session', ) ); echo $token->access_token . PHP_EOL; // List issued tokens $tokens = Yii::$app->taler->instances()->getAccessTokens( 'shop-1', new GetAccessTokensRequest(limit: -20) ); if ($tokens !== null) { foreach ($tokens->tokens as $t) { echo $t->serial . ' ' . $t->scope . PHP_EOL; } } // Revoke current token Yii::$app->taler->instances()->deleteAccessToken('shop-1'); // Revoke token by serial Yii::$app->taler->instances()->deleteAccessTokenBySerial('shop-1', 123);
Update Auth
use Taler\Api\Instance\Dto\InstanceAuthConfigToken; $result = Yii::$app->taler->instances()->updateAuth( 'shop-1', new InstanceAuthConfigToken(password: 'new-secret') );
Forgot Password
use Taler\Api\Instance\Dto\InstanceAuthConfigToken; $result = Yii::$app->taler->instances()->forgotPassword( 'shop-1', new InstanceAuthConfigToken(password: 'new-password') );
KYC Status
use Taler\Api\Instance\Dto\GetKycStatusRequest; $kyc = Yii::$app->taler->instances()->getKycStatus('shop-1'); if ($kyc !== null) { foreach ($kyc->kyc_data as $entry) { echo $entry->exchange_url . PHP_EOL; } }
Merchant Statistics
use Taler\Api\Instance\Dto\GetMerchantStatisticsAmountRequest; use Taler\Api\Instance\Dto\GetMerchantStatisticsCounterRequest; $amounts = Yii::$app->taler->instances()->getMerchantStatisticsAmount( 'shop-1', 'ORDERS', new GetMerchantStatisticsAmountRequest(by: 'BUCKET') ); $counters = Yii::$app->taler->instances()->getMerchantStatisticsCounter( 'shop-1', 'VISITS', new GetMerchantStatisticsCounterRequest(by: 'INTERVAL') );
Templates API
The Templates API is accessible via Yii::$app->taler->templates().
List Templates
$response = Yii::$app->taler->templates()->getTemplates(); foreach ($response->templates as $template) { echo $template->template_id . ' — ' . $template->template_description . PHP_EOL; }
Get Template Details
$details = Yii::$app->taler->templates()->getTemplate('coffee-small'); echo $details->template_description . PHP_EOL; echo $details->template_contract->summary . PHP_EOL; echo $details->template_contract->amount . PHP_EOL; echo $details->template_contract->minimum_age . PHP_EOL;
Create Template
use Taler\Api\Dto\RelativeTime; use Taler\Api\Templates\Dto\TemplateAddDetails; use Taler\Api\Templates\Dto\TemplateContractDetails; Yii::$app->taler->templates()->createTemplate( new TemplateAddDetails( template_id: 'coffee-small', template_description: 'Small coffee in paper cup', template_contract: new TemplateContractDetails( minimum_age: 0, pay_duration: new RelativeTime(900_000_000), summary: 'Small coffee', currency: 'KUDOS', amount: 'KUDOS:2.50' ), otp_id: null, editable_defaults: ['extra_note' => true] ) );
Update Template
use Taler\Api\Dto\RelativeTime; use Taler\Api\Templates\Dto\TemplatePatchDetails; use Taler\Api\Templates\Dto\TemplateContractDetails; Yii::$app->taler->templates()->updateTemplate( 'coffee-small', new TemplatePatchDetails( template_description: 'Small coffee (updated)', template_contract: new TemplateContractDetails( minimum_age: 0, pay_duration: new RelativeTime(1_200_000_000), summary: 'Small coffee (updated)', currency: 'KUDOS', amount: 'KUDOS:2.80' ), otp_id: null, editable_defaults: ['extra_note' => true] ) );
Delete Template
Yii::$app->taler->templates()->deleteTemplate('coffee-small');
Token Families API
The Token Families API is accessible via Yii::$app->taler->tokenFamilies().
List Token Families
$families = Yii::$app->taler->tokenFamilies()->getTokenFamilies(); foreach ($families->token_families as $family) { echo $family->slug . ' — ' . $family->name . ' — ' . $family->kind . PHP_EOL; }
Get Token Family Details
$family = Yii::$app->taler->tokenFamilies()->getTokenFamily('loyalty-token'); echo $family->slug . PHP_EOL; echo $family->name . PHP_EOL; echo $family->description . PHP_EOL; echo $family->kind . PHP_EOL; echo 'issued=' . $family->issued . ', used=' . $family->used . PHP_EOL;
Create Token Family
use Taler\Api\Dto\RelativeTime; use Taler\Api\Dto\Timestamp; use Taler\Api\TokenFamilies\Dto\TokenFamilyCreateRequest; Yii::$app->taler->tokenFamilies()->createTokenFamily( new TokenFamilyCreateRequest( slug: 'loyalty-token', name: 'Loyalty Program', description: 'Discount token family for recurring buyers', valid_before: new Timestamp(1750000000), duration: new RelativeTime(86400000000), validity_granularity: new RelativeTime(3600000000), start_offset: new RelativeTime(0), kind: 'discount', description_i18n: ['de' => 'Rabatt-Tokenfamilie'], extra_data: ['trusted_domains' => ['merchant.example']], valid_after: new Timestamp(1710000000) ) );
Update Token Family
use Taler\Api\Dto\Timestamp; use Taler\Api\TokenFamilies\Dto\TokenFamilyUpdateRequest; Yii::$app->taler->tokenFamilies()->updateTokenFamily( 'loyalty-token', new TokenFamilyUpdateRequest( name: 'Loyalty Program (Updated)', description: 'Updated description for recurring buyers', valid_after: new Timestamp(1710000000), valid_before: new Timestamp(1755000000), description_i18n: ['de' => 'Aktualisierte Rabatt-Tokenfamilie'], extra_data: ['trusted_domains' => ['merchant.example', 'shop.example']] ) );
Delete Token Family
Yii::$app->taler->tokenFamilies()->deleteTokenFamily('loyalty-token');
Async Support
All API methods support asynchronous execution by appending Async to the method name. Async methods return a promise that resolves to the same typed DTO as the synchronous variant.
// Example: create an order asynchronously $promise = Yii::$app->taler->orders()->createOrderAsync( new PostOrderRequest(order: $order) ); $response = $promise->wait(); echo 'Created order (async): ' . $response->order_id . PHP_EOL; // Example: list instances asynchronously $promise = Yii::$app->taler->instances()->getInstancesAsync(); $list = $promise->wait();
Bank Accounts API
The Bank Accounts API is accessible via Yii::$app->taler->bankAccounts().
List Bank Accounts
$accounts = Yii::$app->taler->bankAccounts()->getAccounts(); foreach ($accounts->accounts as $entry) { echo $entry->h_wire . ' ' . $entry->payto_uri . PHP_EOL; }
Get Bank Account Details
$account = Yii::$app->taler->bankAccounts()->getAccount('h_wire_hash_here'); echo $account->payto_uri . PHP_EOL; echo $account->active ? 'active' : 'inactive';
Create Bank Account
use Taler\Api\BankAccounts\Dto\AccountAddDetails; use Taler\Api\BankAccounts\Dto\AccountAddResponse; use Taler\Api\TwoFactorAuth\Dto\ChallengeResponse; $result = Yii::$app->taler->bankAccounts()->createAccount( new AccountAddDetails( payto_uri: 'payto://iban/DE75512108001245126199?receiver-name=Merchant' ) ); if ($result instanceof ChallengeResponse) { echo '2FA required: ' . $result->getChallengeId() . PHP_EOL; } elseif ($result instanceof AccountAddResponse) { echo 'h_wire: ' . $result->h_wire . PHP_EOL; }
Update Bank Account
use Taler\Api\BankAccounts\Dto\AccountPatchDetails; Yii::$app->taler->bankAccounts()->updateAccount( 'h_wire_hash_here', new AccountPatchDetails( credit_facade_url: 'https://bank-facade.example' ) );
Delete Bank Account
Yii::$app->taler->bankAccounts()->deleteAccount('h_wire_hash_here');
OTP Devices API
The OTP Devices API is accessible via Yii::$app->taler->otpDevices().
List OTP Devices
$response = Yii::$app->taler->otpDevices()->getOtpDevices(); foreach ($response->otp_devices as $device) { echo $device->otp_device_id . ' — ' . $device->device_description . PHP_EOL; }
Get OTP Device Details
use Taler\Api\OtpDevices\Dto\GetOtpDeviceRequest; $details = Yii::$app->taler->otpDevices()->getOtpDevice( 'pos-terminal-1', new GetOtpDeviceRequest(price: 'KUDOS:1.00') ); echo $details->device_description . PHP_EOL; echo $details->otp_algorithm . PHP_EOL; echo $details->otp_timestamp . PHP_EOL; echo ($details->otp_code ?? '(none)') . PHP_EOL;
Create OTP Device
use Taler\Api\OtpDevices\Dto\OtpDeviceAddDetails; Yii::$app->taler->otpDevices()->createOtpDevice( new OtpDeviceAddDetails( otp_device_id: 'pos-terminal-1', otp_device_description: 'Front desk terminal', otp_key: 'JBSWY3DPEHPK3PXP', otp_algorithm: 'TOTP_WITHOUT_PRICE', ) );
Update OTP Device
use Taler\Api\OtpDevices\Dto\OtpDevicePatchDetails; Yii::$app->taler->otpDevices()->updateOtpDevice( 'pos-terminal-1', new OtpDevicePatchDetails( otp_device_description: 'Front desk terminal (updated)', otp_algorithm: 'TOTP_WITH_PRICE', ) );
Delete OTP Device
Yii::$app->taler->otpDevices()->deleteOtpDevice('pos-terminal-1');
Two-Factor Auth API
The Two-Factor Auth API is accessible via Yii::$app->taler->twoFactorAuth().
Request Challenge Transmission
$response = Yii::$app->taler->twoFactorAuth()->requestChallenge( 'sandbox', 'challenge-id-123', ['resend' => true] ); echo 'solve_expiration: ' . $response->solve_expiration->t_s . PHP_EOL; echo 'earliest_retransmission: ' . $response->earliest_retransmission->t_s . PHP_EOL;
Confirm Challenge
use Taler\Api\TwoFactorAuth\Dto\MerchantChallengeSolveRequest; Yii::$app->taler->twoFactorAuth()->confirmChallenge( 'sandbox', 'challenge-id-123', new MerchantChallengeSolveRequest(tan: '123456') );
Async Two-Factor Calls
use Taler\Api\TwoFactorAuth\Dto\MerchantChallengeSolveRequest; $requestPromise = Yii::$app->taler->twoFactorAuth()->requestChallengeAsync( 'sandbox', 'challenge-id-123', [] ); $challenge = $requestPromise->wait(); $confirmPromise = Yii::$app->taler->twoFactorAuth()->confirmChallengeAsync( 'sandbox', 'challenge-id-123', new MerchantChallengeSolveRequest(tan: '123456') ); $confirmPromise->wait();
Donau Charity API
The Donau Charity API is accessible via Yii::$app->taler->donauCharities().
List Linked Donau Charity Instances
$response = Yii::$app->taler->donauCharities()->getInstances(); foreach ($response->donau_instances as $instance) { echo '#' . $instance->donau_instance_serial . ' ' . $instance->charity_name . PHP_EOL; }
Link a Donau Charity
use Taler\Api\DonauCharity\Dto\PostDonauRequest; use Taler\Api\TwoFactorAuth\Dto\ChallengeResponse; $result = Yii::$app->taler->donauCharities()->createDonauCharity( new PostDonauRequest( donau_url: 'https://donau.example', charity_id: 42, ) ); if ($result instanceof ChallengeResponse) { echo '2FA required: ' . $result->getChallengeId() . PHP_EOL; }
Unlink a Donau Charity by Serial
Yii::$app->taler->donauCharities()->deleteDonauCharityBySerial(42);
Testing
vendor/bin/phpunit
Funding
This project is funded through NGI TALER Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet program. Learn more at the NLnet project page.