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

v1.1.0 2025-12-14 12:09 UTC

This package is auto-updated.

Last update: 2025-12-14 12:12:22 UTC


README

CI PHP Version License: MIT

繁體中文 | 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\Payment namespace
  • πŸ”Œ 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 (requires ext-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.

Links