πŸ”Œ API интСграция

Назад ΠΊ списку Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ
Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ
Slug:
api.html
ОбновлСно:
30.05.2026 15:03
Π Π°Π·ΠΌΠ΅Ρ€:
11.82 KB
ΠŸΡƒΡ‚ΡŒ:
/resources/docs/developer/api.html
Бсылки
ΠŸΡƒΠ±Π»ΠΈΡ‡Π½Π°Ρ ссылка:
Бсылка Π² Π°Π΄ΠΌΠΈΠ½ΠΊΠ΅:
πŸ”Œ API интСграция

АрхитСктура API систСмы

БистСма DEXA ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½ΡƒΡŽ систСму API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с внСшними источниками курсов.

Π’Π°Π±Π»ΠΈΡ†Π° exchange_apis

ПолС Π’ΠΈΠΏ ОписаниС ΠŸΡ€ΠΈΠΌΠ΅Ρ€
name VARCHAR(255) НазваниС API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Rapira API
base_url VARCHAR(500) Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ URL API https://api.rapira.net
endpoint VARCHAR(255) Π­Π½Π΄ΠΏΠΎΠΈΠ½Ρ‚ для запроса /v1/rates
method ENUM('GET','POST') HTTP ΠΌΠ΅Ρ‚ΠΎΠ΄ GET
field_mapping JSON Маппинг ΠΏΠΎΠ»Π΅ΠΉ ΠΎΡ‚Π²Π΅Ρ‚Π° {"symbol_field": "pair"}
pair_format JSON Π€ΠΎΡ€ΠΌΠ°Ρ‚ Π²Π°Π»ΡŽΡ‚Π½Ρ‹Ρ… ΠΏΠ°Ρ€ {"from_separator": "_"}
authentication_type VARCHAR(50) Π’ΠΈΠΏ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ api_key
api_key TEXT ΠšΠ»ΡŽΡ‡ API (ΡˆΠΈΡ„Ρ€ΡƒΠ΅Ρ‚ΡΡ) encrypted_data

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ

Π§Π΅Ρ€Π΅Π· интСрфСйс

  1. ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π² API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ β†’ Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ
  2. Π—Π°ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ поля:
    • НазваниС для ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ
    • Base URL (ΠΏΠΎΠ»Π½Ρ‹ΠΉ адрСс Π±Π΅Π· эндпоинта)
    • Endpoint (ΠΏΡƒΡ‚ΡŒ ΠΊ API)
    • HTTP ΠΌΠ΅Ρ‚ΠΎΠ΄ (GET ΠΈΠ»ΠΈ POST)
    • Π’ΠΈΠΏ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ
    • ΠšΠ»ΡŽΡ‡ΠΈ доступа
  3. НастройтС ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ ΠΏΠΎΠ»Π΅ΠΉ (JSON)
  4. ΠŸΡ€ΠΎΡ‚Π΅ΡΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅
  5. Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ

Π§Π΅Ρ€Π΅Π· ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ/сиды

// ΠŸΡ€ΠΈΠΌΠ΅Ρ€ создания API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
ExchangeApi::create([
    'name' => 'Binance Public API',
    'base_url' => 'https://api.binance.com',
    'endpoint' => '/api/v3/ticker/price',
    'method' => 'GET',
    'field_mapping' => json_encode([
        'data_path' => null,
        'symbol_field' => 'symbol',
        'rate_path' => 'price',
        'is_simple_array' => false
    ]),
    'pair_format' => json_encode([
        'from_separator' => '',
        'to_separator' => '',
        'reverse' => false
    ]),
    'authentication_type' => 'none',
    'is_active' => true,
    'priority' => 1
]);

Field Mapping

JSON структура для ΠΌΠ°ΠΏΠΏΠΈΠ½Π³Π° ΠΏΠΎΠ»Π΅ΠΉ API ΠΎΡ‚Π²Π΅Ρ‚Π°:

