carllee1983 / tappay-payment-backend
Type-safe PHP 8.1+ library for TapPay Backend Payment APIs. Supports Pay by Prime, Pay by Token, Refund, and Record Query with injectable HTTP client for easy testing.
Fund package maintenance!
CarlLee1983
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/carllee1983/tappay-payment-backend
Requires
- php: ^8.1
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^10.5
README
ηΉι«δΈζ | English
A type-safe, PSR-4 compliant PHP library for TapPay Backend Payment APIs. Supports Pay by Prime, Pay by Token, Refund, and Record Query operations with injectable HTTP client for easy testing.
Features
- π PHP 8.1+ with strict types and readonly properties
- π¦ PSR-4 Autoloading with
TapPay\Paymentnamespace - π Injectable HTTP Client for easy mocking and testing
- β Type-safe DTOs for requests and responses
- π‘οΈ Comprehensive Error Handling with custom exceptions
- π Full PHPDoc Documentation for IDE support
Requirements
- PHP 8.1 or higher
- ext-json
- (Optional) ext-curl for
CurlHttpClient
Installation
composer require carllee1983/tappay-payment-backend
Quick Start
Basic Configuration
use TapPay\Payment\ClientConfig; use TapPay\Payment\TapPayClient; // Sandbox environment (default) $client = new TapPayClient(new ClientConfig( partnerKey: getenv('TAPPAY_PARTNER_KEY'), merchantId: getenv('TAPPAY_MERCHANT_ID') )); // Production environment $client = new TapPayClient(new ClientConfig( partnerKey: getenv('TAPPAY_PARTNER_KEY'), merchantId: getenv('TAPPAY_MERCHANT_ID'), baseUri: 'https://prod.tappaysdk.com' ));
Optional: Use Environment Enum
use TapPay\Payment\ClientConfig; use TapPay\Payment\Enum\TapPayEnvironment; $config = ClientConfig::forEnvironment( TapPayEnvironment::Sandbox, partnerKey: getenv('TAPPAY_PARTNER_KEY'), merchantId: getenv('TAPPAY_MERCHANT_ID') );
Optional: Use cURL HTTP Client
use TapPay\Payment\ClientConfig; use TapPay\Payment\TapPayClient; use TapPay\Payment\Http\CurlHttpClient; $client = new TapPayClient( new ClientConfig( partnerKey: getenv('TAPPAY_PARTNER_KEY'), merchantId: getenv('TAPPAY_MERCHANT_ID') ), new CurlHttpClient() );
Optional: Use PSR-18 HTTP Client
use TapPay\Payment\ClientConfig; use TapPay\Payment\TapPayClient; use TapPay\Payment\Http\Psr18HttpClientAdapter; // Requires PSR-18 + PSR-17 + a PSR-7 implementation, e.g.: // composer require psr/http-client psr/http-factory nyholm/psr7 $psr18Client = /* \Psr\Http\Client\ClientInterface */; $requestFactory = /* \Psr\Http\Message\RequestFactoryInterface */; $streamFactory = /* \Psr\Http\Message\StreamFactoryInterface */; $client = new TapPayClient( new ClientConfig( partnerKey: getenv('TAPPAY_PARTNER_KEY'), merchantId: getenv('TAPPAY_MERCHANT_ID') ), new Psr18HttpClientAdapter($psr18Client, $requestFactory, $streamFactory) );
Pay by Prime
Process a payment using a Prime token from the TapPay frontend SDK:
use TapPay\Payment\Dto\Money; use TapPay\Payment\Dto\PrimePaymentRequest; $response = $client->payByPrime(new PrimePaymentRequest( prime: 'prime_from_frontend', amount: 100, currency: 'TWD', details: 'Order #12345', orderNumber: 'ORDER-12345', cardholder: [ 'phone_number' => '+886912345678', 'name' => 'Test User', 'email' => 'test@example.com', ], remember: true // Save card for future payments )); if ($response->isSuccess()) { // Save rec_trade_id for refunds or queries $recTradeId = $response->recTradeId; // If remember=true, save card tokens for Pay by Token $cardKey = $response->cardSecret['card_key'] ?? null; $cardToken = $response->cardSecret['card_token'] ?? null; }
Tip: for non-TWD currencies, pass a Money object to avoid manual conversion:
$response = $client->payByPrime(new PrimePaymentRequest( prime: 'prime_from_frontend', amount: Money::USD(10.99), details: 'Order #12345' ));
Pay by Token
Process a payment using saved card tokens:
use TapPay\Payment\Dto\TokenPaymentRequest; $response = $client->payByToken(new TokenPaymentRequest( cardKey: $savedCardKey, cardToken: $savedCardToken, amount: 200, currency: 'TWD', details: 'Subscription renewal', orderNumber: 'SUB-12345' )); if ($response->isSuccess()) { echo "Payment successful: " . $response->recTradeId; }
Refund
Process a full or partial refund:
use TapPay\Payment\Dto\RefundRequest; // Full refund $response = $client->refund(new RefundRequest( recTradeId: $transactionId )); // Partial refund $response = $client->refund(new RefundRequest( recTradeId: $transactionId, amount: 50 // Refund 50 out of original amount )); if ($response->isSuccess()) { echo "Refund successful: " . $response->refundId; }
Query Records
Query transaction records:
use TapPay\Payment\Dto\RecordQueryRequest; $response = $client->queryRecords(new RecordQueryRequest( recordsPerPage: 50, page: 0, filters: [ 'time' => [ 'start_time' => strtotime('-30 days') * 1000, 'end_time' => time() * 1000, ], ], orderBy: [ 'attribute' => 'time', 'is_descending' => true, ] )); foreach ($response->tradeRecords as $record) { echo $record['rec_trade_id'] . ': ' . $record['amount'] . "\n"; }
API Reference
TapPayClient
| Method | Description |
|---|---|
payByPrime(PrimePaymentRequest $request) |
Process payment using Prime token |
payByToken(TokenPaymentRequest $request) |
Process payment using saved card tokens |
refund(RefundRequest $request) |
Process full or partial refund |
queryRecords(RecordQueryRequest $request) |
Query transaction records |
Request DTOs
PrimePaymentRequest
| Property | Type | Required | Description |
|---|---|---|---|
prime |
string | Yes | Prime token from frontend |
amount |
int|Money | Yes | Payment amount (if Money is used, currency is ignored) |
currency |
string | No | Currency code (default: TWD) |
details |
string | No | Transaction description |
orderNumber |
string | No | Merchant order number |
bankTransactionId |
string | No | Bank transaction ID |
cardholder |
array | No | Cardholder information |
remember |
bool | No | Save card for future use |
instalment |
int | No | Instalment period |
delayCaptureInDays |
int | No | Days to delay capture |
threeDomainSecure |
bool | No | Enable 3D Secure |
resultUrl |
array | No | 3D Secure result URLs |
TokenPaymentRequest
| Property | Type | Required | Description |
|---|---|---|---|
cardKey |
string | Yes | Card key from previous payment |
cardToken |
string | Yes | Card token from previous payment |
amount |
int|Money | Yes | Payment amount (if Money is used, currency is ignored) |
currency |
string | No | Currency code (default: TWD) |
details |
string | No | Transaction description |
orderNumber |
string | No | Merchant order number |
threeDomainSecure |
bool | No | Enable 3D Secure |
resultUrl |
array | No | 3D Secure result URLs |
Exceptions
| Exception | Description |
|---|---|
TapPayException |
Base exception class |
SignatureException |
Invalid API key (401/403) |
ValidationException |
Input validation errors |
HttpException |
HTTP-level errors |
Error Handling
use TapPay\Payment\Exception\SignatureException; use TapPay\Payment\Exception\ValidationException; use TapPay\Payment\Exception\HttpException; try { $response = $client->payByPrime($request); } catch (SignatureException $e) { // Invalid partner key error_log('API key error: ' . $e->getMessage()); } catch (ValidationException $e) { // Missing required fields error_log('Validation error: ' . $e->getMessage()); } catch (HttpException $e) { // TapPay service unavailable error_log('HTTP error: ' . $e->getMessage()); }
Testing
This library includes an injectable HTTP client interface for easy testing:
use TapPay\Payment\Http\HttpClientInterface; use TapPay\Payment\Http\HttpResponse; // Create a mock HTTP client $mockClient = new class implements HttpClientInterface { public function request( string $method, string $url, array $headers = [], array $body = [] ): HttpResponse { return new HttpResponse(200, json_encode([ 'status' => 0, 'msg' => 'success', 'rec_trade_id' => 'test_trade_id', ])); } }; // Inject mock client for testing $client = new TapPayClient($config, $mockClient);
HTTP Client Options
- Default:
TapPay\Payment\Http\NativeHttpClient(stream-based, no extra extensions) - Optional:
TapPay\Payment\Http\CurlHttpClient(requiresext-curl) - Optional:
TapPay\Payment\Http\Psr18HttpClientAdapter(requires PSR-18 + PSR-17 + PSR-7 implementation)
Running Tests
composer install
composer test
Documentation
For a library-specific API overview, see doc/API/README.md.
Contributing
Please see CONTRIBUTING.md for details.
Security
For security vulnerabilities, please see SECURITY.md.
License
This project is licensed under the MIT License - see the LICENSE file for details.