PHP code example of comfino / php-api-client

1. Go to this page and download the library: Download comfino/php-api-client library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

comfino / php-api-client example snippets


use Comfino\Api\Client;
use Nyholm\Psr7\Factory\Psr17Factory;
use Sunrise\Http\Client\Curl\Client as CurlClient;

$psr17Factory = new Psr17Factory();

$client = new Client(
    httpClient: new CurlClient($psr17Factory),
    requestFactory: $psr17Factory,
    streamFactory: $psr17Factory,
    apiKey: 'your-api-key' // Private - keep server-side only.
);

$client->enableSandboxMode(); // Omit or call disableSandboxMode() for production.

// Submit a loan application.
$response = $client->createOrder($order); // $order implements OrderInterface
header('Location: ' . $response->applicationUrl);

// Override the default user agent.
$client->setCustomUserAgent('my-plugin/1.0.0');

// Set the API language (ISO 639-1) and currency (ISO 4217).
$client->setApiLanguage('pl');
$client->setApiCurrency('PLN');

// Add a custom HTTP header (e.g., for platform identification).
$client->addCustomHeader('X-Shop-Platform', 'WooCommerce/8.5');

// Use a different API endpoint (e.g., staging). Accepted destinations are ComfinoPay
// domains over HTTPS, plus private/loopback IPs, single-label hosts and `.test`
// domains for local development.
$client->setCustomApiBaseUrl('https://api-ecommerce.craty.pl');

use Comfino\Api\Dto\Payment\LoanQueryCriteria;
use Comfino\Enum\LoanType;
use Comfino\Enum\ProductListType;

// List all products for a 1 500 PLN cart (amounts in grosz).
$criteria = new LoanQueryCriteria(loanAmount: 150000);
$response = $client->getFinancialProducts($criteria);

foreach ($response->financialProducts as $product) {
    echo $product->name . ' - ' . $product->instalmentAmount . " grosz/month\n";
}

// Filter by product type.
$criteria = new LoanQueryCriteria(
    loanAmount: 150000,
    loanType: LoanType::INSTALLMENTS_ZERO_PERCENT
);

// Get detailed information about a specific financial product (e.g., for a product detail page).
$details = $client->getFinancialProductDetails($criteria, $cart); // $cart implements CartInterface

// Get available product types configured for this shop account (for promotional banner widget at shop product page).
$types = $client->getProductTypes(ProductListType::WIDGET);

// Create a loan application - $order implements Comfino\Shop\Order\OrderInterface.
$createResponse = $client->createOrder($order);
$applicationUrl = $createResponse->applicationUrl;

// Validate an order without submitting it.
$validateResponse = $client->validateOrder($order);

// Cancel an order.
$client->cancelOrder('ORDER-123');

use Comfino\Api\Dto\Account\UserRegistration;

$client = new Client($httpClient, $requestFactory, $streamFactory, null);

// Fetch the legal agreements to present as consent checkboxes.
$agreements = $client->fetchAgreements()->agreements;

