giorgigrdzelidze/laravel-bog-sdk

Laravel SDK for Bank of Georgia APIs: Business Online, Payments, iPay, Installment, BOG-ID, and Open Banking.

Maintainers

Package info

github.com/GiorgiGrdzelidze/laravel-bog-sdk

pkg:composer/giorgigrdzelidze/laravel-bog-sdk

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-04-22 17:31 UTC

This package is auto-updated.

Last update: 2026-04-22 17:32:06 UTC


README

Bank of Georgia

๐Ÿฆ Laravel BOG SDK

A comprehensive Laravel SDK for Bank of Georgia APIs. Covers all major BOG product lines with typed DTOs, automatic OAuth2 token management, and full test coverage.

CI PHP Version License

๐Ÿ“‹ Supported APIs

API Description Status
๐Ÿข Business Online (Bonline) Account balances, statements, today activities, currency rates, requisites โœ… Full
๐Ÿ’ณ Payments v1 E-commerce orders, refunds, pre-auth, saved cards, split payments โœ… Full
๐ŸŽ Apple Pay Apple Pay payment completion โœ… Full
๐Ÿ“ฑ Google Pay Google Pay payment completion โœ… Full
๐Ÿ’ฐ iPay (legacy) Orders, refunds, subscriptions, pre-auth โœ… Full
๐Ÿ“† Installment Calculator, checkout, order details โœ… Full
๐Ÿงพ Billing Payments, status, cancellation (OAuth2/Basic/API Key/HMAC) โœ… Full
๐Ÿ†” BOG-ID OpenID Connect: redirect, code exchange, userinfo โœ… Full
๐ŸŒ Open Banking Identity assurance โœ… Full
๐Ÿ”ฎ PSD2 AIS/PIS (scaffolded for future) ๐Ÿ”œ Planned

๐Ÿ“ฆ Requirements

  • PHP 8.3+
  • Laravel 12.x or 13.x

๐Ÿš€ Installation

composer require giorgigrdzelidze/laravel-bog-sdk

The service provider is auto-discovered. To publish the config file:

php artisan vendor:publish --tag=bog-sdk-config

To publish the BOG Payments callback public key (for signature verification):

php artisan vendor:publish --tag=bog-sdk-keys

โš™๏ธ Configuration

Add the following to your .env file. Only configure the APIs you plan to use:

# ๐Ÿข Business Online (Bonline)
BOG_BONLINE_CLIENT_ID=your-client-id
BOG_BONLINE_CLIENT_SECRET=your-client-secret
BOG_BONLINE_ACCOUNTS=GE00BG0000000000000001,GE00BG0000000000000002
BOG_BONLINE_DEFAULT_ACCOUNT=GE00BG0000000000000001
BOG_BONLINE_DEFAULT_CURRENCY=GEL
BOG_BONLINE_CURRENCIES=GEL,USD,EUR

# ๐Ÿ’ณ Payments
BOG_PAYMENTS_CLIENT_ID=your-client-id
BOG_PAYMENTS_CLIENT_SECRET=your-client-secret

# ๐Ÿ’ฐ iPay (legacy)
BOG_IPAY_CLIENT_ID=your-client-id
BOG_IPAY_CLIENT_SECRET=your-client-secret

# ๐Ÿ“† Installment
BOG_INSTALLMENT_CLIENT_ID=your-client-id
BOG_INSTALLMENT_CLIENT_SECRET=your-client-secret
BOG_INSTALLMENT_SHOP_ID=your-shop-id

# ๐Ÿงพ Billing
BOG_BILLING_CLIENT_ID=your-client-id
BOG_BILLING_CLIENT_SECRET=your-client-secret
BOG_BILLING_AUTH=oauth2  # oauth2 | basic | apikey | hmac-sha256

# ๐Ÿ†” BOG-ID (OpenID Connect)
BOG_ID_CLIENT_ID=your-client-id
BOG_ID_CLIENT_SECRET=your-client-secret
BOG_ID_REDIRECT_URI=https://your-app.com/auth/bog/callback

