PHPackages                             aftandilmmd/odero-payment-for-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. aftandilmmd/odero-payment-for-php

ActiveLibrary[Payment Processing](/categories/payments)

aftandilmmd/odero-payment-for-php
=================================

OderoPay payment gateway integration for PHP.

10PHP

Since Feb 9Pushed 3mo agoCompare

[ Source](https://github.com/aftandilmmd/odero-payment-for-php)[ Packagist](https://packagist.org/packages/aftandilmmd/odero-payment-for-php)[ RSS](/packages/aftandilmmd-odero-payment-for-php/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

**English** | [Türkçe](README.tr.md) | [Azərbaycanca](README.az.md)

OderoPay for PHP
================

[](#oderopay-for-php)

Framework-agnostic [OderoPay](https://developer.oderopay.com.tr/az) payment gateway integration for PHP. Supports both Azerbaijan (`odero.az`) and Turkey (`oderopay.com.tr`) regions with sandbox and live environments.

Works with any PHP 8.2+ application -- no Laravel or other framework required.

> **Using Laravel?** See [odero-payment-for-laravel](https://github.com/aftandilmmd/odero-payment-for-laravel) -- a thin wrapper that adds auto-discovery, `config/odero.php`, the `Odero` facade, and Laravel Log channel integration. All DTOs, Enums, Exceptions, and core logic come from this package.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Guzzle HTTP 7.0+

Installation
------------

[](#installation)

```
composer require aftandilmmd/odero-payment-for-php
```

Quick Start
-----------

[](#quick-start)

```
use Aftandilmmd\OderoPayment\OderoFactory;

$odero = OderoFactory::create([
    'api_key' => 'your-api-key',
    'secret_key' => 'your-secret-key',
    'sandbox' => true,
    'region' => 'az', // 'az' or 'tr'
]);

$payment = $odero->createPayment([
    'price' => 100.0,
    'paidPrice' => 100.0,
    'currency' => 'AZN',
    'paymentGroup' => 'PRODUCT',
    'card' => [
        'cardHolderName' => 'John Doe',
        'cardNumber' => '4508034508034509',
        'expireYear' => '2030',
        'expireMonth' => '12',
        'cvc' => '000',
    ],
    'items' => [['name' => 'Product', 'price' => 100.0]],
]);

echo $payment->paymentStatus; // "SUCCESS"
```

Configuration
-------------

[](#configuration)

```
$odero = OderoFactory::create([
    'api_key' => 'your-api-key',      // Required
    'secret_key' => 'your-secret-key', // Required
    'sandbox' => true,                  // Default: true
    'region' => 'az',                   // Default: 'az' ('az' or 'tr')
    'auth_version' => 'V1',            // Default: 'V1'
    'timeout' => 30,                    // Default: 30 seconds
    'retry' => [
        'times' => 3,                  // Default: 3
        'sleep' => 100,                // Default: 100ms
    ],
    'logging' => [
        'enabled' => false,            // Default: false
    ],
]);
```

### Custom Guzzle Client

[](#custom-guzzle-client)

You can pass your own Guzzle client instance:

```
use GuzzleHttp\Client;

$client = new Client(['timeout' => 60, 'proxy' => 'http://proxy:8080']);
$odero = OderoFactory::create($config, $client);
```

### PSR-3 Logger

[](#psr-3-logger)

Pass any PSR-3 compatible logger (Monolog, etc.) and enable logging:

```
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('odero');
$logger->pushHandler(new StreamHandler('path/to/odero.log'));

$odero = OderoFactory::create([
    'api_key' => 'your-key',
    'secret_key' => 'your-secret',
    'logging' => ['enabled' => true],
], logger: $logger);
```

---

API Reference
-------------

[](#api-reference)

### Checkout Payments

[](#checkout-payments)

Initialize a checkout session and redirect the user to OderoPay's hosted payment page.

```
$response = $odero->initCheckout([
    'price' => 100.0,
    'paidPrice' => 100.0,
    'currency' => 'AZN',
    'paymentGroup' => 'PRODUCT',
    'conversationId' => 'order-123',
    'callbackUrl' => 'https://example.com/payment/callback',
    'items' => [
        ['name' => 'Monthly subscription', 'price' => 100.0],
    ],
]);

$response->token;          // "ckm-token-abc"
$response->pageUrl;        // "https://payment.odero.az/ckm-token-abc"
$response->tokenExpireDate; // "2026-03-01T12:00:00"

// Redirect user to $response->pageUrl
```

Retrieve the payment result after the callback:

```
$payment = $odero->retrieveCheckout($token);

$payment->id;             // 12345
$payment->paymentStatus;  // "SUCCESS"
$payment->price;          // 100.0
$payment->cardType;       // "CREDIT_CARD"
```

---

### Card Payments (Non-3DS)

[](#card-payments-non-3ds)

Charge a card directly without 3D Secure:

```
$payment = $odero->createPayment([
    'price' => 50.0,
    'paidPrice' => 50.0,
    'currency' => 'AZN',
    'paymentGroup' => 'PRODUCT',
    'conversationId' => 'order-456',
    'card' => [
        'cardHolderName' => 'John Doe',
        'cardNumber' => '4508034508034509',
        'expireYear' => '2030',
        'expireMonth' => '12',
        'cvc' => '000',
    ],
    'items' => [
        ['name' => 'Product A', 'price' => 30.0],
        ['name' => 'Product B', 'price' => 20.0],
    ],
]);

if ($payment->paymentStatus === 'SUCCESS') {
    $payment->id;              // Payment ID
    $payment->binNumber;       // "450803"
    $payment->lastFourDigits;  // "4509"
    $payment->cardAssociation; // "VISA"
}
```

#### Using the Card DTO

[](#using-the-card-dto)

```
use Aftandilmmd\OderoPayment\DTOs\Card;
use Aftandilmmd\OderoPayment\DTOs\PaymentItem;

$card = new Card(
    cardHolderName: 'John Doe',
    cardNumber: '4508034508034509',
    expireYear: '2030',
    expireMonth: '12',
    cvc: '000',
    storeCardAfterSuccessPayment: true,
    cardAlias: 'My Visa',
);

$items = [
    new PaymentItem(name: 'Product A', price: 30.0),
    new PaymentItem(name: 'Product B', price: 20.0, externalId: 'SKU-001'),
];

$payment = $odero->createPayment([
    'price' => 50.0,
    'paidPrice' => 50.0,
    'currency' => 'AZN',
    'card' => $card->toArray(),
    'items' => array_map(fn ($item) => $item->toArray(), $items),
]);
```

#### Paying with a Stored Card

[](#paying-with-a-stored-card)

```
$payment = $odero->createPayment([
    'price' => 50.0,
    'paidPrice' => 50.0,
    'currency' => 'AZN',
    'card' => [
        'cardUserKey' => $savedCardUserKey,
        'cardToken' => $savedCardToken,
    ],
    'items' => [['name' => 'Product', 'price' => 50.0]],
]);
```

---

### 3D Secure Payments

[](#3d-secure-payments)

#### Step 1: Initialize

[](#step-1-initialize)

```
$response = $odero->init3dsPayment([
    'price' => 100.0,
    'paidPrice' => 100.0,
    'currency' => 'AZN',
    'paymentGroup' => 'PRODUCT',
    'conversationId' => 'order-789',
    'callbackUrl' => 'https://example.com/payment/3ds-callback',
    'card' => [
        'cardHolderName' => 'John Doe',
        'cardNumber' => '4508034508034509',
        'expireYear' => '2030',
        'expireMonth' => '12',
        'cvc' => '000',
    ],
    'items' => [['name' => 'Product', 'price' => 100.0]],
]);

// Render the 3DS form in the browser
echo $response->decodedHtml();
```

#### Step 2: Complete (in callback handler)

[](#step-2-complete-in-callback-handler)

```
$payment = $odero->complete3dsPayment($paymentId);

if ($payment->paymentStatus === 'SUCCESS') {
    // 3DS payment completed
}
```

---

### Pre-Authorization

[](#pre-authorization)

Create a pre-authorized payment (hold funds) and capture later:

```
$payment = $odero->createPayment([
    'price' => 200.0,
    'paidPrice' => 200.0,
    'currency' => 'AZN',
    'paymentGroup' => 'PRODUCT',
    'paymentPhase' => 'PRE_AUTH',
    'card' => [...],
    'items' => [['name' => 'Hotel booking', 'price' => 200.0]],
]);

// Later, capture the funds (full or partial amount)
$captured = $odero->postAuthPayment($payment->id, 200.0);
```

---

### Refunds

[](#refunds)

#### Full Refund

[](#full-refund)

```
$refund = $odero->refund(paymentId: 12345);

$refund->id;                    // Refund ID
$refund->status;                // "SUCCESS"
$refund->refundPrice;           // 100.0
$refund->refundType;            // "REFUND"
$refund->refundDestinationType; // "CARD"
```

With optional parameters:

```
$refund = $odero->refund(
    paymentId: 12345,
    conversationId: 'refund-001',
    destinationType: 'CARD',  // or 'WALLET'
);
```

#### Partial Refund

[](#partial-refund)

```
$refund = $odero->partialRefund(
    paymentTransactionId: 99,
    refundPrice: 30.0,
    conversationId: 'partial-refund-001',
);

$refund->id;                   // Partial refund ID
$refund->refundPrice;          // 30.0
$refund->isAfterSettlement;    // false
$refund->paymentTransactionId; // 99
```

#### Retrieve Refund Status

[](#retrieve-refund-status)

```
$refund = $odero->retrieveRefund(refundId: 5001);
$partialRefund = $odero->retrievePartialRefund(id: 7001);
```

---

### Payment Reporting

[](#payment-reporting)

#### Retrieve a Single Payment

[](#retrieve-a-single-payment)

```
$report = $odero->retrievePayment(paymentId: 12345);

$report->id;
$report->orderId;
$report->paymentStatus;
$report->paymentCard;         // Card details array
$report->paymentRefunds;      // Refunds array
$report->paymentTransactions; // Transactions array
```

#### Search Payments

[](#search-payments)

```
$results = $odero->searchPayments([
    'paymentStatus' => 'SUCCESS',
    'currency' => 'AZN',
    'minPrice' => 10.0,
    'maxPrice' => 500.0,
    'page' => 0,
    'size' => 20,
]);

$results->items;     // Array of payments
$results->totalSize; // Total matching payments
$results->size;      // Page size

foreach ($results->items as $payment) {
    echo "{$payment['orderId']}: {$payment['price']} AZN";
}
```

---

### Subscriptions

[](#subscriptions)

#### Retrieve a Subscription

[](#retrieve-a-subscription)

```
$sub = $odero->retrieveSubscription(8001);

$sub->id;              // 8001
$sub->price;           // "29.99"
$sub->periodType;      // "30" (days)
$sub->status;          // 0 (Active)
$sub->nextPaymentDate; // "2026-02-15"
$sub->retryCount;      // 0
```

#### Search Subscriptions

[](#search-subscriptions)

```
$results = $odero->searchSubscriptions([
    'page' => 0,
    'size' => 10,
]);
```

#### Update Subscription Status

[](#update-subscription-status)

```
use Aftandilmmd\OderoPayment\Enums\SubscriptionStatus;

// Deactivate
$odero->updateSubscriptionStatus(8001, SubscriptionStatus::Passive->value);

// Reactivate
$odero->updateSubscriptionStatus(8001, SubscriptionStatus::Active->value);
```

#### Subscription Plan DTO

[](#subscription-plan-dto)

```
use Aftandilmmd\OderoPayment\DTOs\SubscriptionPlan;

$plan = new SubscriptionPlan(
    price: 29.99,
    periodType: 30,       // 7 = weekly, 30 = monthly, 360 = yearly
    nochargeDayCount: 7,  // Free trial days
    description: 'Monthly Plan',
);

// Use $plan->toArray() when creating subscriptions
```

---

### Pay by Link

[](#pay-by-link)

Create shareable payment links with optional QR codes.

#### Create

[](#create)

```
$link = $odero->createPayByLink([
    'name' => 'Premium subscription',
    'price' => 49.99,
    'currency' => 'AZN',
    'stock' => 100,
    'enabledInstallments' => '1,2,3,6',
    'expireDate' => '2026-12-31T23:59:59',
]);

$link->id;        // 9001
$link->status;    // "ACTIVE"
$link->token;     // "pbl-token-abc"
$link->url;       // Payment URL
$link->qrCodeUrl; // QR code image URL
$link->soldCount; // 0
```

#### Update

[](#update)

```
$link = $odero->updatePayByLink(9001, [
    'name' => 'Updated product name',
    'price' => 59.99,
    'stock' => 50,
]);
```

#### Retrieve

[](#retrieve)

```
$link = $odero->retrievePayByLink(9001);
```

---

### Card Storage

[](#card-storage)

#### Search Stored Cards

[](#search-stored-cards)

```
$cards = $odero->searchStoredCards([
    'cardUserKey' => 'card-user-key-abc',
]);

foreach ($cards->items as $card) {
    echo "{$card['cardAlias']}: {$card['binNumber']}****{$card['lastFourDigits']}";
}
```

#### Delete a Stored Card

[](#delete-a-stored-card)

```
$odero->deleteStoredCard([
    'cardUserKey' => 'card-user-key-abc',
    'cardToken' => 'card-token-xyz',
]);
```

---

### BIN Lookup &amp; Installments

[](#bin-lookup--installments)

#### BIN Lookup

[](#bin-lookup)

Get card and bank info from the first 6 digits:

```
$bin = $odero->lookupBin('450803');

$bin->binNumber;       // "450803"
$bin->cardType;        // "CREDIT_CARD"
$bin->cardAssociation; // "VISA"
$bin->cardBrand;       // "Bonus"
$bin->bankName;        // "Kapital Bank"
$bin->bankCode;        // 101
$bin->commercial;      // false
```

#### Get Installment Options

[](#get-installment-options)

```
// All banks
$installments = $odero->getInstallments(100.0, 'AZN');

// Specific bank (by BIN)
$installments = $odero->getInstallments(100.0, 'AZN', '450803');

$installments->binNumber;         // "450803"
$installments->bankName;          // "Kapital Bank"
$installments->installmentPrices; // Array of installment options

foreach ($installments->installmentPrices as $option) {
    $count = $option['installmentNumber'];
    $total = $option['totalPrice'];
    $monthly = $option['installmentPrice'];
    echo "{$count}x {$monthly} AZN (total: {$total} AZN)";
}
```

---

### Buyers

[](#buyers)

Manage buyer records for saved customer data.

#### Create

[](#create-1)

```
$buyer = $odero->createBuyer([
    'name' => 'John',
    'surname' => 'Doe',
    'email' => 'john@example.com',
    'gsmNumber' => '+994501234567',
    'identityNumber' => 'ABC123',
    'registrationAddress' => 'Baku, Azerbaijan',
    'city' => 'Baku',
    'country' => 'Azerbaijan',
]);

$buyer->id;     // 2001
$buyer->status; // "ACTIVE"
```

#### Update

[](#update-1)

```
$buyer = $odero->updateBuyer(2001, [
    'name' => 'Jane',
    'email' => 'jane@example.com',
]);
```

#### Retrieve

[](#retrieve-1)

```
$buyer = $odero->retrieveBuyer(2001);
```

---

### Payment Transactions

[](#payment-transactions)

Approve or reject payment transactions for settlement.

#### Approve

[](#approve)

```
$odero->approveTransactions([99, 100, 101]);

// Transactional mode: all-or-nothing
$odero->approveTransactions([99, 100], isTransactional: true);
```

#### Disapprove

[](#disapprove)

```
$odero->disapproveTransactions([99, 100]);
```

---

Error Handling
--------------

[](#error-handling)

All API errors throw typed exceptions:

```
use Aftandilmmd\OderoPayment\Exceptions\OderoException;
use Aftandilmmd\OderoPayment\Exceptions\OderoAuthenticationException;

try {
    $payment = $odero->createPayment([...]);
} catch (OderoAuthenticationException $e) {
    // 401 - Invalid API credentials
    // $e->getMessage()  => "OderoPay authentication failed."
    // $e->getCode()     => 401
} catch (OderoException $e) {
    // 4xx/5xx - API error
    // $e->getMessage()  => "Invalid card number"
    // $e->getCode()     => 400
    // $e->errors        => ['errorCode' => '10051', 'errorDescription' => '...', 'errorGroup' => 'VALIDATION']
}
```

### Response Helper Methods

[](#response-helper-methods)

All response DTOs extend `OderoResponse` and include:

```
$response->isSuccessful(); // true if no errors
$response->hasErrors();    // true if errors present
$response->rawData;        // Full raw API response array
$response->errors;         // Errors array (if any)
```

---

Enums
-----

[](#enums)

The package provides typed enums for all API constants:

```
use Aftandilmmd\OderoPayment\Enums\Currency;
use Aftandilmmd\OderoPayment\Enums\PaymentStatus;
use Aftandilmmd\OderoPayment\Enums\SubscriptionStatus;

// Values
Currency::Azn->value;              // "AZN"
PaymentStatus::Success->value;     // "SUCCESS"
SubscriptionStatus::Active->value; // 0

// Labels
Currency::Azn->label();            // "Azerbaycan Manati"
PaymentStatus::Success->label();   // "Basarili"

// Select options (value => label)
Currency::options();
// ["AZN" => "Azerbaycan Manati", "TRY" => "Turk Lirasi", ...]
```

Available enums: `Currency`, `PaymentGroup`, `PaymentPhase`, `PaymentStatus`, `CardType`, `CardAssociation`, `RefundType`, `RefundDestinationType`, `SubscriptionStatus`, `TransactionStatus`.

---

Testing
-------

[](#testing)

```
vendor/bin/pest
```

107 tests, 353 assertions. Uses Guzzle `MockHandler` with JSON fixtures.

Related Packages
----------------

[](#related-packages)

- **[odero-payment-for-laravel](https://github.com/aftandilmmd/odero-payment-for-laravel)** -- Laravel wrapper that adds ServiceProvider auto-discovery, the `Odero` facade, `config/odero.php` with env variable support, and automatic Laravel Log channel integration. Requires this package as a dependency.

License
-------

[](#license)

MIT

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance55

Moderate activity, may be stable

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity12

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/630ea45c41a7b5c54294a46920d0036cf0693865c7d3254c445b6cc08670edd0?d=identicon)[aftandilmmd](/maintainers/aftandilmmd)

---

Top Contributors

[![aftandilmmd](https://avatars.githubusercontent.com/u/26919900?v=4)](https://github.com/aftandilmmd "aftandilmmd (2 commits)")

### Embed Badge

![Health badge](/badges/aftandilmmd-odero-payment-for-php/health.svg)

```
[![Health](https://phpackages.com/badges/aftandilmmd-odero-payment-for-php/health.svg)](https://phpackages.com/packages/aftandilmmd-odero-payment-for-php)
```

###  Alternatives

[omnipay/paypal

PayPal gateway for Omnipay payment processing library

3156.8M53](/packages/omnipay-paypal)[eduardokum/laravel-boleto

Biblioteca com boletos para o laravel

626351.9k2](/packages/eduardokum-laravel-boleto)[tbbc/money-bundle

This is a Symfony bundle that integrates moneyphp/money library (Fowler pattern): https://github.com/moneyphp/money.

1961.9M](/packages/tbbc-money-bundle)[2checkout/2checkout-php

2Checkout PHP Library

83740.3k2](/packages/2checkout-2checkout-php)[smhg/sepa-qr-data

Generate QR code data for SEPA payments

61717.2k5](/packages/smhg-sepa-qr-data)[omnipay/dummy

Dummy driver for the Omnipay payment processing library

271.2M33](/packages/omnipay-dummy)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