{
    "data_path": "data.tickers",          // ΠŸΡƒΡ‚ΡŒ ΠΊ массиву Π΄Π°Π½Π½Ρ‹Ρ…
    "symbol_field": "symbol",             // ПолС с символом Π²Π°Π»ΡŽΡ‚Π½ΠΎΠΉ ΠΏΠ°Ρ€Ρ‹
    "rate_path": "close",                 // ΠŸΡƒΡ‚ΡŒ ΠΊ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ курса
    "bid_path": "bid",                    // ΠŸΡƒΡ‚ΡŒ ΠΊ Π»ΡƒΡ‡ΡˆΠ΅ΠΉ Ρ†Π΅Π½Π΅ ΠΏΠΎΠΊΡƒΠΏΠΊΠΈ
    "ask_path": "ask",                    // ΠŸΡƒΡ‚ΡŒ ΠΊ Π»ΡƒΡ‡ΡˆΠ΅ΠΉ Ρ†Π΅Π½Π΅ ΠΏΡ€ΠΎΠ΄Π°ΠΆΠΈ
    "volume_path": "volume",              // ΠŸΡƒΡ‚ΡŒ ΠΊ ΠΎΠ±ΡŠΠ΅ΠΌΡƒ Ρ‚ΠΎΡ€Π³ΠΎΠ²
    "change_path": "chg",                 // ΠŸΡƒΡ‚ΡŒ ΠΊ измСнСнию Ρ†Π΅Π½Ρ‹
    "high_path": "high",                  // Максимальная Ρ†Π΅Π½Π°
    "low_path": "low",                    // Минимальная Ρ†Π΅Π½Π°
    "is_simple_array": false,             // ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ массив ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²
    "delimiter": ",",                     // Π Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ для CSV
    "has_header": true,                   // Π•ΡΡ‚ΡŒ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π² CSV
    "orderbook_endpoint": "/market/exchange-plate-mini",
    "orderbook_symbol_format": "{from}/{to}",
    "orderbook_bid_path": "bid.items",
    "orderbook_ask_path": "ask.items",
    "orderbook_price_field": "price",
    "orderbook_amount_field": "amount"
}

Pair Format

Настройка Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° Π²Π°Π»ΡŽΡ‚Π½Ρ‹Ρ… ΠΏΠ°Ρ€:

{
    "from_separator": "/",      // Π Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Π°Π»ΡŽΡ‚Π°ΠΌΠΈ
    "to_separator": "_",        // ΠΠ»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ
    "reverse": false,           // Π Π΅Π²Π΅Ρ€ΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ°Ρ€Ρƒ (USDT/BTC β†’ BTC/USDT)
    "prefix": "",              // ΠŸΡ€Π΅Ρ„ΠΈΠΊΡ для символа
    "suffix": ""               // Буффикс для символа
}

Π’ΠΈΠΏΡ‹ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ

Π’ΠΈΠΏ ОписаниС Поля ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ°
none Π‘Π΅Π· Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ - -
api_key ΠšΠ»ΡŽΡ‡ Π² ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π΅ запроса api_key ?api_key=xxx
bearer Bearer Ρ‚ΠΎΠΊΠ΅Π½ api_key Authorization: Bearer xxx
basic Basic аутСнтификация api_key, secret_key Authorization: Basic base64

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 1: Binance Public API

НазваниС: Binance Spot Prices
Base URL: https://api.binance.com
Endpoint: /api/v3/ticker/price
ΠœΠ΅Ρ‚ΠΎΠ΄: GET
Маппинг: {
    "data_path": null,
    "symbol_field": "symbol",
    "rate_path": "price",
    "is_simple_array": true
}
Π€ΠΎΡ€ΠΌΠ°Ρ‚ ΠΏΠ°Ρ€Ρ‹: {
    "from_separator": "",
    "to_separator": "",
    "reverse": false
}
АутСнтификация: none

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 2: Rapira.net с API ΠΊΠ»ΡŽΡ‡ΠΎΠΌ