# ๐ŸŒ Open Banking
BOG_OB_CLIENT_ID=your-client-id
BOG_OB_CLIENT_SECRET=your-client-secret

๐Ÿ”ง Optional tuning

BOG_HTTP_TIMEOUT=15
BOG_HTTP_RETRY_TIMES=2
BOG_HTTP_RETRY_SLEEP_MS=250
BOG_TOKEN_CACHE_STORE=redis   # null = default cache driver
BOG_TOKEN_CACHE_PREFIX=bog-sdk:token:
BOG_TOKEN_CACHE_SAFETY_TTL=60 # seconds before token expiry to refresh

โšก Quick Start

Use the Bog facade or resolve BogClient from the container:

use GiorgiGrdzelidze\BogSdk\Facades\Bog;
// or
use GiorgiGrdzelidze\BogSdk\BogClient;

$client = app(BogClient::class);

๐Ÿข Business Online (Bonline)

๐Ÿ’ฐ Account Balance

$balance = Bog::bonline()->balance()->get('GE29BG0000000123456789', 'GEL');

$balance->accountNumber;    // "GE29BG0000000123456789"
$balance->currency;         // "GEL"
$balance->availableBalance; // 5432.10
$balance->currentBalance;   // 5500.00
$balance->blockedAmount;    // 67.90

๐Ÿ“„ Statement (with auto-pagination)

// Single page (max 1000 records per request)
$page = Bog::bonline()->statement()->forPeriod(
    from: new DateTimeImmutable('2026-01-01'),
    to: new DateTimeImmutable('2026-01-31'),
    currency: 'GEL',
    accountNumber: 'GE29BG0000000123456789',
);

$page->id;    // statement ID for paging
$page->count; // total records across all pages
$page->records; // TransactionDto[]

// ๐Ÿ”„ Stream all pages automatically (generator)
foreach (Bog::bonline()->statement()->stream(
    from: new DateTimeImmutable('2026-01-01'),
    to: new DateTimeImmutable('2026-03-31'),
    currency: 'GEL',
    accountNumber: 'GE29BG0000000123456789',
) as $transaction) {
    echo $transaction->entryDate . ' โ€” ' . $transaction->entryAmount;
    echo $transaction->senderName() . ' โ†’ ' . $transaction->beneficiaryName();
    echo $transaction->documentNomination;
}

๐Ÿ“‘ Statement Paging (manual)

Pages must be fetched sequentially โ€” skipping is not allowed by the API.

// Returns TransactionDto[] (flat array)
$records = Bog::bonline()->statement()->page(
    accountNumber: 'GE29BG0000000123456789',
    currency: 'GEL',
    statementId: (int) $page->id,
    pageNumber: 2,
);

๐Ÿ“Š Statement Summary

// V2 โ€” by date range (no statement ID needed)
$summary = Bog::bonline()->summary()->forPeriod('GE29BG0000000123456789', 'GEL', '2026-01-01', '2026-01-31');

$summary['GlobalSummary']['CreditSum'];
$summary['GlobalSummary']['DebitSum'];
$summary['DailySummaries']; // day-by-day breakdown

// V1 โ€” by statement ID
$summary = Bog::bonline()->summary()->get('GE29BG0000000123456789', 'GEL', $statementId);

๐Ÿ“… Today's Activities

$activities = Bog::bonline()->todayActivities()->get('GE29BG0000000123456789', 'GEL');

foreach ($activities as $tx) {
    echo $tx->entryAmountDebit . ' / ' . $tx->entryAmountCredit . ' โ€” ' . $tx->entryComment;
}

๐Ÿ’ฑ Currency Rates

// Commercial rate for a currency
$rate = Bog::bonline()->currencyRates()->commercial('USD');
echo "Buy: {$rate->buyRate}, Sell: {$rate->sellRate}";

// All major rates (USD, EUR, GBP)
$rates = Bog::bonline()->currencyRates()->list();

