elgibor-solution/laravel-payment-bca

Laravel package for BCA OpenAPI Virtual Account (Inquiry, Payment Flag, Status) with caching and signatures.

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/elgibor-solution/laravel-payment-bca

1.0.0 2025-12-21 10:06 UTC

This package is auto-updated.

Last update: 2025-12-21 10:08:15 UTC


README

Production-ready Laravel 11 / PHP 8.3 package for BCA OpenAPI Virtual Account (bill presentment + payment flag + optional payment status). Namespace: ESolution\BCAPayment.

Installation

composer require elgibor-solution/laravel-payment-bca
php artisan vendor:publish --provider="ESolution\\BCAPayment\\BcaServiceProvider" --tag=bca-config

Configuration

Config lives at config/bca.php (aliased to config/bca-openapi.php). Keys:

  • base_url (prod) / base_url_staging (sandbox) — defaults: https://api.klikbca.com / https://devapi.klikbca.com
  • client_id, client_secret, private_key (PEM)
  • channel_id, partner_id, optional origin
  • timeout, connect_timeout, retry_times, retry_sleep_ms
  • token_cache_ttl_seconds (default 900), retry_on_codes (default 5002600 for payment status retry)
  • debug toggles staging base URL

Environment example:

BCA_BASE_URL=https://api.klikbca.com
BCA_BASE_URL_STAGING=https://devapi.klikbca.com
BCA_CLIENT_ID=your_client_id
BCA_CLIENT_SECRET=your_symmetric_secret
BCA_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----..."
BCA_CHANNEL_ID=95231
BCA_PARTNER_ID=12345
BCA_ORIGIN=https://merchant.example
BCA_DEBUG=false

Runtime config

  • Override defaults globally: Bca::config([...]) or Bca::setDefaultConfig([...]).
  • Per-call overrides: Bca::withConfig([...]) or Bca::withBaseUrl($url) returning a client instance.
  • Debug staging per call: Bca::withConfig(['debug' => true]).

Usage

use ESolution\BCAPayment\Facades\Bca;

// Access token (cached per client_id + base URL)
$token = Bca::token();

// Inquiry (Bill Presentment)
$inquiry = Bca::withConfig(['debug' => true])->inquiry([
    'partnerServiceId' => '123',
    'customerNo' => '987654',
    'virtualAccountNo' => '123987654',
    'trxDateInit' => now()->toIso8601String(),
    'channelCode' => '6011',
    'amount' => ['value' => '10000', 'currency' => 'IDR'],
    'inquiryRequestId' => 'REQ-1',
]);

// Payment Flag
$payment = Bca::payment([
    'partnerServiceId' => '123',
    'customerNo' => '987654',
    'virtualAccountNo' => '123987654',
    'virtualAccountName' => 'John Doe',
    'paymentRequestId' => 'PAY-1', // should match inquiryRequestId when retrying
    'channelCode' => '6011',
    'paidAmount' => ['value' => '10000', 'currency' => 'IDR'],
    'totalAmount' => ['value' => '10000', 'currency' => 'IDR'],
    'trxDateTime' => now()->toIso8601String(),
    'flagAdvise' => 'N', // N=new, Y=retry
]);

// Payment Status (optional)
$status = Bca::paymentStatus([
    'partnerServiceId' => '123',
    'customerNo' => '987654',
    'virtualAccountNo' => '123987654',
    'inquiryRequestId' => 'REQ-1',
    'paymentRequestId' => 'PAY-1',
]);

All transaction calls accept an optional second argument to override headers (e.g. provide your own X-EXTERNAL-ID). The package auto-generates a numeric X-EXTERNAL-ID (<=36 chars), and always sends CHANNEL-ID, X-PARTNER-ID, and optional ORIGIN.

Endpoints (fixed)

  • Token: POST /openapi/v1.0/access-token/b2b
  • Inquiry: POST /openapi/v1.0/transfer-va/inquiry
  • Payment: POST /openapi/v1.0/transfer-va/payment
  • Payment Status: POST /openapi/v1.0/transfer-va/status

Signatures (overview)

  • Token (asymmetric RSA SHA256): String to sign = client_id|X-TIMESTAMP. Headers: X-TIMESTAMP, X-CLIENT-KEY, X-SIGNATURE.
  • Transactions (HMAC SHA-512):
    • String to sign = HTTPMethod:RelativeUrl:AccessToken:lowercase(sha256(minified_body)):Timestamp
    • RelativeUrl starts with / and includes sorted query params.
    • Body is JSON-minified; empty body => empty string hashed.
    • Header set includes Authorization: Bearer {token}, X-TIMESTAMP, X-SIGNATURE, X-EXTERNAL-ID, CHANNEL-ID, X-PARTNER-ID, optional ORIGIN.

Notes

  • Bill Presentment (Inquiry) and Payment Flag must be used together; Payment Status is optional and marks code 5002600 as retryable by default.
  • Tokens are cached using client_id + base URL hash with a safety buffer to avoid near-expiry calls.
  • HTTP client uses Laravel Http with configurable timeouts and retries; secrets are never logged.

Testing

Run the feature tests with Orchestra Testbench:

composer test