// Register the shop, echoing back the IDs of the agreements the owner accepted.
$registration = new UserRegistration(
    name: 'shop.example.com',
    webSiteUrl: 'https://shop.example.com',
    contactName: 'Jane Doe',
    contactEmail: '[email protected]',
    contactPhone: '500600700',
    platformId: 16,
    agreements: array_map(static fn ($agreement) => $agreement->id, array_filter(
        $agreements,
        static fn ($agreement) => $agreement->

// Check that the API key belongs to an active account.
$isActive = $client->isShopAccountActive();

// Retrieve the widget key (public) for use in frontend scripts (e.g., promotional banner).
$widgetKey = $client->getWidgetKey();

// List available widget types.
$widgetTypes = $client->getWidgetTypes();

use Comfino\Api\Dto\Plugin\ShopPluginError;

// Report a plugin error for remote diagnostics (e.g., from an exception handler).
$client->sendLoggedError(new ShopPluginError(
    host: 'myshop.example.com',
    platform: 'ExampleEcommercePlatform',
    environment: ['php' => PHP_VERSION, 'plugin' => '2.0.0'],
    errorCode: 'API_ERROR',
    errorMessage: 'Unexpected API response.',
    stackTrace: $exception->getTraceAsString()
));

// Notify ComfinoPay when the payment plugin is uninstalled.
$client->notifyPluginRemoval();

// Notify ComfinoPay of an abandoned cart event.
$client->notifyAbandonedCart('checkout_abandoned');

use Comfino\Auth\WebhookSignatureVerifier;

$verifier = new WebhookSignatureVerifier();

$signature = $_SERVER['HTTP_CR_SIGNATURE'] ?? '';
$payload = file_get_contents('php://input');

if (!$verifier->verify($signature, 'your-api-key', $payload)) {
    http_response_code(401);
    exit;
}

// Process verified payload.
$data = json_decode($payload, true);

use Comfino\Auth\PaywallAuthKeyGenerator;

$generator = new PaywallAuthKeyGenerator();
// $widgetKey - public, obtained via $client->getWidgetKey() and stored in shop config
// $apiKey - private, never sent to the browser
$authKey = $generator->generateAuthKey(widgetKey: $widgetKey, apiKey: $apiKey);

// Pass only $authKey to the frontend widget initialization script served from the ComfinoPay CDN (part of the official ComfinoPay Web Frontend SDK).

use Comfino\Api\ApiContext;
use Comfino\Api\RequestOptions;
use Comfino\Api\SharedClient;

// Register this once, as a service. It is stateless and safe to share.
$client = new SharedClient(
    httpClient: $httpClient,
    requestFactory: $requestFactory,
    streamFactory: $streamFactory,
    retryExecutor: new RetryExecutor($retryPolicy)
);

// Build one context per merchant, per request. Immutable, so it cannot be mutated out from under a call.
$context = new ApiContext(
    apiKey: $merchant->apiKey,
    sandboxMode: $merchant->isSandbox,
    tenantKey: $merchant->id // Partitions the limiter, the breaker, and your own metrics.
);

$products = $client->getFinancialProducts($context, $criteria, RequestOptions::attempts(2));
$order = $client->createOrder($context, $order, RequestOptions::failFast());

use Comfino\Api\Client;
use Comfino\Api\Retry\ExponentialBackoffRetryPolicy;
use Comfino\Api\Retry\RetryExecutor;
use Comfino\Api\Retry\TimeoutConfig;

$retryPolicy = new ExponentialBackoffRetryPolicy(
    timeoutConfig: new TimeoutConfig(connectionTimeout: 5, transferTimeout: 15),
    maxAttempts: 3,
    maxTotalTransferTimeout: 15, // Budget shared by every attempt; null restores unbounded escalation.
    baseDelayMs: 100, // 0 disables the delay entirely
    maxDelayMs: 2000
);

$client = new Client(
    httpClient: $httpClient,
    requestFactory: $requestFactory,
    streamFactory: $streamFactory,
    apiKey: 'your-api-key',
    retryExecutor: new RetryExecutor($retryPolicy)
);

// One attempt, no delay: surface the failure and let the shopper pick another method.
$policy = ExponentialBackoffRetryPolicy::failFast(new TimeoutConfig(1, 3));

// Retries, but never sleeping.
$policy = ExponentialBackoffRetryPolicy::withoutDelay(new TimeoutConfig(1, 3), maxAttempts: 2);

final class RegisterSomething extends Request
{
    public function isIdempotent(): bool
    {
        return false; // No dedup key server-side, so never replay it.
    }

    // ...
}

use Comfino\Api\Retry\CallbackTimeoutAwareClient;
use Comfino\Api\Retry\TimeoutConfig;
use Symfony\Component\HttpClient\Psr18Client;

$transport = new CallbackTimeoutAwareClient(
    fn (TimeoutConfig $t) => new Psr18Client(
        $symfonyHttpClient->withOptions(['timeout' => $t->connectionTimeout, 'max_duration' => $t->transferTimeout])
    ),
    new TimeoutConfig(connectionTimeout: 1, transferTimeout: 3)
);

use Comfino\Api\CircuitBreaker\CircuitBreaker;
use Comfino\Api\RateLimit\TokenBucketRateLimiter;
use Comfino\Api\RateLimit\TwoTierRateLimiter;

$client = new SharedClient(
    httpClient: $httpClient,
    requestFactory: $requestFactory,
    streamFactory: $streamFactory,
    retryExecutor: new RetryExecutor($retryPolicy),
    rateLimiter: new TwoTierRateLimiter(
        perTenantLimiter: new TokenBucketRateLimiter(capacity: 20, refillTokensPerSecond: 5),
        globalLimiter: new TokenBucketRateLimiter(capacity: 200, refillTokensPerSecond: 50)
    ),
    circuitBreaker: new CircuitBreaker()
);

use Comfino\Api\OnLimit;

// Checkout: surface ServiceUnavailable and let the shopper choose another method.
$client->getFinancialProducts($context, $criteria, (new RequestOptions())->andOnLimit(OnLimit::FailFast));

// Worker: catch RateLimitExceeded, read getRetryAfterMs(), and put the call back on your queue.
$client->cancelOrder($context, $orderId, (new RequestOptions())->andOnLimit(OnLimit::Queue));

final class MetricsObserver implements RequestObserverInterface
{
    public function onResponse(ApiContext $c, RequestInterface $rq, ResponseInterface $rs, float $durationMs): void
    {
        $this->histogram->observe($durationMs, ['tenant' => $c->tenantKey, 'status' => $rs->getStatusCode()]);
    }

    // onRequest() and onFailure() omitted for brevity.
}

use Comfino\Api\Request\CustomRequest;

// Free-form JSON in, free-form JSON out - no Request/Response subclass needed.
$response = $client->sendCustomRequest(
    new CustomRequest(method: 'POST', endpointPath: 'orders/ORDER-123/notes', body: ['note' => 'Called back, will retry payment.'])
);

$response->body; // Deserialized response body, verbatim (array|string|bool|int|float|null)

$response = $client->sendCustomRequest(new CustomRequest('GET', 'orders/ORDER-123/notes'), MyNotesResponse::class);

use Comfino\Api\Exception\AuthorizationError;
use Comfino\Api\Exception\RequestValidationError;
use Comfino\Api\Exception\ServiceUnavailable;

try {
    $response = $client->createOrder($order);
} catch (RequestValidationError $e) {
    // $e->errors contains field-level validation messages from the API.
} catch (AuthorizationError $e) {
    // Invalid or missing API key.
} catch (ServiceUnavailable $e) {
    // ComfinoPay API is temporarily unavailable.
}
bash
composer