// Cross rate between two currencies (returns float)
$crossRate = Bog::bonline()->currencyRates()->crossRate('USD', 'EUR');

// NBG official rate (returns float)
$nbgRate = Bog::bonline()->currencyRates()->nbg('USD');

๐Ÿฆ Multiple Accounts & Currencies

The SDK supports managing multiple bank accounts and currencies via comma-separated env variables:

BOG_BONLINE_ACCOUNTS=GE22BG0000000541687311,GE46BG0000000498609082
BOG_BONLINE_DEFAULT_ACCOUNT=GE22BG0000000541687311
BOG_BONLINE_CURRENCIES=GEL,USD,EUR
BOG_BONLINE_DEFAULT_CURRENCY=GEL

Access the configured lists in your code:

$accounts = config('bog-sdk.bonline.accounts');
// ['GE22BG0000000541687311', 'GE46BG0000000498609082']

$currencies = config('bog-sdk.bonline.currencies');
// ['GEL', 'USD', 'EUR']

// Fetch balance for all accounts and currencies
foreach ($accounts as $iban) {
    foreach ($currencies as $currency) {
        $balance = Bog::bonline()->balance()->get($iban, $currency);
        echo "{$iban}: {$balance->availableBalance} {$currency}";
    }
}

// Stream transactions across all accounts and currencies
foreach ($accounts as $iban) {
    foreach ($currencies as $currency) {
        foreach (Bog::bonline()->statement()->stream($from, $to, $currency, $iban) as $tx) {
            // process each transaction
        }
    }
}
  • default_account is used when no specific account is provided (e.g. by CLI commands).
  • default_currency is the fallback when currencies is not set.
  • When BOG_BONLINE_CURRENCIES is configured, commands automatically iterate over all currencies for each account.

๐Ÿ›๏ธ Account Requisites

$requisites = Bog::bonline()->requisites()->get('GE29BG0000000123456789', 'GEL');

$requisites['BankName'];  // "Bank of Georgia"
$requisites['SwiftCode']; // "BAGAGE22"

๐Ÿ’ณ Payments v1

๐Ÿ›’ Create an Order

use GiorgiGrdzelidze\BogSdk\Payments\Dto\CreateOrderRequestDto;
use GiorgiGrdzelidze\BogSdk\Payments\Dto\BasketItemDto;
use GiorgiGrdzelidze\BogSdk\Payments\Dto\BuyerDto;

$order = Bog::payments()->orders()->create(new CreateOrderRequestDto(
    callbackUrl: 'https://your-app.com/bog/callback',
    externalOrderId: 'ORDER-001',
    currency: 'GEL',
    totalAmount: 49.99,
    basket: [
        new BasketItemDto('SKU-001', 'Product name', quantity: 1, unitPrice: 49.99),
    ],
    successUrl: 'https://your-app.com/success',
    failUrl: 'https://your-app.com/fail',
    buyer: new BuyerDto('Giorgi Grdzelidze', 'giorgi@example.com', '+995599000000'),
    capture: 'automatic', // or 'manual' for pre-auth
    saveCard: false,
));

$order->id;          // BOG order UUID
$order->redirectUrl; // redirect the customer here ๐Ÿ”—
$order->detailsUrl;  // API URL to check status

๐Ÿ” Get Order Details

$details = Bog::payments()->orders()->get($orderId);

$details->statusKey;       // "completed", "rejected", etc.
$details->totalAmount;     // 49.99
$details->currency;        // "GEL"
$details->paymentMethod;   // "card"
$details->cardMask;        // "4***1234"
$details->rrn;             // retrieval reference number
$details->externalOrderId; // "ORDER-001"

โ†ฉ๏ธ Refund / โŒ Cancel / โœ… Confirm Pre-auth

// Full refund
Bog::payments()->orders()->refund($orderId);

// Partial refund
Bog::payments()->orders()->refund($orderId, amount: 10.00);

// Cancel (before completion)
Bog::payments()->orders()->cancel($orderId);