НазваниС: Rapira Exchange API
Base URL: https://api.rapira.net
Endpoint: /v1/rates
ΠœΠ΅Ρ‚ΠΎΠ΄: GET
Маппинг: {
    "data_path": "data",
    "symbol_field": "pair",
    "rate_path": "rate",
    "bid_path": "bid",
    "ask_path": "ask",
    "volume_path": "volume_24h",
    "is_simple_array": false
}
Π€ΠΎΡ€ΠΌΠ°Ρ‚ ΠΏΠ°Ρ€Ρ‹: {
    "from_separator": "_",
    "to_separator": "_",
    "reverse": false
}
АутСнтификация: api_key
API Key: ваш_ΠΊΠ»ΡŽΡ‡_rapira

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ΅ использованиС API

БСрвис UniversalApiService

Основной сСрвис для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с API:

// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ курсов с API
$apiService = new UniversalApiService();
$result = $apiService->fetchRates($apiConfig);

// ВСстированиС API
$testResult = $apiService->testApi($apiConfig, $useTestData);

// ОбновлСниС курсов ΠΈΠ· ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ API
$externalRateService = new ExternalRateService();
$updatedCount = $externalRateService->updateRatesFromSpecificApi($api);

ΠšΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€ ApiConfigController

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹:

  • test() - тСстированиС API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
  • quickTest() - быстрый тСст Π±Π΅Π· сохранСния
  • toggleActive() - активация/дСактивация API

ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²

Π£ΡΠΏΠ΅ΡˆΠ½Ρ‹ΠΉ ΠΎΡ‚Π²Π΅Ρ‚

{
    "success": true,
    "rates": [
        {
            "from": "USDT",
            "to": "RUB",
            "rate": 92.45,
            "bid": 92.40,
            "ask": 92.50,
            "source": "binance"
        }
    ],
    "count": 150,
    "timestamp": "2024-01-15T12:30:45Z"
}

Ошибка

{
    "success": false,
    "error": "API connection failed",
    "message": "Could not connect to https://api.binance.com",
    "code": "CONNECTION_ERROR",
    "retry_count": 3
}

Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³

Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ API вСдСтся статистика:

  • success_count - количСство ΡƒΡΠΏΠ΅ΡˆΠ½Ρ‹Ρ… запросов
  • error_count - количСство ошибок
  • last_success_at - врСмя послСднСго успСха
  • last_error_at - врСмя послСднСй ошибки
  • last_error_message - тСкст послСднСй ошибки

ΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

Настройки ΠΊΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡ:

  • ДоступныС Π²Π°Π»ΡŽΡ‚Ρ‹ ΠΊΡΡˆΠΈΡ€ΡƒΡŽΡ‚ΡΡ Π½Π° 24 часа
  • ΠšΡƒΡ€ΡΡ‹ ΠΊΡΡˆΠΈΡ€ΡƒΡŽΡ‚ΡΡ согласно ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Ρƒ обновлСния
  • Настройки API Π½Π΅ ΠΊΡΡˆΠΈΡ€ΡƒΡŽΡ‚ΡΡ (часто ΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ)

ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок

БистСма ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚:

  1. Π’Π°ΠΉΠΌΠ°ΡƒΡ‚Ρ‹ соСдинСния (настраиваСмыС)
  2. ΠŸΠΎΠ²Ρ‚ΠΎΡ€Π½Ρ‹Π΅ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠΈ (retry_count)
  3. ΠΠ»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ API (fallback)
  4. Π’Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²
  5. Π”Π΅Π³Ρ€Π°Π΄Π°Ρ†ΠΈΡŽ сСрвиса

Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Π°ΠΌΠΈ

ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ свой API:

// НазначСниС API ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Ρƒ
$partner = Partner::find(1);
$partner->api_id = $apiConfig->id;
$partner->save();

// ОбновлСниС курсов ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Π°
$rateUpdateService = new RateUpdateService();
$result = $rateUpdateService->updatePartnerRatesFromApi($partner->id, $apiConfig);