// Confirm pre-auth (capture = manual)
Bog::payments()->orders()->confirm($orderId, amount: 49.99);

๐Ÿ’พ Saved Card Charges

// Charge a saved card
Bog::payments()->cardCharges()->charge($parentOrderId, 25.00, 'GEL');

// Subscription charge
Bog::payments()->cardCharges()->subscription($parentOrderId, 9.99, 'GEL', 'SUB-001');

// Delete saved card
Bog::payments()->cardCharges()->deleteCard($parentOrderId);

โœ‚๏ธ Split Payments

use GiorgiGrdzelidze\BogSdk\Payments\Dto\SplitAccountDto;

Bog::payments()->splitPayment()->create($orderId, [
    new SplitAccountDto('GE00ACCOUNT1', 30.00),
    new SplitAccountDto('GE00ACCOUNT2', 19.99),
]);

๐ŸŽ Apple Pay / ๐Ÿ“ฑ Google Pay

Bog::payments()->applePay()->complete($applePayTokenData);
Bog::payments()->googlePay()->complete($googlePayTokenData);

๐Ÿ” Verify Callback Signature

// In your callback controller:
$callback = Bog::payments()->verifyCallback(
    rawBody: $request->getContent(),
    signatureHeader: $request->header('X-Signature'),
);

$callback->id;              // order ID
$callback->statusKey;       // "completed"
$callback->externalOrderId; // your order reference
$callback->totalAmount;     // 49.99

๐Ÿ”‘ Publish the BOG callback public key first: php artisan vendor:publish --tag=bog-sdk-keys

๐Ÿ’ฐ iPay (Legacy)

use GiorgiGrdzelidze\BogSdk\IPay\Dto\IPayOrderRequestDto;
use GiorgiGrdzelidze\BogSdk\IPay\Dto\IPayItemDto;

$order = Bog::ipay()->orders()->create(new IPayOrderRequestDto(
    intent: 'CAPTURE',
    amount: 25.00,
    currency: 'GEL',
    items: [new IPayItemDto('SKU-1', 'Product', 1, 25.00)],
    callbackUrl: 'https://your-app.com/ipay/callback',
    redirectUrl: 'https://your-app.com/ipay/redirect',
));

$order->orderId;     // iPay order ID
$order->redirectUrl; // redirect customer ๐Ÿ”—

// ๐Ÿ” Check payment
$details = Bog::ipay()->orders()->get($orderId);

// โ†ฉ๏ธ Refund
Bog::ipay()->orders()->refund($orderId);
Bog::ipay()->orders()->refund($orderId, amount: 10.00); // partial

// ๐Ÿ”„ Subscription
Bog::ipay()->orders()->subscription($orderId, 9.99);

// โœ… Pre-auth confirm
Bog::ipay()->orders()->preAuthConfirm($orderId, 25.00);

๐Ÿ“† Installment

๐Ÿงฎ Calculate Discounts

use GiorgiGrdzelidze\BogSdk\Installment\Dto\CalculatorRequestDto;
use GiorgiGrdzelidze\BogSdk\Installment\Dto\InstallmentBasketItemDto;

$discounts = Bog::installment()->calculator()->discounts(new CalculatorRequestDto(
    clientType: 'standard',
    invoiceCurrency: 'GEL',
    basket: [new InstallmentBasketItemDto('PROD-1', 500.00, 1)],
    totalItemAmount: 500.00,
    totalAmount: 500.00,
));

foreach ($discounts as $discount) {
    echo "{$discount->month} months: {$discount->description} (fee: {$discount->amount})";
}

๐Ÿ›๏ธ Checkout & Details

$result = Bog::installment()->checkout()->create([
    'shop_id' => config('bog-sdk.installment.shop_id'),
    'amount' => 500.00,
    'currency' => 'GEL',
    // ... other fields
]);

$details = Bog::installment()->checkout()->details($orderId);
$details->orderId; // "inst-order-123"
$details->status;  // "approved" โœ…

๐Ÿ–ฅ๏ธ JS SDK Config Helper

$jsConfig = Bog::installment()->jsConfig(
    basket: [
        ['product_id' => 'P1', 'total_item_amount' => 300.00, 'total_item_qty' => 1],
        ['product_id' => 'P2', 'total_item_amount' => 200.00, 'total_item_qty' => 1],
    ],
    onCompleteUrl: 'https://your-app.com/installment/complete',
);
// Returns: ['shop_id' => '...', 'basket' => [...], 'currency' => 'GEL', 'amount' => 500.00, ...]

๐Ÿ“ Validation Rules

use GiorgiGrdzelidze\BogSdk\Support\InstallmentRules;

InstallmentRules::MIN_AMOUNT;     // 100.00 ๐Ÿ’ต
InstallmentRules::MAX_AMOUNT;     // 10,000.00 ๐Ÿ’ต
InstallmentRules::CURRENCY;       // "GEL"
InstallmentRules::ALLOWED_MONTHS; // [3, 6, 9, 12, 18, 24]

๐Ÿงพ Billing

Supports four authentication methods: oauth2, basic, apikey, hmac-sha256.

use GiorgiGrdzelidze\BogSdk\Billing\Dto\PaymentRequestDto;
use GiorgiGrdzelidze\BogSdk\Billing\Dto\PaymentInfoDto;

// ๐Ÿ’ต Create payment
$response = Bog::billing()->payment(new PaymentRequestDto(
    amount: 100.00,
    currency: 'GEL',
    description: 'Invoice #123',
    externalId: 'INV-123',
));
$response->paymentId;   // "pay-uuid"
$response->status;      // "pending"
$response->redirectUrl; // redirect customer ๐Ÿ”—

// ๐Ÿ” Check status
$status = Bog::billing()->paymentStatus($paymentId);
$status->status; // "completed" โœ…

// โŒ Cancel
$cancel = Bog::billing()->cancelPayment($paymentId);
$cancel->status; // "cancelled"

// โ„น๏ธ Send additional info
Bog::billing()->sendPaymentInfo(new PaymentInfoDto($paymentId, ['note' => 'Extra info']));

๐Ÿ†” BOG-ID (OpenID Connect)

use GiorgiGrdzelidze\BogSdk\BogId\Enums\BogIdClaim;

// 1๏ธโƒฃ Generate redirect URL
$url = Bog::bogId()->redirectUrl(
    scopes: [BogIdClaim::FPI->value, BogIdClaim::CI->value],
    redirectUri: 'https://your-app.com/auth/bog/callback',
    state: csrf_token(),
);
// Redirect user to $url ๐Ÿ”—

// 2๏ธโƒฃ Exchange code for tokens (in callback controller)
$tokens = Bog::bogId()->exchangeCode($request->code, 'https://your-app.com/auth/bog/callback');
$tokens->accessToken;
$tokens->idToken;
$tokens->refreshToken;
$tokens->expiresIn;

// 3๏ธโƒฃ Get user info
$user = Bog::bogId()->userinfo($tokens->accessToken);
$user->sub;            // unique user ID
$user->name;           // "Giorgi Grdzelidze"
$user->email;          // "giorgi@example.com"
$user->emailVerified;  // true โœ…
$user->phoneNumber;    // "+995599000000"
$user->personalNumber; // "01001012345"

๐Ÿ“‹ Available BOG-ID Scopes

Scope Description
FPI ๐Ÿ‘ค Full personal info
BPI ๐Ÿ‘ค Basic personal info
PI ๐Ÿ‘ค Personal info
DI ๐Ÿ“„ Document info
BI ๐Ÿฆ Bank info
CI ๐Ÿ“ž Contact info

๐ŸŒ Open Banking

๐Ÿ” Identity Assurance

use GiorgiGrdzelidze\BogSdk\OpenBanking\Identity\Dto\IdentityRequestDto;

$result = Bog::openBanking()->identity()->assure(new IdentityRequestDto(
    personalNumber: '01001012345',
    documentNumber: 'DOC123456',
    birthDate: '1990-01-01',
));