Π’Π°ΠΆΠ½ΠΎ: ΠŸΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠ΅Ρ€Π΅ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ всС связанныС ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Ρ‹.

ПослСднСС обновлСниС: 30.05.2026 в 15:03
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>πŸ”Œ API интСграция</title>
    <style>
        body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; padding: 20px; max-width: 1200px; margin: 0 auto; }
        h1 { color: #2c3e50; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-bottom: 20px; }
        h2 { color: #34495e; border-bottom: 1px solid #eee; padding-bottom: 5px; margin-top: 30px; }
        h3 { color: #7f8c8d; margin-top: 25px; }
        p { margin-bottom: 15px; }
        ul, ol { margin-bottom: 15px; padding-left: 20px; }
        li { margin-bottom: 5px; }
        code { background-color: #f8f9fa; padding: 2px 6px; border-radius: 4px; font-family: monospace; }
        pre { background-color: #f8f9fa; padding: 15px; border-radius: 8px; overflow-x: auto; border: 1px solid #dee2e6; }
        .endpoint { background-color: #e9ecef; padding: 10px; border-radius: 5px; margin: 10px 0; }
        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
        th, td { padding: 12px; border: 1px solid #dee2e6; }
        th { background-color: #f8f9fa; }
    </style>
</head>
<body>
<h1>πŸ”Œ API интСграция</h1>

<h2>АрхитСктура API систСмы</h2>
<p>БистСма DEXA ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½ΡƒΡŽ систСму API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с внСшними источниками курсов.</p>

<h3>Π’Π°Π±Π»ΠΈΡ†Π° exchange_apis</h3>
<table>
    <thead>
    <tr>
        <th>ПолС</th>
        <th>Π’ΠΈΠΏ</th>
        <th>ОписаниС</th>
        <th>ΠŸΡ€ΠΈΠΌΠ΅Ρ€</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td>name</td>
        <td>VARCHAR(255)</td>
        <td>НазваниС API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ</td>
        <td>Rapira API</td>
    </tr>
    <tr>
        <td>base_url</td>
        <td>VARCHAR(500)</td>
        <td>Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ URL API</td>
        <td>https://api.rapira.net</td>
    </tr>
    <tr>
        <td>endpoint</td>
        <td>VARCHAR(255)</td>
        <td>Π­Π½Π΄ΠΏΠΎΠΈΠ½Ρ‚ для запроса</td>
        <td>/v1/rates</td>
    </tr>
    <tr>
        <td>method</td>
        <td>ENUM('GET','POST')</td>
        <td>HTTP ΠΌΠ΅Ρ‚ΠΎΠ΄</td>
        <td>GET</td>
    </tr>
    <tr>
        <td>field_mapping</td>
        <td>JSON</td>
        <td>Маппинг ΠΏΠΎΠ»Π΅ΠΉ ΠΎΡ‚Π²Π΅Ρ‚Π°</td>
        <td>{"symbol_field": "pair"}</td>
    </tr>
    <tr>
        <td>pair_format</td>
        <td>JSON</td>
        <td>Π€ΠΎΡ€ΠΌΠ°Ρ‚ Π²Π°Π»ΡŽΡ‚Π½Ρ‹Ρ… ΠΏΠ°Ρ€</td>
        <td>{"from_separator": "_"}</td>
    </tr>
    <tr>
        <td>authentication_type</td>
        <td>VARCHAR(50)</td>
        <td>Π’ΠΈΠΏ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ</td>
        <td>api_key</td>
    </tr>
    <tr>
        <td>api_key</td>
        <td>TEXT</td>
        <td>ΠšΠ»ΡŽΡ‡ API (ΡˆΠΈΡ„Ρ€ΡƒΠ΅Ρ‚ΡΡ)</td>
        <td>encrypted_data</td>
    </tr>
    </tbody>
</table>

<h2>Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ</h2>

<h3>Π§Π΅Ρ€Π΅Π· интСрфСйс</h3>
<ol>
    <li>ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π² <strong>API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ β†’ Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ</strong></li>
    <li>Π—Π°ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ поля:
        <ul>
            <li>НазваниС для ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ</li>
            <li>Base URL (ΠΏΠΎΠ»Π½Ρ‹ΠΉ адрСс Π±Π΅Π· эндпоинта)</li>
            <li>Endpoint (ΠΏΡƒΡ‚ΡŒ ΠΊ API)</li>
            <li>HTTP ΠΌΠ΅Ρ‚ΠΎΠ΄ (GET ΠΈΠ»ΠΈ POST)</li>
            <li>Π’ΠΈΠΏ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ</li>
            <li>ΠšΠ»ΡŽΡ‡ΠΈ доступа</li>
        </ul>
    </li>
    <li>НастройтС ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ ΠΏΠΎΠ»Π΅ΠΉ (JSON)</li>
    <li>ΠŸΡ€ΠΎΡ‚Π΅ΡΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅</li>
    <li>Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ</li>
</ol>

<h3>Π§Π΅Ρ€Π΅Π· ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ/сиды</h3>
<pre><code>// ΠŸΡ€ΠΈΠΌΠ΅Ρ€ создания API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
ExchangeApi::create([
    'name' => 'Binance Public API',
    'base_url' => 'https://api.binance.com',
    'endpoint' => '/api/v3/ticker/price',
    'method' => 'GET',
    'field_mapping' => json_encode([
        'data_path' => null,
        'symbol_field' => 'symbol',
        'rate_path' => 'price',
        'is_simple_array' => false
    ]),
    'pair_format' => json_encode([
        'from_separator' => '',
        'to_separator' => '',
        'reverse' => false
    ]),
    'authentication_type' => 'none',
    'is_active' => true,
    'priority' => 1
]);</code></pre>

<h2>Field Mapping</h2>
<p>JSON структура для ΠΌΠ°ΠΏΠΏΠΈΠ½Π³Π° ΠΏΠΎΠ»Π΅ΠΉ API ΠΎΡ‚Π²Π΅Ρ‚Π°:</p>

<pre><code>{
    "data_path": "data.tickers",          // ΠŸΡƒΡ‚ΡŒ ΠΊ массиву Π΄Π°Π½Π½Ρ‹Ρ…
    "symbol_field": "symbol",             // ПолС с символом Π²Π°Π»ΡŽΡ‚Π½ΠΎΠΉ ΠΏΠ°Ρ€Ρ‹
    "rate_path": "close",                 // ΠŸΡƒΡ‚ΡŒ ΠΊ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ курса
    "bid_path": "bid",                    // ΠŸΡƒΡ‚ΡŒ ΠΊ Π»ΡƒΡ‡ΡˆΠ΅ΠΉ Ρ†Π΅Π½Π΅ ΠΏΠΎΠΊΡƒΠΏΠΊΠΈ
    "ask_path": "ask",                    // ΠŸΡƒΡ‚ΡŒ ΠΊ Π»ΡƒΡ‡ΡˆΠ΅ΠΉ Ρ†Π΅Π½Π΅ ΠΏΡ€ΠΎΠ΄Π°ΠΆΠΈ
    "volume_path": "volume",              // ΠŸΡƒΡ‚ΡŒ ΠΊ ΠΎΠ±ΡŠΠ΅ΠΌΡƒ Ρ‚ΠΎΡ€Π³ΠΎΠ²
    "change_path": "chg",                 // ΠŸΡƒΡ‚ΡŒ ΠΊ измСнСнию Ρ†Π΅Π½Ρ‹
    "high_path": "high",                  // Максимальная Ρ†Π΅Π½Π°
    "low_path": "low",                    // Минимальная Ρ†Π΅Π½Π°
    "is_simple_array": false,             // ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ массив ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²
    "delimiter": ",",                     // Π Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ для CSV
    "has_header": true,                   // Π•ΡΡ‚ΡŒ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π² CSV
    "orderbook_endpoint": "/market/exchange-plate-mini",
    "orderbook_symbol_format": "{from}/{to}",
    "orderbook_bid_path": "bid.items",
    "orderbook_ask_path": "ask.items",
    "orderbook_price_field": "price",
    "orderbook_amount_field": "amount"
}</code></pre>

<h2>Pair Format</h2>
<p>Настройка Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° Π²Π°Π»ΡŽΡ‚Π½Ρ‹Ρ… ΠΏΠ°Ρ€:</p>

<pre><code>{
    "from_separator": "/",      // Π Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Π°Π»ΡŽΡ‚Π°ΠΌΠΈ
    "to_separator": "_",        // ΠΠ»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ
    "reverse": false,           // Π Π΅Π²Π΅Ρ€ΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ°Ρ€Ρƒ (USDT/BTC β†’ BTC/USDT)
    "prefix": "",              // ΠŸΡ€Π΅Ρ„ΠΈΠΊΡ для символа
    "suffix": ""               // Буффикс для символа
}</code></pre>

<h2>Π’ΠΈΠΏΡ‹ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ</h2>
<table>
    <thead>
    <tr>
        <th>Π’ΠΈΠΏ</th>
        <th>ОписаниС</th>
        <th>Поля</th>
        <th>ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ°</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td>none</td>
        <td>Π‘Π΅Π· Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ</td>
        <td>-</td>
        <td>-</td>
    </tr>
    <tr>
        <td>api_key</td>
        <td>ΠšΠ»ΡŽΡ‡ Π² ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π΅ запроса</td>
        <td>api_key</td>
        <td>?api_key=xxx</td>
    </tr>
    <tr>
        <td>bearer</td>
        <td>Bearer Ρ‚ΠΎΠΊΠ΅Π½</td>
        <td>api_key</td>
        <td>Authorization: Bearer xxx</td>
    </tr>
    <tr>
        <td>basic</td>
        <td>Basic аутСнтификация</td>
        <td>api_key, secret_key</td>
        <td>Authorization: Basic base64</td>
    </tr>
    </tbody>
</table>

<h2>ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ</h2>

<h3>ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 1: Binance Public API</h3>
<pre><code>НазваниС: Binance Spot Prices
Base URL: https://api.binance.com
Endpoint: /api/v3/ticker/price
ΠœΠ΅Ρ‚ΠΎΠ΄: GET
Маппинг: {
    "data_path": null,
    "symbol_field": "symbol",
    "rate_path": "price",
    "is_simple_array": true
}
Π€ΠΎΡ€ΠΌΠ°Ρ‚ ΠΏΠ°Ρ€Ρ‹: {
    "from_separator": "",
    "to_separator": "",
    "reverse": false
}
АутСнтификация: none</code></pre>

<h3>ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 2: Rapira.net с API ΠΊΠ»ΡŽΡ‡ΠΎΠΌ</h3>
<pre><code>НазваниС: Rapira Exchange API
Base URL: https://api.rapira.net
Endpoint: /v1/rates
ΠœΠ΅Ρ‚ΠΎΠ΄: GET
Маппинг: {
    "data_path": "data",
    "symbol_field": "pair",
    "rate_path": "rate",
    "bid_path": "bid",
    "ask_path": "ask",
    "volume_path": "volume_24h",
    "is_simple_array": false
}
Π€ΠΎΡ€ΠΌΠ°Ρ‚ ΠΏΠ°Ρ€Ρ‹: {
    "from_separator": "_",
    "to_separator": "_",
    "reverse": false
}
АутСнтификация: api_key
API Key: ваш_ΠΊΠ»ΡŽΡ‡_rapira</code></pre>

<h2>ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ΅ использованиС API</h2>

<h3>БСрвис UniversalApiService</h3>
<p>Основной сСрвис для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с API:</p>

<pre><code>// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ курсов с API
$apiService = new UniversalApiService();
$result = $apiService->fetchRates($apiConfig);

// ВСстированиС API
$testResult = $apiService->testApi($apiConfig, $useTestData);

// ОбновлСниС курсов ΠΈΠ· ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ API
$externalRateService = new ExternalRateService();
$updatedCount = $externalRateService->updateRatesFromSpecificApi($api);</code></pre>

<h3>ΠšΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€ ApiConfigController</h3>
<p>ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹:</p>
<ul>
    <li><code>test()</code> - тСстированиС API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ</li>
    <li><code>quickTest()</code> - быстрый тСст Π±Π΅Π· сохранСния</li>
    <code>toggleActive()</code> - активация/дСактивация API</li>
</ul>

<h2>ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²</h2>

<h3>Π£ΡΠΏΠ΅ΡˆΠ½Ρ‹ΠΉ ΠΎΡ‚Π²Π΅Ρ‚</h3>
<pre><code>{
    "success": true,
    "rates": [
        {
            "from": "USDT",
            "to": "RUB",
            "rate": 92.45,
            "bid": 92.40,
            "ask": 92.50,
            "source": "binance"
        }
    ],
    "count": 150,
    "timestamp": "2024-01-15T12:30:45Z"
}</code></pre>

<h3>Ошибка</h3>
<pre><code>{
    "success": false,
    "error": "API connection failed",
    "message": "Could not connect to https://api.binance.com",
    "code": "CONNECTION_ERROR",
    "retry_count": 3
}</code></pre>

<h2>Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³</h2>
<p>Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ API вСдСтся статистика:</p>
<ul>
    <li><strong>success_count</strong> - количСство ΡƒΡΠΏΠ΅ΡˆΠ½Ρ‹Ρ… запросов</li>
    <li><strong>error_count</strong> - количСство ошибок</li>
    <li><strong>last_success_at</strong> - врСмя послСднСго успСха</li>
    <li><strong>last_error_at</strong> - врСмя послСднСй ошибки</li>
    <li><strong>last_error_message</strong> - тСкст послСднСй ошибки</li>
</ul>

<h2>ΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅</h2>
<p>Настройки ΠΊΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡ:</p>
<ul>
    <li>ДоступныС Π²Π°Π»ΡŽΡ‚Ρ‹ ΠΊΡΡˆΠΈΡ€ΡƒΡŽΡ‚ΡΡ Π½Π° 24 часа</li>
    <li>ΠšΡƒΡ€ΡΡ‹ ΠΊΡΡˆΠΈΡ€ΡƒΡŽΡ‚ΡΡ согласно ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Ρƒ обновлСния</li>
    <li>Настройки API Π½Π΅ ΠΊΡΡˆΠΈΡ€ΡƒΡŽΡ‚ΡΡ (часто ΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ)</li>
</ul>

<h2>ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок</h2>
<p>БистСма ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚:</p>
<ol>
    <li>Π’Π°ΠΉΠΌΠ°ΡƒΡ‚Ρ‹ соСдинСния (настраиваСмыС)</li>
    <li>ΠŸΠΎΠ²Ρ‚ΠΎΡ€Π½Ρ‹Π΅ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠΈ (retry_count)</li>
    <li>ΠΠ»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ API (fallback)</li>
    <li>Π’Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²</li>
    <li>Π”Π΅Π³Ρ€Π°Π΄Π°Ρ†ΠΈΡŽ сСрвиса</li>
</ol>

<h2>Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Π°ΠΌΠΈ</h2>
<p>ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ свой API:</p>
<pre><code>// НазначСниС API ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Ρƒ
$partner = Partner::find(1);
$partner->api_id = $apiConfig->id;
$partner->save();

// ОбновлСниС курсов ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Π°
$rateUpdateService = new RateUpdateService();
$result = $rateUpdateService->updatePartnerRatesFromApi($partner->id, $apiConfig);</code></pre>

<blockquote>
    <p><strong>Π’Π°ΠΆΠ½ΠΎ:</strong> ΠŸΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ API ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠ΅Ρ€Π΅ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ всС связанныС ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Ρ‹.</p>
</blockquote>
</body>
</html>