$result->verified;   // true โœ…
$result->firstName;  // "Giorgi"
$result->lastName;   // "Grdzelidze"
$result->confidence; // "HIGH"

๐Ÿท๏ธ Enums

The SDK ships with typed enums for all known API codes:

use GiorgiGrdzelidze\BogSdk\Payments\Enums\BogPaymentResponseCode;
use GiorgiGrdzelidze\BogSdk\Payments\Enums\OrderStatus;
use GiorgiGrdzelidze\BogSdk\Payments\Enums\PaymentMethod;
use GiorgiGrdzelidze\BogSdk\Payments\Enums\CaptureMethod;
use GiorgiGrdzelidze\BogSdk\Billing\Enums\BillingErrorCode;
use GiorgiGrdzelidze\BogSdk\Bonline\Enums\BonlineResultCode;
use GiorgiGrdzelidze\BogSdk\BogId\Enums\BogIdClaim;
use GiorgiGrdzelidze\BogSdk\Support\CurrencyCode;

// Each enum has a description() method ๐Ÿ“–
BogPaymentResponseCode::REJECTED_INSUFFICIENT_FUNDS->description();
// "Insufficient funds"

OrderStatus::COMPLETED->value; // "completed"
PaymentMethod::CARD->value;    // "card"
CurrencyCode::GEL->value;     // "GEL"

๐Ÿšจ Error Handling

All exceptions extend BogSdkException, making it easy to catch everything or be specific:

use GiorgiGrdzelidze\BogSdk\Exceptions\BogSdkException;
use GiorgiGrdzelidze\BogSdk\Exceptions\BogHttpException;
use GiorgiGrdzelidze\BogSdk\Exceptions\BogAuthenticationException;
use GiorgiGrdzelidze\BogSdk\Exceptions\BogBillingException;
use GiorgiGrdzelidze\BogSdk\Exceptions\BogInvalidSignatureException;

try {
    $balance = Bog::bonline()->balance()->get($iban, 'GEL');
} catch (BogAuthenticationException $e) {
    // ๐Ÿ”‘ OAuth credentials invalid or token fetch failed
} catch (BogHttpException $e) {
    $e->status;       // HTTP status code
    $e->body;         // raw response body
    $e->url;          // request URL
    $e->bogErrorCode; // BOG-specific error code (if present)
} catch (BogSdkException $e) {
    // ๐Ÿ›ก๏ธ Catch-all for any SDK error
}

๐ŸŒณ Exception Hierarchy

BogSdkException (abstract)
โ”œโ”€โ”€ ๐Ÿ”‘ BogAuthenticationException     โ€” OAuth2 token failures
โ”œโ”€โ”€ โš™๏ธ BogConfigurationException      โ€” Missing config or keys
โ”œโ”€โ”€ ๐ŸŒ BogHttpException               โ€” HTTP errors (4xx, 5xx) with metadata
โ”œโ”€โ”€ ๐Ÿ” BogInvalidSignatureException   โ€” Callback signature verification failed
โ”œโ”€โ”€ ๐Ÿข BogBonlineException            โ€” Bonline-specific errors with result codes
โ”œโ”€โ”€ ๐Ÿ’ณ BogPaymentException            โ€” Payment errors
โ”‚   โ”œโ”€โ”€ โŒ BogPaymentDeclinedException  โ€” Payment was declined
โ”‚   โ””โ”€โ”€ โš ๏ธ BogPaymentValidationException โ€” Validation errors
โ”œโ”€โ”€ ๐Ÿงพ BogBillingException            โ€” Billing errors with error codes and details
โ”œโ”€โ”€ ๐Ÿ’ฐ BogIPayException               โ€” iPay errors
โ”œโ”€โ”€ ๐Ÿ“† BogInstallmentException        โ€” Installment errors
โ”œโ”€โ”€ ๐Ÿ†” BogIdException                 โ€” BOG-ID/OIDC errors
โ””โ”€โ”€ ๐ŸŒ BogOpenBankingException        โ€” Open Banking errors

๐Ÿ” Token Management

The SDK automatically manages OAuth2 tokens per domain:

  • ๐Ÿง  Runtime cache โ€” tokens are held in memory for the current request
  • ๐Ÿ’พ Laravel cache โ€” tokens are persisted across requests using your configured cache driver
  • โฑ๏ธ Safety TTL โ€” tokens are refreshed 60 seconds before expiry (configurable)
  • ๐Ÿ”„ Automatic retry โ€” on 401 responses, the token is refreshed and the request retried once

You can customize the cache store:

BOG_TOKEN_CACHE_STORE=redis
BOG_TOKEN_CACHE_PREFIX=bog-sdk:token:
BOG_TOKEN_CACHE_SAFETY_TTL=60

๐ŸŽ Apple Pay Domain Verification

To set up Apple Pay, publish the domain association file:

php artisan bog-sdk:publish-apple-domain-association

This copies the merchant verification file to public/.well-known/apple-developer-merchantid-domain-association.

๐Ÿ—๏ธ Architecture

src/
โ”œโ”€โ”€ ๐Ÿ”‘ Auth/
โ”‚   โ”œโ”€โ”€ Dto/AccessToken.php          โ€” OAuth2 token DTO
โ”‚   โ””โ”€โ”€ TokenManager.php             โ€” Per-domain OAuth2 token management with caching
โ”œโ”€โ”€ ๐Ÿงพ Billing/
โ”‚   โ”œโ”€โ”€ Dto/                         โ€” PaymentRequest, PaymentResponse, PaymentStatus, Cancel, PaymentInfo
โ”‚   โ”œโ”€โ”€ Enums/BillingErrorCode.php   โ€” Error code enum
โ”‚   โ””โ”€โ”€ BillingClient.php            โ€” Multi-auth billing client (OAuth2/Basic/API Key/HMAC)
โ”œโ”€โ”€ ๐Ÿ†” BogId/
โ”‚   โ”œโ”€โ”€ Dto/                         โ€” BogIdToken, BogIdUser
โ”‚   โ”œโ”€โ”€ Enums/BogIdClaim.php         โ€” OIDC scope enum
โ”‚   โ””โ”€โ”€ BogIdClient.php              โ€” Redirect, code exchange, userinfo
โ”œโ”€โ”€ ๐Ÿข Bonline/
โ”‚   โ”œโ”€โ”€ Dto/                         โ€” Account, Balance, CurrencyRate, StatementPage, Summary, Transaction
โ”‚   โ”œโ”€โ”€ Endpoints/                   โ€” Accounts, Balance, CurrencyRates, Requisites, Statement, Summary, TodayActivities
โ”‚   โ”œโ”€โ”€ Enums/BonlineResultCode.php  โ€” Result code enum
โ”‚   โ””โ”€โ”€ BonlineClient.php            โ€” Lazy-loaded endpoint orchestrator
โ”œโ”€โ”€ ๐Ÿ–ฅ๏ธ Console/
โ”‚   โ””โ”€โ”€ PublishAppleDomainAssociationCommand.php
โ”œโ”€โ”€ ๐Ÿ“ Contracts/
โ”‚   โ””โ”€โ”€ HttpClientContract.php       โ€” Interface for HTTP client (get/post/put/patch/delete)
โ”œโ”€โ”€ ๐Ÿšจ Exceptions/                   โ€” 14 exception classes with full hierarchy
โ”œโ”€โ”€ ๐ŸŒ Http/
โ”‚   โ””โ”€โ”€ HttpClient.php               โ€” Token-aware HTTP client with 401 retry
โ”œโ”€โ”€ ๐Ÿ“† Installment/
โ”‚   โ”œโ”€โ”€ Dto/                         โ€” CalculatorRequest, Discount, BasketItem, OrderDetails
โ”‚   โ”œโ”€โ”€ Endpoints/                   โ€” Calculator, Checkout
โ”‚   โ””โ”€โ”€ InstallmentClient.php        โ€” Checkout, calculator, JS config helper
โ”œโ”€โ”€ ๐Ÿ’ฐ IPay/
โ”‚   โ”œโ”€โ”€ Dto/                         โ€” IPayItem, IPayOrderRequest, IPayOrderResponse, IPayPaymentDetails
โ”‚   โ”œโ”€โ”€ Endpoints/IPayOrdersEndpoint.php
โ”‚   โ””โ”€โ”€ IPayClient.php
โ”œโ”€โ”€ ๐ŸŒ OpenBanking/
โ”‚   โ”œโ”€โ”€ Identity/
โ”‚   โ”‚   โ”œโ”€โ”€ Dto/                     โ€” IdentityRequest, IdentityAssurance
โ”‚   โ”‚   โ””โ”€โ”€ IdentityClient.php
โ”‚   โ”œโ”€โ”€ Psd2/Psd2Client.php         โ€” Scaffolded for future PSD2 implementation
โ”‚   โ””โ”€โ”€ OpenBankingClient.php
โ”œโ”€โ”€ ๐Ÿ’ณ Payments/
โ”‚   โ”œโ”€โ”€ Dto/                         โ€” BasketItem, Buyer, CreateOrderRequest/Response, OrderDetails, OrderCallback, SplitAccount
โ”‚   โ”œโ”€โ”€ Endpoints/                   โ€” Orders, CardCharges, SplitPayment, ApplePay, GooglePay
โ”‚   โ”œโ”€โ”€ Enums/                       โ€” BogPaymentResponseCode, OrderStatus, PaymentMethod, CaptureMethod
โ”‚   โ””โ”€โ”€ PaymentsClient.php           โ€” Endpoint orchestrator + callback verification
โ”œโ”€โ”€ ๐Ÿ› ๏ธ Support/
โ”‚   โ”œโ”€โ”€ CurrencyCode.php             โ€” Currency enum (GEL, USD, EUR, GBP)
โ”‚   โ”œโ”€โ”€ InstallmentRules.php         โ€” Installment validation constants
โ”‚   โ””โ”€โ”€ SignatureVerifier.php        โ€” RSA SHA256 callback signature verification
โ”œโ”€โ”€ BogClient.php                    โ€” Main client (bonline, payments, billing, ipay, installment, bogId, openBanking)
โ”œโ”€โ”€ BogSdkServiceProvider.php        โ€” Auto-discovery, config, singletons
โ””โ”€โ”€ Facades/Bog.php                  โ€” Facade with full PHPDoc

๐Ÿงช Testing

The SDK ships with 110 tests and 315 assertions โœ…

# Run tests
composer test

# Run PHPStan (level 6)
composer phpstan

# Run code style check
composer pint -- --test

# Run all CI checks
composer ci

๐Ÿงช Testing in Your Application

The SDK works seamlessly with Http::fake():

use Illuminate\Support\Facades\Http;
use GiorgiGrdzelidze\BogSdk\BogClient;

Http::fake([
    // Fake the OAuth token endpoint
    'account.bog.ge/*' => Http::response([
        'access_token' => 'test-token',
        'expires_in' => 3600,
        'token_type' => 'Bearer',
    ]),
    // Fake the API endpoint
    'api.businessonline.ge/api/accounts/*/GEL' => Http::response([
        'AccountNumber' => 'GE00TEST',
        'Currency' => 'GEL',
        'AvailableBalance' => 1000.00,
        'CurrentBalance' => 1000.00,
        'BlockedAmount' => 0.0,
    ]),
]);

$balance = app(BogClient::class)->bonline()->balance()->get('GE00TEST', 'GEL');
assert($balance->availableBalance === 1000.00); // โœ…

๐Ÿ“ Changelog

See CHANGELOG.md for release history.

๐Ÿ“„ License

MIT. See LICENSE.md.

Made with โค๏ธ for the ๐Ÿ‡ฌ๐Ÿ‡ช Georgian developer community