20 Commits

Author SHA1 Message Date
Anatoliy Poloz
95203efbad fix(oauth): after saloon upgrade 2026-06-03 10:07:00 +03:00
c763fe6c71 fix(statements/transactions) 2026-06-02 21:00:44 +03:00
a412af3e07 fix(transactions) 2026-06-02 19:46:51 +03:00
9b62a59705 saloon update 2026-04-25 13:59:25 +03:00
Anatoliy Poloz
d4db68f2e7 refactor(error): handling 2026-04-07 18:47:53 +03:00
Anatoliy Poloz
ea374d2696 doc(test-payin) added 2026-04-07 18:44:27 +03:00
Anatoliy Poloz
13c91ad108 bump versions 2026-04-05 09:37:54 +03:00
Anatoliy Poloz
3cf15b7913 refactor(qr) 2026-04-02 16:45:41 +03:00
Anatoliy Poloz
a05a6506e8 fix(sign) 2026-03-21 07:10:16 +03:00
Anatoliy Poloz
4f52a189c7 add Identification 2026-03-19 19:38:21 +03:00
Anatoliy Poloz
b7b2a8fd61 refactor(Sbp) 2026-03-17 12:26:30 +03:00
Anatoliy Poloz
e2adc8d530 fix(OpenSslCmsSigner) 2026-03-10 22:29:35 +03:00
Anatoliy Poloz
c070297211 fix(sign) 2026-03-08 18:35:02 +03:00
Anatoliy Poloz
706fcb01b2 fix 2026-03-08 18:03:43 +03:00
7a6b13b12d update docs cross links 2026-02-15 08:09:32 +03:00
Anatoliy Poloz
b15d29f8e9 fix(formating) 2026-01-28 03:36:26 +03:00
Anatoliy Poloz
1723177949 fix(certs) 2026-01-28 02:47:39 +03:00
d89a78bef2 docs(README): add redirect_uri and ca_bundle config options with Laravel callback example
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-01-26 16:12:27 +03:00
ca3f14485a feat: Add optional redirectUri and keyNameAlias parameters with null defaults
- Make keyNameAlias parameter optional in SbpConnector with null default
- Add redirectUri parameter to AlfaBankServiceProvider configuration
- Make keyNameAlias optional in service provider with null coalescing operator
- Add conditional check for caBundlePath to allow disabling SSL verification

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-01-26 15:48:22 +03:00
86f50eed6a feat: update BaaS flow example and connector OAuth implementation
- Updated 01_baas_flow.php example to properly initialize BaaS with auth credentials
- Removed unused GetTokenRequest import from AlfaBankConnector
- Removed OAuth2Api interface implementation from AlfaBankConnector
- Renamed resolveOauth2Config method to defaultOauthConfig in AlfaBankConnector

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-01-26 15:36:42 +03:00
366 changed files with 3897 additions and 1968 deletions

View File

@@ -64,8 +64,12 @@ php artisan vendor:publish --tag=alfa-bank-config
ALFA_BAAS_ENVIRONMENT=sandbox # или production
ALFA_BAAS_CLIENT_ID=your-client-id
ALFA_BAAS_CLIENT_SECRET=your-client-secret
# URL в вашем приложении, на который вернется пользователь после входа (должен совпадать с настройками в Портале)
ALFA_BAAS_REDIRECT_URI=https://your-app.com/alfa/callback
ALFA_BAAS_CERT_PATH=storage/certs/baas_cert.pem
ALFA_BAAS_KEY_PATH=storage/certs/baas_key.pem
# Путь к корневым сертификатам (или 'false' для отключения проверки SSL в sandbox)
ALFA_BAAS_CA_BUNDLE=false
# Опционально: Ключи для CMS-подписи (если отличаются от транспортных)
# ALFA_BAAS_SIGNING_CERT_PATH=storage/certs/sign_cert.pem
@@ -76,6 +80,7 @@ ALFA_SBP_ENVIRONMENT=sandbox # или production
ALFA_SBP_ALIAS=your-key-name-alias
ALFA_SBP_CERT_PATH=storage/certs/sbp_cert.pem
ALFA_SBP_KEY_PATH=storage/certs/sbp_key.pem
ALFA_SBP_CA_BUNDLE=false
# --- Webhooks ---
ALFA_WEBHOOK_USER=alfa
@@ -94,8 +99,10 @@ return [
'environment' => env('ALFA_BAAS_ENVIRONMENT', 'sandbox'),
'client_id' => env('ALFA_BAAS_CLIENT_ID'),
'client_secret' => env('ALFA_BAAS_CLIENT_SECRET'),
'redirect_uri' => env('ALFA_BAAS_REDIRECT_URI'),
'certificate_path' => env('ALFA_BAAS_CERT_PATH'),
'private_key_path' => env('ALFA_BAAS_KEY_PATH'),
'ca_bundle' => env('ALFA_BAAS_CA_BUNDLE'),
// ...
],
'sbp' => [
@@ -103,6 +110,7 @@ return [
'key_name_alias' => env('ALFA_SBP_ALIAS'),
'certificate_path' => env('ALFA_SBP_CERT_PATH'),
'private_key_path' => env('ALFA_SBP_KEY_PATH'),
'ca_bundle' => env('ALFA_SBP_CA_BUNDLE'),
// ...
],
'webhook' => [
@@ -193,6 +201,23 @@ $newAuth = $baas->refreshAccessToken($savedRefreshToken);
$baas->authenticate($newAuth);
```
**Пример обработки callback в Laravel:**
```php
// routes/web.php
Route::get('/alfa/callback', function (Request $request, AlfaBankConnector $baas) {
$code = $request->query('code');
// Обмениваем временный код на постоянные токены
$authenticator = $baas->getAccessToken($code);
// Сохраняем refresh_token в БД для будущих обновлений сессии
$refreshToken = $authenticator->getRefreshToken();
auth()->user()->update(['alfa_refresh_token' => $refreshToken]);
return "Авторизация в Альфа-Банке прошла успешно!";
});
```
Полный пример: [examples/13_h2h_auth_service.php](examples/13_h2h_auth_service.php)
### 4. Генерация Client Secret (Утилита)

17
_docs/alfabank/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Alfa Bank SDK Documentation
Добро пожаловать в структурированную документацию Alfa API.
## Основные разделы
### 1. [Pay-in & KYC (Alfa API / Alfa ID)](payin_and_kyc/README.md)
Документация по приему платежей, идентификации пользователей через Alfa ID и управлению номинальными счетами.
### 2. [QR Payout (СБП C2B)](qr_payout/0_full.md)
Инструкции по интеграции Системы Быстрых Платежей (СБП) для QR-оплаты.
## Быстрая навигация
- [Карта всех эндпоинтов](endpoints.md)
- [Как подключиться](payin_and_kyc/Подключение_к_Alfa_API/how_to_connect.md)
- [Песочница](payin_and_kyc/Песочница/sandbox_intro.md)
- [Чек-лист готовности](payin_and_kyc/Общая_информация/check-list.md)

View File

@@ -0,0 +1,71 @@
# Карта эндпоинтов Alfa API
| Метод | Путь | Файл | Описание |
| :--- | :--- | :--- | :--- |
| `GET` | `/api/endpoint` | [Управление API Key](payin_and_kyc/Портал_разработчика/api_key_managment.md) | |
| `GET` | `/api/endpoint` | [TLS-сертификат](payin_and_kyc/Подключение_к_Alfa_API/tls-cert.md) | |
| `POST` | `/api/gd/v1/crypto-service/certificates` | [Добавление нового сертификата](payin_and_kyc/Транспортная_подпись_и_шифрование/managing-certificates/post-certificates.md) | |
| `GET` | `/api/gd/v1/crypto-service/certificates` | [Получение сертификатов](payin_and_kyc/Транспортная_подпись_и_шифрование/managing-certificates/get-certificates.md) | |
| `PATCH` | `/api/gd/v1/crypto-service/certificates/{id}` | [Обновление сертификата](payin_and_kyc/Транспортная_подпись_и_шифрование/managing-certificates/patch-certificates.md) | |
| `POST` | `/api/na/jp/v1/beneficiaries` | [Создание запроса на регистрацию бенефициара](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/add-beneficiary.md) | |
| `GET` | `/api/na/jp/v1/beneficiaries/requests/{requestId}/status` | [Получение статуса запроса](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/get-request-status.md) | |
| `GET` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}` | [Получение информации о бенефициаре `H2H`](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/get-beneficiary.md) | |
| `PUT` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}` | [Создание запроса на изменение информации о бенефициаре](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/change-beneficiary.md) | |
| `GET` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}/balance` | [Получение информации о балансе бенефициара](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/get-balance.md) | |
| `POST` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}/requisites` | [Добавление платёжных реквизитов бенефициара](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/add-requisites.md) | |
| `GET` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}/requisites` | [Получение платёжных реквизитов бенефициара](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/get-requisites.md) | |
| `PATCH` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}/requisites/{requisiteId}` | [Изменение признаков платёжных реквизитов бенефициара](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/change-requisites.md) | |
| `POST` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}/scoring` | [Создание запроса на проверку бенефициара](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/beneficiary-scoring.md) | |
| `GET` | `/api/na/jp/v1/beneficiaries/{beneficiaryId}/transactions` | [Получение списка денежных операций бенефициара](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Бенефициары/get-transactions.md) | |
| `POST` | `/api/na/jp/v1/deals` | [Регистрация сделки](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/add-deal.md) | |
| `PATCH` | `/api/na/jp/v1/deals/action` | [Выполнение действия по сделке](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/deal-actions.md) | |
| `POST` | `/api/na/jp/v1/deals/steps` | [Выполнение действия по этапам сделки](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/add-step.md) | |
| `PATCH` | `/api/na/jp/v1/deals/steps/contractors` | [Выполнение действия по участникам этапа сделки](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/step-contractors.md) | |
| `GET` | `/api/na/jp/v1/deals/{dealId}` | [Получение информации о сделке](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/get-deal.md) | |
| `PATCH` | `/api/na/jp/v1/deals/{dealId}/is-valid` | [Проверка возможности осуществления выплат по сделке](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/deal-is-valid.md) | |
| `GET` | `/api/na/jp/v1/deals/{dealId}/payoffs` | [Получение списка платежей по сделке](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/get-deal-payoffs.md) | |
| `GET` | `/api/na/jp/v1/deals/{dealId}/requests/{requestId}/status` | [Получение статуса запроса на завершение этапа сделки](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/get-deal-request-status.md) | |
| `GET` | `/api/na/jp/v1/deals/{dealId}/steps` | [Получение списка этапов сделки](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/get-steps.md) | |
| `GET` | `/api/na/jp/v1/deals/{dealId}/steps/{stepId}` | [Получение информации об этапе сделки](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/get-step.md) | |
| `GET` | `/api/na/jp/v1/deals/{dealId}/steps/{stepId}/contractors` | [Получение информации об участниках этапа сделки](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/get-contractors.md) | |
| `GET` | `/api/na/jp/v1/nominal-accounts` | [Получение списка номинальных счетов](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/get-nominal-accounts.md) | |
| `POST` | `/api/na/jp/v1/payoffs` | [Создание запроса на выплату с номинального счёта](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Выплаты/payoff.md) | |
| `GET` | `/api/na/jp/v1/unidentified-transactions` | [Получение списка неидентифицированных пополнений номинального счёта](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Идентификация_пополнений/get-unidentified-transactions.md) | |
| `POST` | `/api/na/jp/v1/unidentified-transactions/{id}/identify` | [Создание запроса на идентификацию пополнения номинального счёта](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Идентификация_пополнений/identify.md) | |
| `GET` | `/api/na/jp/v1/unidentified-transactions/{id}/identify/{identifyId}` | [Получение статуса запроса на идентификацию пополнения номинального счёта](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Идентификация_пополнений/get-identify-request-status.md) | |
| `POST` | `/api/na/jp/v1/unidentified-transactions/{id}/refunds` | [Создание запроса на возврат неидентифицированного пополнения](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Идентификация_пополнений/transaction-refund.md) | |
| `GET` | `/api/na/jp/v1/unidentified-transactions/{id}/refunds/{refundId}` | [Получение статуса запроса на возврат неидентифицированного пополнения](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Идентификация_пополнений/get-transaction-refund-request-status.md) | |
| `POST` | `/api/na/jp/v1/universal-recipients` | [Создание запроса на регистрацию универсального реципиента](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Универсальные_реципиенты/add-universal_recipient.md) | |
| `GET` | `/api/na/jp/v1/universal-recipients` | [Получение списка универсальных реципиентов номинального счёта](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Универсальные_реципиенты/get-universal_recipients_list.md) | |
| `GET` | `/api/na/jp/v1/universal-recipients/{universalRecipientId}` | [Получение информации об универсальном реципиенте](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Универсальные_реципиенты/get-universal_recipient.md) | |
| `POST` | `/api/na/jp/v1/universal-recipients/{universalRecipientId}/requisites` | [Добавление платёжных реквизитов универсального реципиента](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Универсальные_реципиенты/add-requisites.md) | |
| `GET` | `/api/na/jp/v1/universal-recipients/{universalRecipientId}/requisites` | [Получение платёжных реквизитов универсального реципиента](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Универсальные_реципиенты/get-requisites.md) | |
| `PATCH` | `/api/na/jp/v1/universal-recipients/{universalRecipientId}/requisites/{requisiteId}` | [Изменение признаков платёжных реквизитов универсального реципиента](payin_and_kyc/продукты_и_сервисы/Номинальные_счета/Контрагенты/Универсальные_реципиенты/change-requisites.md) | |
| `POST` | `/api/signature-encryption-tests/json` | [Формат исходного сообщения JSON](payin_and_kyc/Песочница/signature-encryption-tests/jws_POST.md) | |
| `POST` | `/api/signature-encryption-tests/text` | [Формат исходного сообщения TXT](payin_and_kyc/Песочница/signature-encryption-tests/text_POST.md) | |
| `POST` | `/api/signature-encryption-tests/xml` | [Формат исходного сообщения XML](payin_and_kyc/Песочница/signature-encryption-tests/xmldsig_POST.md) | |
| `GET` | `/api/v1/endpoint` | [Начало работы в песочнице](payin_and_kyc/Песочница/sandbox_intro.md) | |
| `POST` | `/api/v1/webhook-events` | [Партнёрский метод для получения вебхуков](payin_and_kyc/Вебхуки/partner-webhook.md) | |
| `POST` | `/api/v1/webhooks` | [Создание вебхука](payin_and_kyc/Вебхуки/create-webhook.md) | |
| `POST` | `/api/v1/webhooks-events` | [Проверка работы вебхука](payin_and_kyc/Песочница/check-webhook/checking_the_webhook_eg_transactions.md) | |
| `DELETE` | `/api/v1/webhooks/f9f8c674-7a2a-4297-bdb8-ddd3013de3a3?object=ul_transaction_default` | [Удаление вебхука](payin_and_kyc/Вебхуки/delete-webhook.md) | |
| `DELETE` | `/api/v1/webhooks/{id}` | [Удаление вебхука](payin_and_kyc/Вебхуки/delete-webhook.md) | |
| `PUT` | `/api/v2/webhooks/f9f8c674-7a2a-4297-bdb8-ddd3013de3a3` | [Редактирование вебхука](payin_and_kyc/Вебхуки/edit-webhook.md) | |
| `GET` | `/api/v2/webhooks/f9f8c674-7a2a-4297-bdb8-ddd3013de3a3?object=ul_transaction_default` | [Получение вебхука](payin_and_kyc/Вебхуки/get-webhook.md) | |
| `GET` | `/api/v2/webhooks/{id}` | [Получение вебхука](payin_and_kyc/Вебхуки/get-webhook.md) | |
| `PUT` | `/api/v2/webhooks/{id}` | [Редактирование вебхука](payin_and_kyc/Вебхуки/edit-webhook.md) | |
| `GET` | `/api/v2/webhooks?offset=20&limit=10&object=ul_transaction_default` | [Получение списка вебхуков](payin_and_kyc/Вебхуки/get-webhooks-list.md) | |
| `PUT` | `/filebox/secure-file-transfer.incoming-files.to-processing/12345678-90AB-CDEF-1234-1234567890AB?X-Amz-Date=20230608T152952Z&X-Amz-Expires=3600&X-Amz-Credential=secure-file-transfer%2F20230608%2Fbaas%2Fs3%2Faws4_request&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Signature=36ef1ccf28bdf6e54710fc3c1dd235c8f383275c2bbb0c9db365da272d3c24a8` | [Загрузка файла](payin_and_kyc/Обмен_файлами/upload.md) | |
| `GET` | `/filebox/secure-file-transfer.incoming-files.to-processing/12345678-90ab-cdef-1234-1234567890ab?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230608T152952Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=secure-file-transfer%2F20230608%2Fdev%2Fs3%2Faws4_request&X-Amz-Signature=e78c051fcff1017a68795620c20e50db33126ab8374c2ee9644ef4743b3625c6` | [Скачивание файла](payin_and_kyc/Обмен_файлами/download.md) | |
| `GET` | `/oidc/authorize?response_type=code&client_id=0cee0683-85ae-49f2-a63d-29f97aad1911&redirect_uri=https%3A%2F%2Fwwww.partner.ru%2Fcode&scope=openid&state=abcdef` | [Получение кода авторизации](payin_and_kyc/Alfa_ID/Authorization_Code_Flow/obtaining_an_authorization_code_GET.md) | |
| `GET` | `/oidc/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={scope}&state={state}` | [Получение кода авторизации](payin_and_kyc/Alfa_ID/Authorization_Code_Flow/obtaining_an_authorization_code_GET.md) | |
| `GET` | `/oidc/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={scope}&state={state}` | [Получение кода авторизации](payin_and_kyc/Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/obtaining_an_authorization_code.md) | |
| `GET` | `/oidc/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={scope}&state={state}` | [Получение кода авторизации](payin_and_kyc/Alfa_ID/Authorization_Code_Flow_for_Holding_Companies/getting_authorization_token.md) | |
| `GET` | `/oidc/client-consents` | [Данные по согласиям пользователей](payin_and_kyc/Alfa_ID/expansion/client-consents_GET.md) | |
| `POST` | `/oidc/clients/{clientId}/client-secret` | [Client secret](payin_and_kyc/Подключение_к_Alfa_API/client_secret.md) | |
| `POST` | `/oidc/revoke` | [Отзыв токена доступа](payin_and_kyc/Alfa_ID/expansion/revoke-token_POST.md) | |
| `POST` | `/oidc/token` | [Обновление токена доступа](payin_and_kyc/Alfa_ID/Authorization_Code_Flow/access_token_refresh_POST.md) | |
| `POST` | `/oidc/token` | [Как использовать CCF (Client Credentials Flow)](payin_and_kyc/Alfa_ID/client_credentials_flow/how_to_use_ccf.md) | |
| `POST` | `/oidc/token` | [Обновление токена доступа](payin_and_kyc/Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/refreshing_access_token_POST.md) | |
| `POST` | `/oidc/token` | [Получение токена доступа `H2H` `POST`](payin_and_kyc/Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/geting_access_token_POST.md) | |
| `GET` | `/oidc/userinfo` | [Получение профиля представителя пользователя `B2B` `B2C`](payin_and_kyc/Alfa_ID/Authorization_Code_Flow/obtaining_a_user_representative_profile.md) | |

View File

@@ -0,0 +1,30 @@
# Pay-in & KYC (Alfa API / Alfa ID)
Этот раздел содержит документацию по интеграции с банковскими сервисами Alfa-Bank для B2B, B2C и H2H сегментов.
## Навигация по разделам
### 🚀 [Начало работы](Подключение_к_Alfa_API/how_to_connect.md)
- [Как подключиться](Подключение_к_Alfa_API/how_to_connect.md)
- [Подписание договора](Подключение_к_Alfa_API/contract_signing.md)
- [Чек-лист готовности](Общая_информация/check-list.md)
### 🆔 [Alfa ID](Alfa_ID/what_is_alfa_id.md)
- [Что такое Alfa ID](Alfa_ID/what_is_alfa_id.md)
- [Authorization Code Flow](Alfa_ID/Authorization_Code_Flow/how_to_use_ACF.md)
- [H2H Аутентификация](Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/How_to_use_ACF_for_H2H.md)
### 💳 [Номинальные счета](продукты_и_сервисы/Номинальные_счета/intro.md)
- [Введение](продукты_и_сервисы/Номинальные_счета/intro.md)
- [Выплаты](продукты_и_сервисы/Номинальные_счета/Выплаты/intro.md)
- [Безопасные сделки](продукты_и_сервисы/Номинальные_счета/Безопасные_сделки/intro.md)
- [Идентификация пополнений](продукты_и_сервисы/Номинальные_счета/Идентификация_пополнений/how_it_works_intro.md)
### 🛠 [Инструменты и Безопасность](Общая_информация/authorization.md)
- [Авторизация (API Key / Alfa ID)](Общая_информация/authorization.md)
- [Вебхуки](Вебхуки/webhooks_intro.md)
- [Транспортная подпись и шифрование](Транспортная_подпись_и_шифрование/signature-encryption-intro.md)
- [Песочница](Песочница/sandbox_intro.md)
---
[Все эндпоинты](../endpoints.md)

View File

@@ -1,7 +1,6 @@
Ниже представлен сконвертированный из HTML текст документации в формате Markdown. Все ссылки сохранены, структура таблиц и примеров кода приведена к удобному для чтения виду.
---
# Удаление вебхука
**Теги:** `B2B` `B2C` `H2H`
@@ -14,7 +13,7 @@
| **Пром** | `DELETE https://baas.alfabank.ru/api/v1/webhooks/{id}` |
### Scope
`scope` события, на которое подписываетесь, с допустимыми значениями можно посмотреть [здесь](https://developers.alfabank.ru/products/alfa-api/documentation/articles/webhooks/webhooks).
`scope` события, на которое подписываетесь, с допустимыми значениями можно посмотреть [здесь](webhooks_intro.md).
---
@@ -23,7 +22,7 @@
### HEADERS
| Атрибут | Тип | Обязательность | Описание |
| :--- | :--- | :--- | :--- |
| **Authorization** | string | **required** | Bearer {access_token}, полученный по [Authorization Code Flow](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/acf/articles/intro/intro) / [Authorization Code Flow H2H](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/acf-h2h/articles/intro/intro) |
| **Authorization** | string | **required** | Bearer {access_token}, полученный по [Authorization Code Flow](../Alfa_ID/Authorization_Code_Flow/how_to_use_ACF.md) / [Authorization Code Flow H2H](../Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/How_to_use_ACF_for_H2H.md) |
| **Accept** | string | **required** | `application/json` |
| **Content-Type** | string | optional | `application/json` |
@@ -95,4 +94,4 @@ curl -X DELETE https://baas.alfabank.ru/api/v1/webhooks/f9f8c674-7a2a-4297-bdb8-
---
**Навигация:**
[← Редактирование вебхука](https://developers.alfabank.ru/products/alfa-api/documentation/articles/webhooks/articles/edit-webhook/v2/edit-webhook) | [Получение вебхука →](https://developers.alfabank.ru/products/alfa-api/documentation/articles/webhooks/articles/get-webhook/v1/get-webhook)
[← Редактирование вебхука](edit-webhook.md) | [Получение вебхука →](get-webhook.md)

View File

@@ -23,10 +23,10 @@
Это упрощённый способ авторизации запросов без аутентификации сотрудников вашей организации, который не требует регулярного обновления ключа доступа. Подходит для выполнения операций по своей организации. Контроль безопасности обеспечивается за счёт того, что запросы принимаются только с ваших доверенных серверов.
Доступные с помощью этого способа авторизации продукты и сервисы можно посмотреть [здесь](https://developers.alfabank.ru/products/alfa-api/documentation/articles/selfservice/articles/api-key/api-key).
Доступные с помощью этого способа авторизации продукты и сервисы можно посмотреть [здесь](../API_Key/api-key.md).
Использование упрощённого способа авторизации будет оптимальным вариантом, если у вас H2H-интеграция, использующая продукты и сервисы, доступные с помощью `API Key` , и вам не требуется аутентификация сотрудников для доступа к продуктам и сервисам Alfa API.
Подробнее о способах авторизации можно прочитать в статьях ниже.
[Alfa ID](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/intro/intro)[API Key](https://developers.alfabank.ru/products/alfa-api/documentation/articles/api-key/api-key)
[Alfa ID](../Alfa_ID/what_is_alfa_id.md) [API Key](../API_Key/api-key.md)

View File

@@ -12,6 +12,6 @@
Шифрование канала происходит исходя из выбора метода шифрования. Это может быть:
•шифрование с применением сертификата RSA (как применить RSA-сертификат смотрите в разделе [Требования к сертификату](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/tls/tls));•шифрование с применением сертификатов ГОСТ (раздел в подготовке).Выбор того или иного метода шифрования канала определяется критичностью данных:
•шифрование с применением сертификата RSA (как применить RSA-сертификат смотрите в разделе [Требования к сертификату](../Подключение_к_Alfa_API/tls-cert.md));•шифрование с применением сертификатов ГОСТ (раздел в подготовке).Выбор того или иного метода шифрования канала определяется критичностью данных:
•если персональные данные не передаются, то TLS RSA будет самым простым, дешёвым и гибким инструментом интеграции;•если персональные данные передаются, то обязательно использование сертификата ГОСТ. Партнёр API может выбирать, что использовать - TLS ГОСТ или вариант с ФПСУ ГОСТ.

View File

@@ -1,16 +1,16 @@
## Чек-лист готовности к тестовой интеграции
1. **Заключите соглашение и договор**
Заключите соглашение о конфиденциальности и неразглашении информации, договор на информационно-технологическое взаимодействие с банком и подпишите приложения к нему. Подробнее в шаге 1 [инструкции по подключению](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/instruction/instruction).
Заключите соглашение о конфиденциальности и неразглашении информации, договор на информационно-технологическое взаимодействие с банком и подпишите приложения к нему. Подробнее в шаге 1 [инструкции по подключению](../Подключение_к_Alfa_API/how_to_connect.md).
2. **Получите тестовые client_id и scope**
Подробнее в шаге 2 [инструкции по подготовке к работе с песочницей](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/instruction/instruction).
Подробнее в шаге 2 [инструкции по подготовке к работе с песочницей](../Подключение_к_Alfa_API/how_to_connect.md).
3. **Установите тестовый TLS-сертификат, сертификаты Минцифры и проверьте доступ до Swagger UI**
Подробнее в шагах 3-5 [инструкции по подготовке к работе с песочницей](https://developers.alfabank.ru/products/alfa-api/documentation/articles/sandbox/sandbox).
Подробнее в шагах 3-5 [инструкции по подготовке к работе с песочницей](../Песочница/sandbox_intro.md).
4. **Получите тестовый client_secret**
Подробнее [на странице Client secret](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/clientsecret/clientsecret).
Подробнее [на странице Client secret](../Подключение_к_Alfa_API/client_secret.md).
5. **Реализуйте и протестируйте интеграцию Alfa ID и Alfa API в песочнице**
@@ -21,12 +21,12 @@
2. **Создайте интеграцию в проме на Портале разработчика**
Подробнее [на странице Создание интеграции в проме](https://developers.alfabank.ru/products/alfa-api/documentation/articles/selfservice/articles/prod/prod)
Подробнее [на странице Создание интеграции в проме](../Портал_разработчика/creating_prod_integration.md)
3. **Выпустите TLS-сертификат**
Подробнее [на странице TLS-сертификат](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/tls/tls)
Подробнее [на странице TLS-сертификат](../Подключение_к_Alfa_API/tls-cert.md)
4. **Получите client_secret**
Подробнее [на странице Client secret](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/clientsecret/clientsecret)
Подробнее [на странице Client secret](../Подключение_к_Alfa_API/client_secret.md)
5. **Начните использовать Alfa ID и Alfa API**

View File

@@ -8,9 +8,9 @@
Перед началом работы рекомендуем внимательно ознакомиться с нашей документацией, которая содержит всю необходимую информацию для успешной интеграции.
[Подключение к Alfa API](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/connection)
[Подключение к Alfa API](../Подключение_к_Alfa_API/how_to_connect.md)
[Песочница](https://developers.alfabank.ru/products/alfa-api/documentation/articles/sandbox/sandbox)
[Песочница](../Песочница/sandbox_intro.md)
## Преимущества

View File

@@ -82,4 +82,4 @@ invalid_request
Сортировка в пагинации происходит следующим образом: вверху списка возвращаются новые записи, внизу - старые записи.
---
[Версионирование](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/version/version) | [Термины и определения](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/terms/terms)
[Версионирование](vensioning.md) | [Термины и определения](terms_and_definitions.md)

View File

@@ -61,5 +61,5 @@
**Scopes** – это общий набор операций и/или клэймов.
---
[Пагинация](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/pagination/pagination) | [Что это и для чего нужно](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/intro/intro)
[Пагинация](pagination.md) | [Что это и для чего нужно](Сертификаты_Минцифры/what_it_is_and_what_it_is_for.md)

View File

@@ -57,4 +57,4 @@ B2BB2CH2H# Сертификаты для Android
Очистите кэш вашего браузераОчистите кэш браузера на устройстве, с которого осуществляется доступ. Это необходимо для корректной работы с ресурсами, защищёнными сертификатами безопасности Минцифры.
[Что это и для чего нужно](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/intro/intro)[Сертификаты для iOS](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/ios/ios)
[Что это и для чего нужно](what_it_is_and_what_it_is_for.md) [Сертификаты для iOS](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/ios/ios)

View File

@@ -78,4 +78,4 @@ B2BB2CH2H# Сертификаты для Linux
Очистите кэш вашего браузераОчистите кэш браузера на устройстве, с которого осуществляется доступ. Это необходимо для корректной работы с ресурсами, защищёнными сертификатами безопасности Минцифры.
[Сертификаты для MacOS](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/macos/macos)[Как подключить](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/instruction/instruction)
[Сертификаты для MacOS](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/macos/macos) [Как подключить](../../Подключение_к_Alfa_API/how_to_connect.md)

View File

@@ -19,4 +19,4 @@
Ответы на часто задаваемые вопросы можно посмотреть здесь.
---
[Термины и определения](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/terms/terms) | [Сертификаты для Android](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/android/android)
[Термины и определения](../terms_and_definitions.md) | [Сертификаты для Android](for_android.md)

View File

@@ -12,8 +12,8 @@
---
### Описание процесса
* **RSA-сертификат:** Процесс формирования и подписания описан [здесь](https://developers.alfabank.ru/products/alfa-api/documentation/articles/signature-encryption/articles/signature/articles/text-rsa/text-rsa), а шифрования — [здесь](https://developers.alfabank.ru/products/alfa-api/documentation/articles/signature-encryption/articles/encryption/articles/text-rsa/text-rsa).
* **ГОСТ-сертификат:** Процесс формирования и подписания описан [здесь](https://developers.alfabank.ru/products/alfa-api/documentation/articles/signature-encryption/articles/signature/articles/text-gost/text-gost), а шифрования — [здесь](https://developers.alfabank.ru/products/alfa-api/documentation/articles/signature-encryption/articles/encryption/articles/text-gost/text-gost).
* **RSA-сертификат:** Процесс формирования и подписания описан [здесь](../../Транспортная_подпись_и_шифрование/transport-signature/json-rsa.md), а шифрования — [здесь](../../Транспортная_подпись_и_шифрование/encription/json-rsa.md).
* **ГОСТ-сертификат:** Процесс формирования и подписания описан [здесь](../../Транспортная_подпись_и_шифрование/transport-signature/json-ghost.md), а шифрования — [здесь](../../Транспортная_подпись_и_шифрование/encription/json-ghost.md).
* **Тестирование:** Подписание запроса и дешифрование ответа происходит с использованием закрытого ключа. Для тестов используйте [закрытый ключ](https://developers.alfabank.ru/assets/developers-portal.docs.alfa-api/articles/sandbox/articles/signature/articles/text/v1/files/sandbox_alfa_test_jwt_2026.zip) (пароль уточняйте у персонального менеджера).
> **⚠️ Внимание**

View File

@@ -8,19 +8,19 @@
> Если вы ещё не являетесь клиентом Альфа-Банка, то для подключения к Alfa API вам необходимо открыть [счёт](https://alfabank.ru/sme/quick/docstariffs/), оформить [расчётно-кассовое обслуживание](https://alfabank.ru/sme/) и подключить [Альфа-Бизнес](https://alfabank.ru/corporate/rko/internet-bank/#form).
1. **Подпишите договор**
[Подпишите договор](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/onboarding/onboarding).
[Подпишите договор](contract_signing.md).
Комиссия за подключение и использование не взимается. Вопросы по заключению договора можно направлять на почту [alfa_api@alfabank.ru](https://developers.alfabank.rumailto:alfa_api@alfabank.ru).
Комиссия за подключение и использование не взимается. Вопросы по заключению договора можно направлять на почту [alfa_api@alfabank.ru](mailto:alfa_api@alfabank.ru).
2. **Проверьте тестовую интеграцию**
Получите тестовые учётные данные и настройте тестовую интеграцию [на Портале разработчика](https://developers.alfabank.ru/products/alfa-api/documentation/articles/selfservice/articles/test/test), реализуйте и протестируйте аутентификацию в Alfa ID и вызов методов Alfa API [в песочнице](https://developers.alfabank.ru/products/alfa-api/documentation/articles/sandbox/sandbox).
Получите тестовые учётные данные и настройте тестовую интеграцию [на Портале разработчика](../Портал_разработчика/testing.md), реализуйте и протестируйте аутентификацию в Alfa ID и вызов методов Alfa API [в песочнице](../Песочница/sandbox_intro.md).
3. **Подготовьтесь к промышленной интеграции**
Создайте интеграцию в проме, выпустите TLS-сертификат и `client_secret` . Подробнее [в инструкции](https://developers.alfabank.ru/products/alfa-api/documentation/articles/selfservice/articles/prod/prod).
Создайте интеграцию в проме, выпустите TLS-сертификат и `client_secret` . Подробнее [в инструкции](../Портал_разработчика/creating_prod_integration.md).
4. **Используйте Alfa API**
Если вы ещё не являетесь клиентом Альфа-Банка, то для подключения к Alfa API вам необходимо открыть [счёт](https://alfabank.ru/sme/quick/docstariffs/), оформить [расчётно-кассовое обслуживание](https://alfabank.ru/sme/) и подключить [Альфа-Бизнес](https://alfabank.ru/corporate/rko/internet-bank/#form).
---
[← Сертификаты для Linux](https://developers.alfabank.ru/products/alfa-api/documentation/articles/specification/articles/certificate/articles/linux/linux) [← Подписание договора](https://developers.alfabank.ru/products/alfa-api/documentation/articles/connection/articles/onboarding/onboarding)
[← Сертификаты для Linux](../Общая_информация/Сертификаты_Минцифры/for_linux.md) [← Подписание договора](contract_signing.md)

View File

@@ -0,0 +1,137 @@
какой email технической поддержки ?
10:36
Доставлено
Для связи с технической поддержкой используйте электронную почту alfa\_api@alfabank.ru.
10:36
как происходит flow регистрации бенифициара ?
10:53
Доставлено
Для регистрации бенефициара необходимо выполнить следующие шаги:
1. 1.
**Создать запрос на регистрацию бенефициара** с помощью метода:
- •
**Песочница**: `POST https://sandbox.alfabank.ru/api/na/jp/v1/beneficiaries`
- •
**Пром**: `POST https://baas.alfabank.ru/api/na/jp/v1/beneficiaries`
При этом нужно учитывать, что в зависимости от типа бенефициара поля запроса заполняются по-разному.
2. 2.
3. 3.
При успешной регистрации бенефициару присваивается уникальный идентификатор — `beneficiaryId`.
**Важно:** учёт денежных средств на виртуальных счетах бенефициаров будет вестись корректно только при условии, что владелец номинального счёта не использует другие каналы вывода средств с номинального счёта (например, банк-клиент, платёжные поручения на бумажном носителе, сервисы Alfa API для осуществления переводов и другие).
Ссылки на документацию:
- •
- •
- •
10:53
а как же socring ?
10:55
Доставлено
Для проверки актуальности ранее зарегистрированных данных о бенефициаре используются следующие методы:
1. 1.
**«Создание запроса на проверку бенефициара»** — инициирует процесс скоринга бенефициара.
2. 2.
**«Получение статуса запроса»** — позволяет отслеживать статус ранее созданного запроса на проверку.
**Ссылки на документацию:**
- •
- •
10:55
каким образом можно пополнить номинальный счёт компании ?
22:24
Доставлено
Депонент (бенефициар) может пополнить номинальный счёт удобным ему способом. После этого владелец номинального счёта должен идентифицировать поступившие денежные средства. Для этого владельцу счёта необходимо выполнить следующие шаги:
1. 1.
2. 2.
3. 3.
22:25
каким образом можно пополнить номинальный счёт компании ?
22:25
Доставлено
Депонент (бенефициар) может пополнить номинальный счёт удобным ему способом. После этого владелец номинального счёта должен идентифицировать поступившие денежные средства. Для этого владельцу счёта необходимо выполнить следующие шаги:
1. 1.
2. 2.
3. 3.
**Важно:** для работы с сервисом необходимо использовать электронную подпись. Допускается использование сертификата, выпущенного с помощью [сервиса «Электронная подпись»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/signature/articles/intro/intro), или сертификата УКЭП, выпущенного в любом аккредитованном УЦ.
Ссылка на статью с подробным описанием процесса: [Идентификация пополнений номинального счёта](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/intro/intro).
22:25
а что это значит "любым удобным способом"? каким например ?
22:25
Доставлено
В предоставленной документации нет конкретного перечня способов пополнения номинального счёта. Однако указано, что депонент (бенефициар) может пополнить номинальный счёт удобным ему способом. После этого владелец номинального счёта должен идентифицировать поступившие денежные средства с помощью специальных методов API.
Для идентификации пополнений владелец счёта может использовать следующие методы:
1. 1.
2. 2.
3. 3.
Для более детальной информации о возможных способах пополнения номинального счёта рекомендуется обратиться на почту alfa\_api@alfabank.ru.
22:25

View File

@@ -0,0 +1,153 @@
---
title: "Интеграция с Альфа-Банком: API, документация, примеры кода"
source: "https://developers.alfabank.ru/products/alfa-api/documentation/articles/sandbox/articles/nominal-accounts/articles/intro/intro"
author:
published:
created: 2026-04-07
description: "Описания API-методов, примеры запросов, инструкции по настройке интеграции для работы с продуктами и сервисами Альфа-Банка"
tags:
- "clippings"
---
#### Инструкция по тестированию
Рекомендации по тестированию [номинальных счетов](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/intro/intro).
##### Идентификация пополнений
Для тестирования методов для идентификации пополнений номинального счёта предварительно необходимо создать тестовое неидентифицированное пополнение с помощью метода [«Создание тестового неидентифицированного пополнения номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/sandbox/articles/nominal-accounts/articles/unidentified-transaction/v1/unidentified-transaction).
В результате успешного запроса будет создано тестовое неидентифицированное пополнение c идентификатором `id`, который далее необходимо будет передать в методе [«Создание запроса на идентификацию пополнения номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/identify/v1/identify).
[Создание тестового неидентифицированного пополнения номинального счёта](https://developers.alfabank.ru/products/alfa-api/documentation/articles/sandbox/articles/nominal-accounts/articles/unidentified-transaction/v1/unidentified-transaction)
API Helper
Beta
---
какой email технической поддержки?
10:36
Доставлено
Для связи с технической поддержкой используйте электронную почту alfa\_api@alfabank.ru.
10:36
как происходит flow регистрации бенифициара?
10:53
Доставлено
Для регистрации бенефициара необходимо выполнить следующие шаги:
1. 1.
**Создать запрос на регистрацию бенефициара** с помощью метода:
- •
**Песочница**: `POST https://sandbox.alfabank.ru/api/na/jp/v1/beneficiaries`
- •
**Пром**: `POST https://baas.alfabank.ru/api/na/jp/v1/beneficiaries`
При этом нужно учитывать, что в зависимости от типа бенефициара поля запроса заполняются по-разному.
2. 2.
**Получить статус запроса** с помощью метода [«Получение статуса запроса»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/get-request-status/v1/get-request-status).
3. 3.
**После регистрации бенефициара необходимо указать его платёжные реквизиты** с помощью метода [«Добавление платёжных реквизитов бенефициара»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/beneficiaries/articles/add-requisites/v1/add-requisites).
При успешной регистрации бенефициару присваивается уникальный идентификатор — `beneficiaryId`.
**Важно:** учёт денежных средств на виртуальных счетах бенефициаров будет вестись корректно только при условии, что владелец номинального счёта не использует другие каналы вывода средств с номинального счёта (например, банк-клиент, платёжные поручения на бумажном носителе, сервисы Alfa API для осуществления переводов и другие).
Ссылки на документацию:
- •
[Создание запроса на регистрацию бенефициара](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/beneficiaries/articles/add-beneficiary/v1/add-beneficiary)
- •
[Получение статуса запроса](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/get-request-status/v1/get-request-status)
- •
[Добавление платёжных реквизитов бенефициара](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/beneficiaries/articles/add-requisites/v1/add-requisites)
10:53
а как же socring?
10:55
Доставлено
Для проверки актуальности ранее зарегистрированных данных о бенефициаре используются следующие методы:
1. 1.
**«Создание запроса на проверку бенефициара»** — инициирует процесс скоринга бенефициара.
2. 2.
**«Получение статуса запроса»** — позволяет отслеживать статус ранее созданного запроса на проверку.
**Ссылки на документацию:**
- •
[Создание запроса на проверку бенефициара](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/beneficiaries/articles/beneficiary-scoring/v1/beneficiary-scoring)
- •
[Получение статуса запроса](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/get-request-status/v1/get-request-status)
10:55
каким образом можно пополнить номинальный счёт компании?
22:24
Доставлено
Депонент (бенефициар) может пополнить номинальный счёт удобным ему способом. После этого владелец номинального счёта должен идентифицировать поступившие денежные средства. Для этого владельцу счёта необходимо выполнить следующие шаги:
1. 1.
**Получить информацию обо всех неидентифицированных пополнениях** с помощью метода [«Получение списка неидентифицированных пополнений номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-unidentified-transactions/v1/get-unidentified-transactions).
2. 2.
**Создать запрос на идентификацию денежных средств** с помощью метода [«Создание запроса на идентификацию пополнения номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/identify/v1/identify).
3. 3.
**Получить статус запроса на идентификацию денежных средств** с помощью метода [«Получение статуса запроса на идентификацию пополнения номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-identify-request-status/v1/get-identify-request-status).
22:25
каким образом можно пополнить номинальный счёт компании?
22:25
Доставлено
Депонент (бенефициар) может пополнить номинальный счёт удобным ему способом. После этого владелец номинального счёта должен идентифицировать поступившие денежные средства. Для этого владельцу счёта необходимо выполнить следующие шаги:
1. 1.
Получить информацию обо всех неидентифицированных пополнениях с помощью метода [«Получение списка неидентифицированных пополнений номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-unidentified-transactions/v1/get-unidentified-transactions).
2. 2.
Создать запрос на идентификацию денежных средств с помощью метода [«Создание запроса на идентификацию пополнения номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/identify/v1/identify).
3. 3.
Получить статус запроса на идентификацию денежных средств с помощью метода [«Получение статуса запроса на идентификацию пополнения номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-identify-request-status/v1/get-identify-request-status).
**Важно:** для работы с сервисом необходимо использовать электронную подпись. Допускается использование сертификата, выпущенного с помощью [сервиса «Электронная подпись»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/signature/articles/intro/intro), или сертификата УКЭП, выпущенного в любом аккредитованном УЦ.
Ссылка на статью с подробным описанием процесса: [Идентификация пополнений номинального счёта](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/intro/intro).
22:25
а что это значит "любым удобным способом"? каким например?
22:25
Доставлено
В предоставленной документации нет конкретного перечня способов пополнения номинального счёта. Однако указано, что депонент (бенефициар) может пополнить номинальный счёт удобным ему способом. После этого владелец номинального счёта должен идентифицировать поступившие денежные средства с помощью специальных методов API.
Для идентификации пополнений владелец счёта может использовать следующие методы:
1. 1.
Получить информацию обо всех неидентифицированных пополнениях: [«Получение списка неидентифицированных пополнений номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-unidentified-transactions/v1/get-unidentified-transactions).
2. 2.
Создать запрос на идентификацию денежных средств: [«Создание запроса на идентификацию пополнения номинального счёта»](https://developers.alfa-bank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/identify/v1/identify).
3. 3.
Получить статус запроса на идентификацию денежных средств: [«Получение статуса запроса на идентификацию пополнения номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-identify-request-status/v1/get-identify-request-status).
Для более детальной информации о возможных способах пополнения номинального счёта рекомендуется обратиться на почту alfa\_api@alfabank.ru.
22:25

View File

@@ -0,0 +1,355 @@
H2H
Песочница
POST https://sandbox.alfabank.ru/api/na/jp/v1/unidentified-transactions
##### Scope
`beneficiary-payments`
[](https://developers.alfabank.ru/assets/developers-portal.docs.alfa-api/articles/sandbox/articles/nominal-accounts/articles/unidentified-transaction/v1/files/unidentified-transaction.yaml)
##### Описание
Метод позволяет создать тестовое неидентифицированное пополнение номинального счёта.
###### Параметры запроса
Атрибут
Описание
Authorization
Accept
stringrequired
application/json
Content-Type
stringrequired
application/json
Атрибут
Описание
documentNumber
stringrequired
Номер платёжного поручения
date
stringrequired
Дата и время пополнения по МСК
amount
stringrequired
Сумма пополнения в рублях
purpose
stringrequired
Назначение платежа
accountNumber
stringrequired
Номер номинального счёта
objectrequired
Информация о плательщике
inn
stringoptional
ИНН плательщика
kpp
stringoptional
КПП плательщика
accountNumber
stringoptional
Номер счёта плательщика
name
stringoptional
Имя плательщика
bankAccount
stringoptional
Номер счёта банка плательщика
bankBik
stringoptional
БИК банка плательщика
bankName
stringoptional
Наименования банка плательщика
```bash
1curl --location 'https://baas.alfabank.ru/api/na/jp/v1/unidentified-transactions' \
2--header 'Authorization: Bearer {access-token}' \
3--header 'Content-Type: application/json' \
4--header 'Accept: application/json' \
5--data '{
6 "documentNumber": "3",
7 "date": "2026-04-03T13:23:24.439Z",
8 "amount": 200.9,
9 "purpose": "Входящая транзакция созданная вручную для тестирования на песочнице",
10 "accountNumber": "40817810306050000000",
11 "payer": {
12 "inn": "221284672706",
13 "kpp": "641914992",
14 "accountNumber": "87149728127096890679",
15 "name": "Имя плательщика",
16 "bankAccount": "3932755239052037086628",
17 "bankBik": "108997635",
18 "bankName": "Наименования банка плательщика"
19 }
20}'
```
###### Параметры ответа
```json
1{
2 "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6\"",
3 "documentNumber": "3",
4 "date": "2025-04-08T10:47:17.927Z",
5 "amount": 200.9,
6 "purpose": "Входящая транзакция созданная вручную для тестирования на песочнице",
7 "accountNumber": "40817810306050000000",
8 "payer": {
9 "inn": "221284672706",
10 "kpp": "641914992",
11 "accountNumber": "87149728127096890679",
12 "name": "Имя плательщика",
13 "bankAccount": "3932755239052037086628",
14 "bankBik": "108997635",
15 "bankName": "Наименования банка плательщика"
16 }
17}
```
атрибут
описание
id
stringrequired
Идентификатор операции пополнения
documentNumber
stringrequired
Номер платёжного поручения
date
stringrequired
Дата и время пополнения по МСК
amount
stringrequired
Сумма пополнения в рублях
purpose
stringrequired
Назначение платежа
accountNumber
stringrequired
Номер номинального счёта
objectrequired
Информация о плательщике
inn
stringoptional
ИНН плательщика
kpp
stringoptional
КПП плательщика
accountNumber
stringoptional
Номер счёта плательщика
name
stringoptional
Имя плательщика
bankAccount
stringoptional
Номер счёта банка плательщика
bankBik
stringoptional
БИК банка плательщика
bankName
stringoptional
Наименования банка плательщика
атрибут
описание
error
stringrequired
Код ошибки. Принимает возможные значения:
- •
`invalid_request` — неверные входные параметры запроса
error\_description
stringoptional
Описание ошибки
атрибут
описание
error
stringrequired
Код ошибки. Принимает возможные значения:
- •
`invalid_token` — предоставленный токен просрочен, отозван, имеет неправильный формат или недействителен по другим причинам
error\_description
stringoptional
Описание ошибки
атрибут
описание
error
stringrequired
Код ошибки. Принимает возможные значения:
- •
`insufficient_scope` — у пользователя нет прав на использование запрашиваемого сервиса, доступ к которому не предусмотрен настройками scope
error\_description
stringoptional
Описание ошибки
атрибут
описание
error
stringrequired
Код ошибки. Принимает возможные значения:
- •
`unknown_endpoint` — эндпоинт не найден или неактивен
error\_description
stringoptional
Описание ошибки
Нет тела ответа
атрибут
описание
error
stringrequired
Код ошибки. Принимает возможные значения:
- •
`internal_error` — внутренняя ошибка сервиса при выполнении обработки запроса
error\_description
stringoptional
Описание ошибки
Нет тела ответа

View File

@@ -22,7 +22,7 @@
| Атрибут | Тип | Обязательность | Описание |
| :---------------- | :----- | :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Authorization** | string | required | Bearer {access_token}, полученный по [Authorization Code Flow H2H](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/acf-h2h/articles/intro/intro) |
| **Authorization** | string | required | Bearer {access_token}, полученный по [Authorization Code Flow H2H](../../../../Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/How_to_use_ACF_for_H2H.md) |
| **Accept** | string | required | application/json |
### PATH (Путь)

View File

@@ -2,22 +2,22 @@
_Номинальные счета / Выплаты / Как это работает_
Для осуществления выплат с номинального счёта предварительно необходимо [зарегистрировать контрагента](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/intro/intro), участвующего в выплате.
Для осуществления выплат с номинального счёта предварительно необходимо [зарегистрировать контрагента](../Контрагенты/intro.md), участвующего в выплате.
## Общий механизм выплат с номинального счёта
1. **Создайте запрос на выплату**
Метод [«Создание запроса на выплату с номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/payoff/v1/payoff)
Метод [«Создание запроса на выплату с номинального счёта»](payoff.md)
2. **Получите статус запроса на выплату**
Метод [«Получение статуса запроса на выплату с номинального счёта»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/get-payoff-request-status/v1/get-payoff-request-status)
Метод [«Получение статуса запроса на выплату с номинального счёта»](get-payoff-request-status.md)
3. **Подтвердите или отклоните обработку запроса-дубля на выплату**
В случае, если статус запроса на выплату уже был создан ранее, он примет статус `MANUAL_ACCEPTANCE` и его нужно будет подтвердить или отклонить.
Метод [«Подтвердить или отклонить запрос-дубль на выплату»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/payoff-accept/v1/payoff-accept)
Метод [«Подтвердить или отклонить запрос-дубль на выплату»](payoff-accept.md)
4. **Получите информацию о платеже по его идентификатору**
Метод [«Получение информации о платеже»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/get-payoff/v1/get-payoff)
Метод [«Получение информации о платеже»](get-payoff.md)
---
@@ -33,13 +33,13 @@ _Номинальные счета / Выплаты / Как это работа
Необходимо учитывать:
- На номинальном счёте должен быть положительный баланс.
- Если выплата производится в пользу универсального реципиента, то для него предварительно необходимо зарегистрировать платёжные реквизиты с помощью метода [«Добавление платёжных реквизитов универсального реципиента»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/universal-recipients/articles/add-requisites/v1/add-requisites).
- Если выплата производится в пользу универсального реципиента, то для него предварительно необходимо зарегистрировать платёжные реквизиты с помощью метода [«Добавление платёжных реквизитов универсального реципиента»](../Контрагенты/Универсальные_реципиенты/add-requisites.md).
В качестве платёжных реквизитов получателя могут быть указаны:
- реквизиты счёта;
- номер телефона (СБП);
- зашифрованный номер карты (как зашифровать номер карты, описано [здесь](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/cardtoken/cardtoken));
- зашифрованный номер карты (как зашифровать номер карты, описано [здесь](../how-to-encrypt-your-card-number-eg-cardtoken.md));
- идентификатор платёжных реквизитов контрагента.
## Выплаты с биллингом на стороне Банка
@@ -55,11 +55,11 @@ _Номинальные счета / Выплаты / Как это работа
### Механизм возврата денежных средств с налогового виртуального кошелька
1. **Создайте запрос на возврат денежных средств с налогового виртуального кошелька**
Метод [«Создание запроса на возврат денежных средств с налогового виртуального кошелька»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/tax-refund/v1/tax-refund)
Метод [«Создание запроса на возврат денежных средств с налогового виртуального кошелька»](tax-refund.md)
2. **Получите статус запроса на возврат налоговых денежных средств**
Метод [«Получение статуса запроса на возврат налоговых денежных средств»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/get-tax-refund-request-status/v1/get-tax-refund-request-status)
Метод [«Получение статуса запроса на возврат налоговых денежных средств»](get-tax-refund-request-status.md)
3. **Подтвердите или отклоните обработку запроса-дубля на возврат денежных средств с налогового виртуального кошелька**
В случае, если статус запроса на выплату уже был создан ранее, он примет статус `MANUAL_ACCEPTANCE` и его нужно будет подтвердить или отклонить.
Метод [«Подтверждение или отклонение запроса-дубля на возврат денежных средств с налогового виртуального кошелька»](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/tax-refund-accept/v1/tax-refund-accept)
Метод [«Подтверждение или отклонение запроса-дубля на возврат денежных средств с налогового виртуального кошелька»](tax-refund-accept.md)

View File

@@ -27,7 +27,7 @@
| Атрибут | Тип | Обязательность | Описание |
| :---------------- | :----- | :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Authorization** | string | required | Bearer {access_token}, полученный по [Authorization Code Flow H2H](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/acf-h2h/articles/intro/intro) |
| **Authorization** | string | required | Bearer {access_token}, полученный по [Authorization Code Flow H2H](../../../../Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/How_to_use_ACF_for_H2H.md) |
| **Accept** | string | required | `application/json` |
### PATH (Путь)
@@ -90,5 +90,5 @@ curl --location --globoff --request PATCH \
## Навигация
- **Предыдущий шаг:** [Получение статуса запроса на возврат налоговых денежных средств](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/na-payments/articles/get-tax-refund-request-status/v1/get-tax-refund-request-status)
- **Предыдущий шаг:** [Получение статуса запроса на возврат налоговых денежных средств](get-tax-refund-request-status.md)
- **Раздел:** Номинальные счета / Выплаты

View File

@@ -1,7 +1,6 @@
Вот очищенная и структурированная версия документации в формате Markdown:
# Создание запроса на идентификацию пополнения номинального счёта
**Тип интеграции:** H2H
## Эндпоинты
@@ -27,7 +26,7 @@
### HEADERS
| Атрибут | Тип | Обяз. | Описание |
| :--- | :--- | :--- | :--- |
| **Authorization** | string | Да | Bearer {access_token}, полученный по [Authorization Code Flow H2H](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/acf-h2h/articles/intro/intro) |
| **Authorization** | string | Да | Bearer {access_token}, полученный по [Authorization Code Flow H2H](../../../../Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/How_to_use_ACF_for_H2H.md) |
| **Accept** | string | Да | application/json |
| **Content-Type** | string | Да | application/json |
@@ -104,5 +103,5 @@ curl --location --globoff 'https://baas.alfabank.ru/api/na/jp/v1/unidentified-tr
---
**Навигация:**
* [Предыдущая: Получение списка неидентифицированных пополнений](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-unidentified-transactions/v1/get-unidentified-transactions)
* [Следующая: Получение статуса запроса на идентификацию](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/identify-transactions/articles/get-identify-request-status/v1/get-identify-request-status)
* [Предыдущая: Получение списка неидентифицированных пополнений](get-unidentified-transactions.md)
* [Следующая: Получение статуса запроса на идентификацию](get-identify-request-status.md)

View File

@@ -28,7 +28,7 @@
| Атрибут | Тип | Обязательность | Описание |
| :---------------- | :------- | :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Authorization** | `string` | required | Bearer {access_token}, полученный по [Authorization Code Flow H2H](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/acf-h2h/articles/intro/intro) |
| **Authorization** | `string` | required | Bearer {access_token}, полученный по [Authorization Code Flow H2H](../../../../../Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/How_to_use_ACF_for_H2H.md) |
| **Accept** | `string` | required | `application/json` |
### PATH
@@ -86,5 +86,5 @@ curl --location --globoff --request POST 'https://baas.alfabank.ru/api/na/jp/v1/
## Навигация
- **Предыдущий метод:** [Создание запроса на изменение информации о бенефициаре](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/beneficiaries/articles/change-beneficiary/v1/change-beneficiary)
- **Следующий метод:** [Добавление платёжных реквизитов бенефициара](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/beneficiaries/articles/add-requisites/v1/add-requisites)
- **Предыдущий метод:** [Создание запроса на изменение информации о бенефициаре](change-beneficiary.md)
- **Следующий метод:** [Добавление платёжных реквизитов бенефициара](add-requisites.md)

View File

@@ -24,7 +24,7 @@
### HEADERS
| Атрибут | Тип | Обяз. | Описание |
| :--- | :--- | :--- | :--- |
| **Authorization** | string | Да | Bearer {access_token}, полученный по [Authorization Code Flow H2H](https://developers.alfabank.ru/products/alfa-api/documentation/articles/alfa-id/articles/acf-h2h/articles/intro/intro) |
| **Authorization** | string | Да | Bearer {access_token}, полученный по [Authorization Code Flow H2H](../../../../../Alfa_ID/Authorization_Code_Flow_for_H2H_Integrations/How_to_use_ACF_for_H2H.md) |
| **Accept** | string | Да | `application/json` |
| **Content-Type** | string | Да | `application/json` |
@@ -99,5 +99,5 @@ curl --location 'https://baas.alfabank.ru/api/na/jp/v1/universal-recipients' \
---
**Навигация:**
* Предыдущая статья: [Получение списка денежных операций бенефициара](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/beneficiaries/articles/get-transactions/v1/get-transactions)
* Следующая статья: [Получение списка универсальных реципиентов номинального счёта](https://developers.alfabank.ru/products/alfa-api/documentation/articles/nominal-accounts/articles/counterparties/articles/universal-recipients/articles/get-urs/v1/get-urs)
* Предыдущая статья: [Получение списка денежных операций бенефициара](../Бенефициары/get-transactions.md)
* Следующая статья: [Получение списка универсальных реципиентов номинального счёта](get-universal_recipients_list.md)

View File

@@ -1,8 +1,20 @@
## Главная
### Инструкция по интеграции СБП C2B (Альфа-Банк)
## Содержание
- [Обзор API](#1-обзор-api)
- [Процесс аутентификации](#2-процесс-аутентификации)
- [Тестирование](#3-тестирование)
- [Как провести тестовую оплату](#4-как-провести-тестовую-оплату)
- [Получение статуса платежа](#5-получение-статуса-платежа)
- [Переход на промышленную среду](#6-переход-на-промышленную-среду)
- [Статический QR-код](#статический-qr-код-сбп)
- [Динамический QR-код](#интеграция-динамических-qr-кодов-сбп)
- [Кассовая платёжная ссылка](#кассовая-платёжная-ссылка-сбп-техническая-документация)
Добро пожаловать в руководство по прямой интеграции с платежным шлюзом (ПШ) Альфа-Банка для реализации сервиса СБП C2B.
---
### ⚠️ Важное объявление (Изменение адресов)

View File

@@ -3,8 +3,8 @@ title: Available property mappers
weight: 19
---
In previous sections we've already seen how to [create](/docs/laravel-data/v4/as-a-data-transfer-object/mapping-property-names) data objects where the keys of the
payload differ from the property names of the data object. It is also possible to [transform](/docs/laravel-data/v4/as-a-resource/mapping-property-names) data objects to an array/json/... where the keys of the payload differ
In previous sections we've already seen how to [create](../as-a-data-transfer-object/mapping-property-names.md) data objects where the keys of the
payload differ from the property names of the data object. It is also possible to [transform](../as-a-resource/mapping-property-names.md) data objects to an array/json/... where the keys of the payload differ
from the property names of the data object.
These mappings can be set manually put the package also provide a set of mappers that can be used to automatically map

View File

@@ -16,7 +16,7 @@ interface Cast
A cast receives the following:
- **property** a `DataProperty` object which represents the property for which the value is cast. You can read more about the internal structures of the package [here](/docs/laravel-data/v4/advanced-usage/internal-structures)
- **property** a `DataProperty` object which represents the property for which the value is cast. You can read more about the internal structures of the package [here](../advanced-usage/internal-structures.md)
- **value** the value that should be cast
- **properties** an array of the current properties that will be used to create the data object
- **creationContext** the context in which the data object is being created you'll find the following info here:

View File

@@ -14,7 +14,7 @@ interface RuleInferrer
}
```
A collection of previous inferred rules is given, and a `DataProperty` object which represents the property for which the value is transformed. You can read more about the internal structures of the package [here](/docs/laravel-data/v4/advanced-usage/internal-structures).
A collection of previous inferred rules is given, and a `DataProperty` object which represents the property for which the value is transformed. You can read more about the internal structures of the package [here](../advanced-usage/internal-structures.md).
The `ValidationContext` is also injected, this contains the following info:

View File

@@ -16,7 +16,7 @@ interface Transformer
The following parameters are provided:
- **property**: a `DataProperty` object which represents the property for which the value is transformed. You can read more about the internal structures of the package [here](/docs/laravel-data/v4/advanced-usage/internal-structures)
- **property**: a `DataProperty` object which represents the property for which the value is transformed. You can read more about the internal structures of the package [here](../advanced-usage/internal-structures.md)
- **value**: the value that should be transformed, this will never be `null`
- **context**: a `TransformationContext` object which contains the current transformation context with the following properties:
- **transformValues** indicates if values should be transformed or not

View File

@@ -57,7 +57,7 @@ The `handle` method has several arguments:
- **payload** the non normalized payload
- **class** the `DataClass` object for the data
object [more info](/docs/laravel-data/v4/advanced-usage/internal-structures)
object [more info](../advanced-usage/internal-structures.md)
- **properties** the key-value properties which will be used to construct the data object
- **creationContext** the context in which the data object is being created you'll find the following info here:
- **dataClass** the data class which is being created

View File

@@ -118,7 +118,7 @@ Tip: we can also remove the `EnumCast` since the package will automatically cast
## Creating your own casts
It is possible to create your casts. You can read more about this in the [advanced chapter](/docs/laravel-data/v4/advanced-usage/creating-a-cast).
It is possible to create your casts. You can read more about this in the [advanced chapter](../advanced-usage/creating-a-cast.md).
## Casting arrays or collections of non-data types

View File

@@ -162,7 +162,7 @@ will try to create itself from the following types:
- An *array*
This list can be extended using extra normalizers, find more about
it [here](/docs/laravel-data/v4/advanced-usage/normalizers).
it [here](../advanced-usage/normalizers.md).
When a data object cannot be created using magical methods or the default methods, a `CannotCreateData`
exception will be thrown.
@@ -190,7 +190,7 @@ SongData::factory()->withoutMagicalCreation()->from($song);
## Advanced creation using factories
It is possible to configure how a data object is created, whether it will be validated, which casts to use and more. You
can read more about it [here](/docs/laravel-data/v4/as-a-data-transfer-object/factories).
can read more about it [here](../as-a-data-transfer-object/factories.md).
## DTO classes

View File

@@ -22,7 +22,7 @@ SongData::factory()->collect(Song::all())
## Disable property name mapping
We saw [earlier](/docs/laravel-data/v4/as-a-data-transfer-object/mapping-property-names) that it is possible to map
We saw [earlier](../as-a-data-transfer-object/mapping-property-names.md) that it is possible to map
property names when creating a data object from an array. This can be disabled when using a factory:
```php
@@ -47,7 +47,7 @@ SongData::factory()->withoutValidation()->from(['title' => 'Never gonna give you
## Disabling magic methods
A data object can be created
using [magic methods](/docs/laravel-data/v4/as-a-data-transfer-object/creating-a-data-object.md#magical-creation) , this can be disabled
using [magic methods](../as-a-data-transfer-object/creating-a-data-object.md.md#magical-creation) , this can be disabled
when using a factory:
```php
@@ -136,4 +136,4 @@ class SongData extends Data
}
```
You can read more about creation contexts [here](/docs/laravel-data/v4/advanced-usage/pipeline).
You can read more about creation contexts [here](../advanced-usage/pipeline.md).

View File

@@ -37,7 +37,7 @@ class ContractData extends Data
}
```
You can also use the `MapName` attribute when you want to combine input (see [transforming data objects](/docs/laravel-data/v4/as-a-resource/mapping-property-names)) and output property name mapping:
You can also use the `MapName` attribute when you want to combine input (see [transforming data objects](../as-a-resource/mapping-property-names.md)) and output property name mapping:
```php
#[MapName(SnakeCaseMapper::class)]
@@ -91,4 +91,4 @@ SongData::from([
]);
```
The package has a set of default mappers available, you can find them [here](/docs/laravel-data/v4/advanced-usage/available-property-mappers).
The package has a set of default mappers available, you can find them [here](../advanced-usage/available-property-mappers.md).

View File

@@ -68,4 +68,4 @@ SongData::factory()
->from(['title' => 'Never gonna give you up']); // artist will `null` instead of `Optional`
```
You can read more about this [here](/docs/laravel-data/v4/as-a-data-transfer-object/factories#disabling-optional-values).
You can read more about this [here](../as-a-data-transfer-object/factories.md#disabling-optional-values).

View File

@@ -63,7 +63,7 @@ class UpdateSongController
}
```
We have a complete section within these docs dedicated to validation, you can find it [here](/docs/laravel-data/v4/validation/introduction).
We have a complete section within these docs dedicated to validation, you can find it [here](../validation/introduction.md).
## Getting the data object filled with request data from anywhere

View File

@@ -18,7 +18,7 @@ Which will output the following array:
]
```
By default, calling `toArray` on a data object will recursively transform all properties to an array. This means that nested data objects and collections of data objects will also be transformed to arrays. Other complex types like `Carbon`, `DateTime`, `Enums`, etc... will be transformed into a string. We'll see in the [transformers](/docs/laravel-data/v4/as-a-resource/transformers) section how to configure and customize this behavior.
By default, calling `toArray` on a data object will recursively transform all properties to an array. This means that nested data objects and collections of data objects will also be transformed to arrays. Other complex types like `Carbon`, `DateTime`, `Enums`, etc... will be transformed into a string. We'll see in the [transformers](../as-a-resource/transformers.md) section how to configure and customize this behavior.
If you only want to transform a data object to an array without transforming the properties, you can call the `all` method:

View File

@@ -81,4 +81,4 @@ And a transformed version of the data object will look like this:
]
```
The package has a set of default mappers available, you can find them [here](/docs/laravel-data/v4/advanced-usage/available-property-mappers).
The package has a set of default mappers available, you can find them [here](../advanced-usage/available-property-mappers.md).

View File

@@ -43,7 +43,7 @@ class ArtistData extends Data{
Next to a `DateTimeInterfaceTransformer` the package also ships with an `ArrayableTransformer` that transforms an `Arrayable` object to an array.
It is possible to create transformers for your specific types. You can find more info [here](/docs/laravel-data/v4/advanced-usage/creating-a-transformer).
It is possible to create transformers for your specific types. You can find more info [here](../advanced-usage/creating-a-transformer.md).
## Global transformers
@@ -114,7 +114,7 @@ Outputting the following array:
]
```
The [mapping of property names](/docs/laravel-data/v4/as-a-resource/mapping-property-names) can also be disabled:
The [mapping of property names](../as-a-resource/mapping-property-names.md) can also be disabled:
```php
ArtistData::from($artist)->transform(
@@ -122,7 +122,7 @@ ArtistData::from($artist)->transform(
);
```
It is possible to enable [wrapping](/docs/laravel-data/v4/as-a-resource/wrapping-data) the data object:
It is possible to enable [wrapping](../as-a-resource/wrapping-data.md) the data object:
```php
use Spatie\LaravelData\Support\Wrapping\WrapExecutionType;

View File

@@ -5,7 +5,19 @@ weight: 1
In this quickstart, we'll guide you through the most important functionalities of the package and how to use them.
First, you should [install the package](/docs/laravel-data/v4/installation-setup).
## Table of Contents
- [Using requests](#using-requests)
- [Casting data](#casting-data)
- [Customizing the creation of a data object](#customizing-the-creation-of-a-data-object)
- [Nesting data objects and arrays of data objects](#nesting-data-objects-and-arrays-of-data-objects)
- [Usage in controllers](#usage-in-controllers)
- [Using transformers](#using-transformers)
- [Generating a blueprint](#generating-a-blueprint)
- [Lazy properties](#lazy-properties)
- [Conclusion](#conclusion)
First, you should [install the package](../installation-setup.md).
We will create a blog with different posts, so let's start with the `PostData` object. A post has a title, some content, a status and a date when it was published:
@@ -189,7 +201,7 @@ As you can see, we're missing the `date` rule on the `published_at` property. By
- `array` when a property type is `array`
- `enum:*` when a property type is a native enum
You can read more about the process of automated rule generation [here](/docs/laravel-data/v4/as-a-data-transfer-object/request-to-data-object#content-automatically-inferring-rules-for-properties-1).
You can read more about the process of automated rule generation [here](../as-a-data-transfer-object/request-to-data-object.md#content-automatically-inferring-rules-for-properties-1).
We can easily add the date rule by using an attribute to our data object:
@@ -232,7 +244,7 @@ array:4 [
]
```
There are [tons](/docs/laravel-data/v4/advanced-usage/validation-attributes) of validation rule attributes you can add to data properties. There's still much more you can do with validating data objects. Read more about it [here](/docs/laravel-data/v4/as-a-data-transfer-object/request-to-data-object#validating-a-request).
There are [tons](../advanced-usage/validation-attributes.md) of validation rule attributes you can add to data properties. There's still much more you can do with validating data objects. Read more about it [here](../as-a-data-transfer-object/request-to-data-object.md#validating-a-request).
Tip: By default, when creating a data object in a non request context, no validation is executed:
@@ -275,7 +287,7 @@ It is possible to define casts within the `data.php` config file. By default, th
This code means that if a class property is of type `DateTime`, `Carbon`, `CarbonImmutable`, ... it will be automatically cast.
You can create your own casts; read more about it [here](/docs/laravel-data/v4/advanced-usage/creating-a-cast).
You can create your own casts; read more about it [here](../advanced-usage/creating-a-cast.md).
### Local casts
@@ -356,7 +368,7 @@ class PostData extends Data
}
```
You can read more about casting [here](/docs/laravel-data/v4/as-a-data-transfer-object/casts).
You can read more about casting [here](../as-a-data-transfer-object/casts.md).
## Customizing the creation of a data object
@@ -406,7 +418,7 @@ class PostData extends Data
```
Magic creation methods allow you to create data objects from any type by passing them to the `from` method of a data
object, you can read more about it [here](/docs/laravel-data/v4/as-a-data-transfer-object/creating-a-data-object#content-magical-creation).
object, you can read more about it [here](../as-a-data-transfer-object/creating-a-data-object.md#content-magical-creation).
It can be convenient to transform more complex models than our `Post` into data objects because you can decide how a model
would be mapped onto a data object.
@@ -764,7 +776,7 @@ Which leads to the following JSON:
}
```
You can read more about transformers [here](/docs/laravel-data/v4/as-a-resource/transformers).
You can read more about transformers [here](../as-a-resource/transformers.md).
## Generating a blueprint
@@ -1010,19 +1022,19 @@ You can do quite a lot with lazy properties like including them:
- when they are requested in the URL query
- by default, with an option to exclude them
And a lot more. You can read all about it [here](/docs/laravel-data/v4/as-a-resource/lazy-properties).
And a lot more. You can read all about it [here](../as-a-resource/lazy-properties.md).
## Conclusion
So that's it, a quick overview of this package. We barely scratched the surface of what's possible with the package. There's still a lot more you can do with data objects like:
- [casting](/docs/laravel-data/v4/advanced-usage/eloquent-casting) them into Eloquent models
- [transforming](/docs/laravel-data/v4/advanced-usage/typescript) the structure to typescript
- [working](/docs/laravel-data/v4/as-a-data-transfer-object/collections) with `DataCollections`
- [optional properties](/docs/laravel-data/v4/as-a-data-transfer-object/optional-properties) not always required when creating a data object
- [wrapping](/docs/laravel-data/v4/as-a-resource/wrapping) transformed data into keys
- [mapping](/docs/laravel-data/v4/as-a-data-transfer-object/mapping-property-names) property names when creating or transforming a data object
- [appending](/docs/laravel-data/v4/as-a-resource/appending-properties) extra data
- [including](/docs/laravel-data/v4/as-a-resource/lazy-properties#content-using-query-strings) properties using the URL query string
- [casting](../advanced-usage/eloquent-casting.md) them into Eloquent models
- [transforming](../advanced-usage/typescript.md) the structure to typescript
- [working](../as-a-data-transfer-object/collections.md) with `DataCollections`
- [optional properties](../as-a-data-transfer-object/optional-properties.md) not always required when creating a data object
- [wrapping](../as-a-resource/wrapping.md) transformed data into keys
- [mapping](../as-a-data-transfer-object/mapping-property-names.md) property names when creating or transforming a data object
- [appending](../as-a-resource/appending-properties.md) extra data
- [including](../as-a-resource/lazy-properties.md#content-using-query-strings) properties using the URL query string
- [inertia](https://spatie.be/docs/laravel-data/v4/advanced-usage/use-with-inertia) support for lazy properties
- and so much more ... you'll find all the information here in the docs

View File

@@ -57,4 +57,4 @@ By default, five rule inferrers are enabled:
- A `array` type will add the `array` rule
- **AttributesRuleInferrer** will make sure that rule attributes we described above will also add their rules
It is possible to write your rule inferrers. You can find more information [here](/docs/laravel-data/v4/advanced-usage/creating-a-rule-inferrer).
It is possible to write your rule inferrers. You can find more information [here](../advanced-usage/creating-a-rule-inferrer.md).

View File

@@ -56,7 +56,7 @@ Completely disabling validation can be done by setting the `validation_strategy`
'validation_strategy' => \Spatie\LaravelData\Support\Creation\ValidationStrategy::Disabled->value,
```
If you require a more fine-grained control over when validation should happen, you can use [data factories](/docs/laravel-data/v4/as-a-data-transfer-object/factories) to manually specify the validation strategy.
If you require a more fine-grained control over when validation should happen, you can use [data factories](../as-a-data-transfer-object/factories.md) to manually specify the validation strategy.
## A quick glance at the validation functionality
@@ -87,7 +87,7 @@ The package will generate the following validation rules:
]
```
The package follows an algorithm to infer rules from the data object. You can read more about it [here](/docs/laravel-data/v4/validation/auto-rule-inferring).
The package follows an algorithm to infer rules from the data object. You can read more about it [here](../validation/auto-rule-inferring.md).
### Validation attributes
@@ -107,7 +107,7 @@ class SongData extends Data
When you provide an artist with a length of more than 20 characters, the validation will fail.
There's a complete [chapter](/docs/laravel-data/v4/validation/using-validation-attributes) dedicated to validation attributes.
There's a complete [chapter](../validation/using-validation-attributes.md) dedicated to validation attributes.
### Manual rules
@@ -132,7 +132,7 @@ class SongData extends Data
}
```
You can read more about manual rules in its [dedicated chapter](/docs/laravel-data/v4/validation/manual-rules).
You can read more about manual rules in its [dedicated chapter](../validation/manual-rules.md).
### Using the container
@@ -147,7 +147,7 @@ If the request contains data that is not compatible with the data object, a vali
### Working with the validator
We provide a few points where you can hook into the validation process. You can read more about it in the [dedicated chapter](/docs/laravel-data/v4/validation/working-with-the-validator).
We provide a few points where you can hook into the validation process. You can read more about it in the [dedicated chapter](../validation/working-with-the-validator.md).
It is for example to:
@@ -207,7 +207,7 @@ The validation rules for this class will be:
]
```
There are a few quirky things to keep in mind when working with nested data objects, you can read all about it [here](/docs/laravel-data/v4/validation/nesting-data).
There are a few quirky things to keep in mind when working with nested data objects, you can read all about it [here](../validation/nesting-data.md).
## Validation of nested data collections
@@ -241,7 +241,7 @@ In this case the validation rules for `AlbumData` would look like this:
]
```
More info about nested data collections can be found [here](/docs/laravel-data/v4/validation/nesting-data).
More info about nested data collections can be found [here](../validation/nesting-data.md).
## Default values

View File

@@ -5,7 +5,7 @@ weight: 6
A data object can contain other data objects or collections of data objects. The package will make sure that also for these data objects validation rules will be generated.
Let's take a look again at the data object from the [nesting](/docs/laravel-data/v4/as-a-data-transfer-object/nesting) section:
Let's take a look again at the data object from the [nesting](../as-a-data-transfer-object/nesting.md) section:
```php
class AlbumData extends Data

View File

@@ -63,4 +63,4 @@ Now the validation rules will look like this:
## Skipping validation for all properties
By using [data factories](/docs/laravel-data/v4/as-a-data-transfer-object/factories) or setting the `validation_strategy` in the `data.php` config you can skip validation for all properties of a data class.
By using [data factories](../as-a-data-transfer-object/factories.md) or setting the `validation_strategy` in the `data.php` config you can skip validation for all properties of a data class.

View File

@@ -31,7 +31,7 @@ above data object will look like this:
```
For each Laravel validation rule we've got a matching validation attribute, you can find a list of
them [here](/docs/laravel-data/v4/advanced-usage/validation-attributes).
them [here](../advanced-usage/validation-attributes.md).
## Referencing route parameters

View File

@@ -1,49 +1,56 @@
{
"name": "apoloz/alfa-bank-sdk",
"description": "Unofficial Alfa Bank API SDK for PHP using Saloon and Laravel Data",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "apoloz",
"email": "anatoliy.poloz@gmail.com"
}
],
"require": {
"php": "^8.2",
"saloonphp/saloon": "^3.0",
"saloonphp/laravel-plugin": "^3.0",
"saloonphp/pagination-plugin": "^2.0",
"spatie/laravel-data": "^4.0",
"guzzlehttp/guzzle": "^7.0",
"phpseclib/phpseclib": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"pestphp/pest": "^2.0",
"phpstan/phpstan": "^2.1"
},
"autoload": {
"psr-4": {
"Apoloz\\AlfaBank\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Apoloz\\AlfaBank\\Laravel\\AlfaBankServiceProvider"
]
}
},
"minimum-stability": "stable",
"prefer-stable": true,
"scripts": {
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage"
},
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true
}
"name": "apoloz/alfa-bank-sdk",
"description": "Unofficial Alfa Bank API SDK for PHP using Saloon and Laravel Data",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "apoloz",
"email": "anatoliy.poloz@gmail.com"
}
],
"require": {
"php": "^8.4",
"saloonphp/saloon": "^4.0",
"saloonphp/laravel-plugin": "^4.0",
"saloonphp/pagination-plugin": "^2.0",
"spatie/laravel-data": "^4.0",
"guzzlehttp/guzzle": "^7.0",
"phpseclib/phpseclib": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"pestphp/pest": "^2.0",
"phpstan/phpstan": "^2.1"
},
"autoload": {
"psr-4": {
"Apoloz\\AlfaBank\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Apoloz\\AlfaBank\\Laravel\\AlfaBankServiceProvider"
]
}
},
"minimum-stability": "stable",
"prefer-stable": true,
"scripts": {
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage"
},
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true
},
"audit": {
"ignore": {
"PKSA-xnj5-w74d-6wmz": "true",
"PKSA-rnpm-45mg-w6ht": "true",
"PKSA-5szq-gvrg-ttfq": "true"
}
}
}
}

View File

@@ -18,45 +18,49 @@ $baas = AlfaBank::baas(
try {
echo "Authenticating...\n";
// AUTHENTICATION:
// client_id: From Developer Portal (App Settings)
// client_secret: From Developer Portal (App Settings -> Key Icon) OR generated via SDK (examples/14_generate_client_secret.php)
// METHOD A: Standard Client Credentials (for simple services)
// $baas->login(
// clientId: 'your-client-id-uuid',
// clientSecret: 'your-client-secret-string'
// );
// METHOD B: Authorization Code Flow (H2H) (REQUIRED for Nominal Accounts)
// See examples/13_h2h_auth_service.php for the full setup
$auth = \Apoloz\AlfaBank\AlfaBank::auth(
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
redirectUri: 'https://...',
// We re-initialize with auth credentials if we didn't pass them initially
$baas = AlfaBank::baas(
certificatePath: __DIR__ . '/certs/client.cer',
privateKeyPath: __DIR__ . '/certs/private.key',
environment: Environment::SANDBOX
environment: Environment::SANDBOX,
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
redirectUri: 'https://...'
);
// Assuming you have a saved refresh token:
// $auth->refreshToken('saved_refresh_token');
echo "Authentication Successful!\n";
// Now you can use OAuth methods:
// $url = $baas->getAuthorizationUrl();
// or
// $baas->refreshAccessToken('saved_refresh_token');
echo "Authentication Configured!\n";
// 2. Create a Beneficiary (Counterparty)
echo "Creating Beneficiary...\n";
// In a real app, use the DTOs
// $payload = new CreateBeneficiaryRequestData(...);
// $baas->send(new CreateBeneficiaryRequest($payload));
echo "Beneficiary Request Sent (Mock).\n";
} catch (\Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
echo 'Error: ' . $e->getMessage() . "\n";
if ($e instanceof \Apoloz\AlfaBank\Exceptions\AlfaBankException) {
echo "API Code: " . $e->getErrorCode() . "\n";
echo 'API Code: ' . $e->getErrorCode() . "\n";
}
}

View File

@@ -4,8 +4,8 @@ require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
// 1. Initialize SBP
$sbp = AlfaBank::sbp(
@@ -30,8 +30,8 @@ try {
if ($response->successful()) {
$qrData = $response->dto();
echo "QR Payload: " . $qrData->payload . "\n";
echo "QR Image URL: " . $qrData->image . "\n";
echo 'QR Payload: ' . $qrData->payload . "\n";
echo 'QR Image URL: ' . $qrData->image . "\n";
} else {
echo "Failed to generate QR.\n";
}
@@ -41,5 +41,5 @@ try {
// foreach($paginator as $item) { ... }
} catch (\Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
echo 'Error: ' . $e->getMessage() . "\n";
}

View File

@@ -7,44 +7,43 @@ use Apoloz\AlfaBank\Enums\Environment;
/**
* This example shows how to initialize the SDK with the Sandbox files provided by the bank.
*
*
* IMPORTANT: You must first convert the .pfx file to .pem format using OpenSSL:
*
* 1. Extract signing key:
*
* 1. Extract signing key:
* openssl pkcs12 -in certificate_for_requests_sign_with_password_1234.pfx -nocerts -out signing_key.pem -nodes -password pass:1234
*
*
* 2. Extract signing certificate:
* openssl pkcs12 -in certificate_for_requests_sign_with_password_1234.pfx -clcerts -nokeys -out signing_cert.pem -password pass:1234
*
*
* 3. Ensure transport certs are in PEM format if they aren't already.
*/
// --- 1. BaaS / Main API Initialization ---
$baas = AlfaBank::baas(
// Transport (mTLS) - use the sandbox_cert/key files
certificatePath: __DIR__ . '/certs/sandbox_cert_2026.cer',
certificatePath: __DIR__ . '/certs/sandbox_cert_2026.cer',
privateKeyPath: __DIR__ . '/certs/sandbox_key_2026.key',
// Signing (Business Logic) - use the extracted PEM files from PFX
signingCertificatePath: __DIR__ . '/certs/signing_cert.pem',
signingPrivateKeyPath: __DIR__ . '/certs/signing_key.pem',
environment: Environment::SANDBOX,
caBundlePath: __DIR__ . '/certs/apica_2022_chain.cer' // Trust chain
);
echo "BaaS Connector Initialized.\n";
// --- 2. SBP (Faster Payments) Initialization ---
$sbp = AlfaBank::sbp(
// SBP usually uses its own mTLS pair found in the sbp_payout/mtls folder
certificatePath: __DIR__ . '/certs/sbp_payout/mtls/9728109955_test_mtls.crt',
privateKeyPath: __DIR__ . '/certs/sbp_payout/mtls/9728109955_test_mtls.key',
// Terminal ID from terminal_num.txt
keyNameAlias: '9728109955',
keyNameAlias: '9728109955',
environment: Environment::SANDBOX,
caBundlePath: __DIR__ . '/certs/sbp_payout/sandbox_root/root-ca-test.crt'
);
@@ -52,4 +51,3 @@ $sbp = AlfaBank::sbp(
echo "SBP Connector Initialized.\n";
// Now you can use $baas->login(...) or $sbp->send(...)

View File

@@ -3,10 +3,10 @@
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\CreateBeneficiaryRequest;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
use Spatie\LaravelData\DataCollection;
// 1. Initialize
@@ -29,7 +29,7 @@ $payload = new CreateBeneficiaryRequestData(
countryOfTaxResidence: 'RU',
name: 'Ivanov Ivan',
addresses: new DataCollection(AddressData::class, [
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU')
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU'),
])
// Note: digestSignatures is now optional!
);
@@ -40,12 +40,12 @@ $payload->sign($baas->getSigner());
// 5. Send
$response = $baas->send(new CreateBeneficiaryRequest($payload));
echo "Status: " . $response->status() . "\n";
echo "ID: " . $response->dto()->id . "\n";
echo 'Status: ' . $response->status() . "\n";
echo 'ID: ' . $response->dto()->id . "\n";
if ($response->successful()) {
$data = $response->dto(); // BeneficiaryResponseData
echo "Beneficiary creation accepted. ID: {$data->id}, Status: {$data->status}\n";
} else {
echo "Error: " . $response->body() . "\n";
echo 'Error: ' . $response->body() . "\n";
}

View File

@@ -3,10 +3,10 @@
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Webhooks\WebhookFactory;
use Apoloz\AlfaBank\Requests\Webhooks\GetWebhooksRequest;
use Apoloz\AlfaBank\Requests\Webhooks\CreateWebhookRequest;
use Apoloz\AlfaBank\Data\Webhooks\Subscriptions\WebhookSubscriptionRequestData;
use Apoloz\AlfaBank\Requests\Webhooks\CreateWebhookRequest;
use Apoloz\AlfaBank\Requests\Webhooks\GetWebhooksRequest;
use Apoloz\AlfaBank\Webhooks\WebhookFactory;
/**
* 1. Managing Webhooks (BaaS API)
@@ -15,7 +15,7 @@ $baas = AlfaBank::baas('cert.pem', 'key.pem');
$baas->login('id', 'secret');
// List existing webhooks
$response = $baas->send(new GetWebhooksRequest());
$response = $baas->send(new GetWebhooksRequest);
$webhooks = $response->dto(); // DataCollection of WebhookSubscriptionData
foreach ($webhooks as $webhook) {
@@ -38,9 +38,9 @@ $rawPayload = [
'transactionId' => 'TX-12345',
'amount' => ['amount' => 100.50, 'currencyName' => 'RUR'],
'direction' => 'CREDIT',
'paymentPurpose' => 'Test payment'
]
]
'paymentPurpose' => 'Test payment',
],
],
];
// Use the factory to parse the payload into a DTO

View File

@@ -3,16 +3,15 @@
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Requests\B2C\CreateB2CPaymentRequest;
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRequestData;
use Apoloz\AlfaBank\Data\B2C\B2CClientData;
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRecipientData;
use Apoloz\AlfaBank\Data\B2C\B2CPaymentRequestData;
use Apoloz\AlfaBank\Requests\B2C\CreateB2CPaymentRequest;
use Spatie\LaravelData\DataCollection;
/**
* Example: B2C Payout via SBP (Phone Number).
*/
$baas = AlfaBank::baas(
certificatePath: 'path/to/cert.pem',
privateKeyPath: 'path/to/key.pem'
@@ -29,8 +28,8 @@ $payload = new B2CPaymentRequestData(
'phone' => '79001112233',
'amount' => 100.00,
'nspkBankId' => '100000000001',
'sequence' => 'unique-payout-id-1'
]
'sequence' => 'unique-payout-id-1',
],
], DataCollection::class)
);
@@ -41,6 +40,5 @@ if ($response->successful()) {
$data = $response->dto(); // B2CPaymentResponseData
echo "Payout request sent. Status: {$data->status}\n";
} else {
echo "Error: " . $response->body() . "\n";
echo 'Error: ' . $response->body() . "\n";
}

View File

@@ -3,18 +3,17 @@
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Apoloz\AlfaBank\Requests\Registries\CreateRegistryRequest;
use Apoloz\AlfaBank\Data\Registries\RegistryRequestData;
use Apoloz\AlfaBank\Data\Registries\RegistryPaymentData;
use Apoloz\AlfaBank\Requests\Registries\SignRegistryRequest;
use Apoloz\AlfaBank\Data\Registries\RegistryRequestData;
use Apoloz\AlfaBank\Data\Registries\RegistrySignatureData;
use Apoloz\AlfaBank\Requests\Registries\CreateRegistryRequest;
use Apoloz\AlfaBank\Requests\Registries\SignRegistryRequest;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Spatie\LaravelData\DataCollection;
/**
* Example: Creating and Signing a Payment Registry (Batch Payments).
*/
$baas = AlfaBank::baas(
certificatePath: 'path/to/cert.pem',
privateKeyPath: 'path/to/key.pem'
@@ -31,8 +30,8 @@ $payload = new RegistryRequestData(
'payeeInn' => '770...',
'payeeName' => 'Vendor 1',
'payerAccount' => '40702...',
'purpose' => 'Payment for goods'
]
'purpose' => 'Payment for goods',
],
], DataCollection::class)
);
@@ -43,7 +42,7 @@ $registryId = $response->dto()->id;
echo "Registry Created: $registryId\n";
// 2. Sign Registry
// In real life, you might need to sign the digest provided by the bank
// In real life, you might need to sign the digest provided by the bank
// or the registry content itself. This depends on the specific bank requirement.
$signature = CmsSigner::sign(
$registryId, // Example data
@@ -55,11 +54,10 @@ $signatures = RegistrySignatureData::collect([
[
'base64Encoded' => $signature,
'signatureType' => 'RSA',
'certificateUuid' => 'YOUR_CERT_UUID'
]
'certificateUuid' => 'YOUR_CERT_UUID',
],
], DataCollection::class);
$baas->send(new SignRegistryRequest($registryId, $signatures));
echo "Registry Signed.\n";

View File

@@ -14,7 +14,6 @@ use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\RecipientData;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\CreateBeneficiaryRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Payouts\CreatePayoffRequest;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Spatie\LaravelData\DataCollection;
/**
@@ -23,7 +22,7 @@ use Spatie\LaravelData\DataCollection;
*/
// 1. Инициализация SDK
// Сертификаты (Transport Certs):
// Сертификаты (Transport Certs):
// Получены от банка (Sandbox) или сгенерированы вами и активированы банком (Production).
$baas = AlfaBank::baas(
certificatePath: 'transport.crt',
@@ -50,27 +49,26 @@ try {
countryOfTaxResidence: 'RU',
name: 'Иванов Иван',
addresses: AddressData::collect([
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU')
new AddressData('REGISTRATION_ADDRESS', 'Moscow', 'RU'),
])
);
// Автоматическая подпись
$benData->sign($baas->getSigner());
$response = $baas->send(new CreateBeneficiaryRequest($benData));
$beneficiaryId = $response->dto()->id;
echo "Beneficiary Created: $beneficiaryId\n";
// --- ЭТАП 2: Идентификация Входящего Платежа ---
// После создания банк должен проверить бенефициара
echo "2. Запуск верификации (скоринга)...";
echo '2. Запуск верификации (скоринга)...';
$baas->send(new ScoreBeneficiaryRequest($beneficiaryId));
echo "Скоринг инициирован.\n";
// --- ЭТАП 3: Выплата (Payoff) ---
// Когда бенефициар проверен, можно делать выплату
echo "3. Создание выплаты...";
echo '3. Создание выплаты...';
$payoffData = new PayoffRequestData(
type: 'PAYMENT_ORDER',
@@ -89,14 +87,14 @@ try {
digestSignatures: DigestSignatureData::collect([
[
'base64Encoded' => '...', // Здесь должна быть подпись тела выплаты
'signatureType' => 'cms'
]
'signatureType' => 'cms',
],
], DataCollection::class)
);
$payoffResponse = $baas->send(new CreatePayoffRequest($payoffData));
echo "Выплата создана. ID: " . $payoffResponse->dto()->payoffId . "\n";
echo 'Выплата создана. ID: ' . $payoffResponse->dto()->payoffId . "\n";
} catch (\Exception $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
echo 'Ошибка: ' . $e->getMessage() . "\n";
}

View File

@@ -5,15 +5,14 @@ declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Data\SelfEmployed\CreateIncomeRequestData;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Requests\SelfEmployed\RegisterIncomeRequest;
use Apoloz\AlfaBank\Data\SelfEmployed\CreateIncomeRequestData;
/**
* Пример регистрации дохода самозанятого.
* Позволяет автоматически задекларировать доход в ФНС от лица самозанятого.
*/
$baas = AlfaBank::baas(
certificatePath: __DIR__ . '/../tests/test_cert.pem',
privateKeyPath: __DIR__ . '/../tests/test_key.pem',
@@ -37,6 +36,5 @@ try {
echo "ID запроса: {$dto->requestId}\n";
echo "Текущий статус: {$dto->status}\n";
} catch (\Exception $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
echo 'Ошибка: ' . $e->getMessage() . "\n";
}

View File

@@ -12,7 +12,6 @@ use Apoloz\AlfaBank\Sbp\Requests\Reversal\GetQrcReversalHistoryRequest;
* Пример получения истории возвратов по транзакции СБП.
* Полезно для отладки частичных возвратов или поиска зависших операций.
*/
$sbp = AlfaBank::sbp(
certificatePath: __DIR__ . '/../tests/test_cert.pem',
privateKeyPath: __DIR__ . '/../tests/test_key.pem',
@@ -27,7 +26,7 @@ try {
$response = $sbp->send(new GetQrcReversalHistoryRequest($payrrn, $termNo));
$dto = $response->dto();
echo "Найдено возвратов: " . ($dto->refunds ? $dto->refunds->count() : 0) . "\n";
echo 'Найдено возвратов: ' . ($dto->refunds ? $dto->refunds->count() : 0) . "\n";
if ($dto->refunds) {
foreach ($dto->refunds as $refund) {
@@ -38,6 +37,5 @@ try {
}
}
} catch (\Exception $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
echo 'Ошибка: ' . $e->getMessage() . "\n";
}

View File

@@ -13,7 +13,6 @@ use Apoloz\AlfaBank\Requests\Files\UploadFileRequest;
* Сначала создается бенефициар, банк возвращает ссылку для загрузки паспорта.
* Затем SDK загружает файл по этой ссылке.
*/
$baas = AlfaBank::baas(
certificatePath: __DIR__ . '/../tests/test_cert.pem',
privateKeyPath: __DIR__ . '/../tests/test_key.pem',
@@ -34,13 +33,12 @@ try {
if ($response->status() === 200) {
echo "Файл успешно загружен в банк!\n";
} else {
echo "Ошибка загрузки: " . $response->body() . "\n";
echo 'Ошибка загрузки: ' . $response->body() . "\n";
}
} catch (\Exception $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
echo 'Ошибка: ' . $e->getMessage() . "\n";
} finally {
if (is_resource($fileResource)) {
fclose($fileResource);
}
}

View File

@@ -10,7 +10,7 @@ use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesReque
/**
* Authorization Code Flow (H2H) Example
*
*
* Сценарий: Обмен полученного в браузере кода на токены и дальнейшая работа через refresh_token.
*/
@@ -21,20 +21,20 @@ $config = [
// Sandbox: Bank sent you these via email/portal.
'cert' => __DIR__ . '/certs/client.cer',
'key' => __DIR__ . '/certs/private.key',
// APP CREDENTIALS (OAUTH2):
// From: Developer Portal -> Your App -> Settings/Keys
// Note: If you don't have client_secret, generate it using `14_generate_client_secret.php`
'client_id' => getenv('ALFA_BAAS_CLIENT_ID'),
'client_secret' => getenv('ALFA_BAAS_CLIENT_SECRET'),
// REDIRECT URI:
// Must match exactly what you entered in Developer Portal for this App.
'redirect_uri' => 'https://your-app.com/callback',
'redirect_uri' => 'https://your-app.com/callback',
// BUSINESS DATA:
// From your Contract or Internet Bank. Not related to Auth directly.
'account_number' => '40702810...'
'account_number' => '40702810...',
];
// 2. Инициализация коннектора
@@ -48,46 +48,45 @@ $baas = AlfaBank::baas(
try {
// --- СЦЕНАРИЙ А: Первый вход (у нас есть только код из браузера) ---
// Ссылка для получения кода: https://baas.alfabank.ru/oidc/authorize?response_type=code&client_id=...
$authCode = 'code_from_browser_url'; // <-- Вставьте сюда код
if ($authCode) {
echo "Обмениваем код на токены...\n";
$tokenData = $baas->authWithCode($authCode, $config['redirect_uri']);
echo "Access Token получен!\n";
echo "Refresh Token: " . $tokenData->refresh_token . "\n";
echo 'Refresh Token: ' . $tokenData->refresh_token . "\n";
echo "(Сохраните refresh_token в базу данных)\n\n";
}
// --- СЦЕНАРИЙ Б: Повторный вход (у нас есть сохраненный refresh_token) ---
$savedRefreshToken = 'your_saved_refresh_token_from_db';
if ($savedRefreshToken) {
echo "Обновляем сессию по Refresh Token...\n";
$tokenData = $baas->refreshToken($savedRefreshToken);
echo "Сессия обновлена. Новый Access Token действует " . $tokenData->expires_in . " сек.\n";
echo 'Сессия обновлена. Новый Access Token действует ' . $tokenData->expires_in . " сек.\n";
if ($tokenData->refresh_token) {
echo "Пришел новый Refresh Token (сохраните его): " . $tokenData->refresh_token . "\n";
echo 'Пришел новый Refresh Token (сохраните его): ' . $tokenData->refresh_token . "\n";
}
}
// 3. Выполняем защищенный запрос (например, список бенефициаров)
// Коннектор уже авторизован (внутри updateAccessToken/authWithCode вызывается authenticate())
echo "Запрашиваем список...\n";
$response = $baas->send(new GetBeneficiariesRequest(
accountNumber: $config['account_number'],
type: 'FL_RESIDENT'
));
echo "Успешно! Найдено: " . count($response->dto()->beneficiaries) . "\n";
echo 'Успешно! Найдено: ' . count($response->dto()->beneficiaries) . "\n";
} catch (\Exception $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
echo 'Ошибка: ' . $e->getMessage() . "\n";
if (method_exists($e, 'getResponse')) {
echo "Body: " . $e->getResponse()->body() . "\n";
echo 'Body: ' . $e->getResponse()->body() . "\n";
}
}

View File

@@ -34,7 +34,6 @@ $baas = AlfaBank::baas(
$link = $baas->getAuthorizationUrl(scopes: ['beneficiaries', 'payment']);
echo "1. Перейдите по ссылке для авторизации:\n$link\n\n";
// --- СЦЕНАРИЙ 2: Обмен кода на токен (в callback-скрипте) ---
// $code приходит в GET-параметре: /callback?code=...
$codeFromUrl = '...код из браузера...';
@@ -42,18 +41,18 @@ $codeFromUrl = '...код из браузера...';
if ($codeFromUrl !== '...код из браузера...') {
try {
echo "2. Обмен кода на токены...\n";
// Saloon делает всё сам:
$authenticator = $baas->getAccessToken($codeFromUrl);
echo "Access Token: " . substr($authenticator->getAccessToken(), 0, 20) . "...\n";
echo "Refresh Token: " . $authenticator->getRefreshToken() . "\n";
echo "Expires At: " . $authenticator->getExpiresAt()->format('Y-m-d H:i:s') . "\n";
echo 'Access Token: ' . substr($authenticator->getAccessToken(), 0, 20) . "...\n";
echo 'Refresh Token: ' . $authenticator->getRefreshToken() . "\n";
echo 'Expires At: ' . $authenticator->getExpiresAt()->format('Y-m-d H:i:s') . "\n";
// TODO: Сохраните refresh_token в базу данных!
} catch (\Exception $e) {
echo "Ошибка обмена кода: " . $e->getMessage() . "\n";
echo 'Ошибка обмена кода: ' . $e->getMessage() . "\n";
}
}
@@ -63,22 +62,21 @@ $savedRefreshToken = '...saved_refresh_token...';
if ($savedRefreshToken !== '...saved_refresh_token...') {
try {
echo "3. Обновление токена...\n";
// Обновляем токен
$newAuthenticator = $baas->refreshAccessToken($savedRefreshToken);
// Автоматически применяем к коннектору (для текущего скрипта)
$baas->authenticate($newAuthenticator);
echo "Токен обновлен!\n";
// Если пришел новый refresh_token — обновляем его
if ($newAuthenticator->getRefreshToken()) {
// DB::update(...)
echo "Новый Refresh Token получен.\n";
// DB::update(...)
echo "Новый Refresh Token получен.\n";
}
} catch (\Exception $e) {
echo "Ошибка обновления токена: " . $e->getMessage() . "\n";
echo 'Ошибка обновления токена: ' . $e->getMessage() . "\n";
}
}

View File

@@ -5,14 +5,14 @@ declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Requests\Auth\RefreshClientSecretRequest;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Requests\Auth\RefreshClientSecretRequest;
/**
* UTILITY SCRIPT: Generate a Client Secret using your TLS certificates.
*
*
* Run this ONCE when setting up the project or if you lose your secret.
*
*
* Requirements:
* 1. You have the `client_id` (Found in Developer Portal -> App Settings URL or Overview).
* 2. You have the TLS certificates (.pem/.key) authorized by the bank.
@@ -22,7 +22,7 @@ use Apoloz\AlfaBank\Enums\Environment;
// 1. Configuration
$certPath = __DIR__ . '/certs/transport.crt'; // Your mTLS certificate
$keyPath = __DIR__ . '/certs/transport.key'; // Your mTLS private key
$keyPath = __DIR__ . '/certs/transport.key'; // Your mTLS private key
$clientId = 'YOUR_CLIENT_ID_UUID'; // E.g. '0cee0683-85ae-...'
// 2. Initialize Connector (No Login required yet)
@@ -41,20 +41,20 @@ try {
// 4. Output Result
$data = $response->dto(); // Returns ClientSecretData
echo "\n-------------------------------------------------------\n";
echo "SUCCESS! New Client Secret Generated:\n";
echo "-------------------------------------------------------\n";
echo "Client ID: " . $data->clientId . "\n";
echo "Client Secret: " . $data->clientSecret . "\n";
echo 'Client ID: ' . $data->clientId . "\n";
echo 'Client Secret: ' . $data->clientSecret . "\n";
echo "-------------------------------------------------------\n";
echo "IMPORTANT: Save this to your .env file immediately.\n";
echo "It will not be shown again.\n";
} catch (\Exception $e) {
echo "\nERROR: Could not generate secret.\n";
echo "Message: " . $e->getMessage() . "\n";
echo 'Message: ' . $e->getMessage() . "\n";
if (method_exists($e, 'getResponse')) {
echo "Response: " . $e->getResponse()->body() . "\n";
echo 'Response: ' . $e->getResponse()->body() . "\n";
}
}

View File

@@ -10,11 +10,11 @@ use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesReque
/**
* FINAL GOAL EXAMPLE: Get List of Nominal Account Beneficiaries
*
*
* Usage:
* 1. Standalone: php examples/15_nominal_accounts_list.php
* 2. Laravel Tinker: Copy-paste the code below (replace config with app() helper).
*
*
* This script assumes you have already:
* 1. Generated/Received Certificates.
* 2. Obtained Client ID & Secret (via Portal or Script 14).
@@ -23,15 +23,15 @@ use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesReque
// --- CONFIGURATION (From .env) ---
$config = [
'client_id' => getenv('ALFA_BAAS_CLIENT_ID'),
'client_id' => getenv('ALFA_BAAS_CLIENT_ID'),
'client_secret' => getenv('ALFA_BAAS_CLIENT_SECRET'),
'redirect_uri' => 'https://your-app.com/callback',
'cert_path' => __DIR__ . '/certs/client.cer',
'key_path' => __DIR__ . '/certs/private.key',
'redirect_uri' => 'https://your-app.com/callback',
'cert_path' => __DIR__ . '/certs/client.cer',
'key_path' => __DIR__ . '/certs/private.key',
// BUSINESS DATA
'account_num' => '40702810...', // Nominal Account Number
'refresh_token' => 'saved_refresh_token_db' // Your stored token
'account_num' => '40702810...', // Nominal Account Number
'refresh_token' => 'saved_refresh_token_db', // Your stored token
];
try {
@@ -48,7 +48,7 @@ try {
// 2. Refresh Token (Get valid Access Token for this session)
echo "Refreshing session...\n";
$authenticator = $baas->refreshAccessToken($config['refresh_token']);
// Apply authentication to the connector
$baas->authenticate($authenticator);
@@ -60,15 +60,15 @@ try {
);
$response = $baas->send($request);
// 4. Handle Result
$list = $response->dto();
echo "Found " . count($list->beneficiaries) . " beneficiaries.\n";
echo 'Found ' . count($list->beneficiaries) . " beneficiaries.\n";
foreach ($list->beneficiaries as $b) {
echo "- {$b->name} (ID: {$b->beneficiaryId})\n";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
echo 'Error: ' . $e->getMessage() . "\n";
}

View File

@@ -5,18 +5,18 @@ declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Requests\Auth\RefreshClientSecretRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\GetBeneficiariesRequest;
use Apoloz\AlfaBank\Enums\Environment;
/**
* FULLY AUTOMATED WORKFLOW
*
* Scenario: You don't want to store `client_secret` persistently.
*
* Scenario: You don't want to store `client_secret` persistently.
* Instead, you use your Certificates to fetch a fresh secret on startup (or when needed),
* and then immediately use it to refresh your OAuth tokens.
*
* CAUTION: Requesting a new secret invalidates the old one.
*
* CAUTION: Requesting a new secret invalidates the old one.
* If you have multiple app instances, implement a shared cache (Redis/DB) for the secret!
*/
@@ -25,8 +25,8 @@ use Apoloz\AlfaBank\Enums\Environment;
$clientId = getenv('ALFA_BAAS_CLIENT_ID');
$redirectUri = 'https://your-app.com/callback';
$certPath = __DIR__ . '/certs/client.cer';
$keyPath = __DIR__ . '/certs/private.key';
$accNum = '40702810...';
$keyPath = __DIR__ . '/certs/private.key';
$accNum = '40702810...';
// This assumes you have already passed the browser flow once and saved the refresh token.
$savedRefreshToken = 'your_saved_refresh_token_from_db';
@@ -38,20 +38,20 @@ try {
// 2. FETCH CLIENT SECRET DYNAMICALLY
// We prove our identity via mTLS certificates.
echo "1. Requesting dynamic client_secret via API...\n";
// In a real app: CHECK CACHE FIRST!
// $cachedSecret = Cache::get('alfa_client_secret');
// if ($cachedSecret) { $tempSecret = $cachedSecret; } else { ... }
$secretResponse = $baas->send(new RefreshClientSecretRequest($clientId));
$tempSecret = $secretResponse->dto()->clientSecret;
echo " Secret acquired: " . substr($tempSecret, 0, 5) . "...\n";
echo ' Secret acquired: ' . substr($tempSecret, 0, 5) . "...\n";
// 3. AUTHENTICATE OAUTH2
// Now we use the fresh secret to get an access token.
echo "2. Refreshing OAuth2 session...\n";
// Re-initialize connector with the new secret
$baasReady = AlfaBank::baas(
certificatePath: $certPath,
@@ -65,9 +65,9 @@ try {
// Refresh token using native method
$authenticator = $baasReady->refreshAccessToken($savedRefreshToken);
$baasReady->authenticate($authenticator);
echo " Session active. Access Token expires at " . $authenticator->getExpiresAt()->format('H:i:s') . "\n";
echo ' Session active. Access Token expires at ' . $authenticator->getExpiresAt()->format('H:i:s') . "\n";
// Update DB if refresh token rotated
if ($authenticator->getRefreshToken()) {
// saveNewRefreshToken($authenticator->getRefreshToken());
@@ -76,14 +76,14 @@ try {
// 4. BUSINESS LOGIC
echo "3. Fetching beneficiaries...\n";
$response = $baasReady->send(new GetBeneficiariesRequest($accNum, 'FL_RESIDENT'));
echo " Success! Found " . count($response->dto()->beneficiaries) . " records.\n";
echo ' Success! Found ' . count($response->dto()->beneficiaries) . " records.\n";
} catch (Exception $e) {
echo "CRITICAL ERROR: " . $e->getMessage() . "\n";
echo 'CRITICAL ERROR: ' . $e->getMessage() . "\n";
if (method_exists($e, 'getResponse')) {
echo "Body: " . $e->getResponse()->body() . "\n";
echo 'Body: ' . $e->getResponse()->body() . "\n";
}
}

View File

@@ -2,21 +2,21 @@
/**
* LARAVEL TINKER WORKFLOW: Scoring -> Creation -> Signing
*
*
* This script is designed to be copy-pasted directly into `php artisan tinker`.
* It demonstrates the new simplified DX with automatic signing.
*
*
* Prerequisites:
* 1. .env is configured (ALFA_BAAS_CLIENT_ID, ALFA_BAAS_CERT_PATH, etc.)
* 2. Run: php artisan tinker
*/
use Apoloz\AlfaBank\Core\AlfaBankConnector;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequest;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequestData;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\CreateBeneficiaryRequest;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\CreateBeneficiaryRequestData;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\AddressData;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\ScoreBeneficiaryRequest;
// 1. Get Configured Connector
// Laravel automatically injects config from config/alfa-bank.php
@@ -40,17 +40,19 @@ $scoreData = new ScoreBeneficiaryRequestData(
try {
$scoreResponse = $baas->send(new ScoreBeneficiaryRequest($scoreData));
$scoreResult = $scoreResponse->dto(); // ScoreBeneficiaryResponseData
echo "Scoring Result: " . $scoreResult->result . "\n";
echo "Description: " . $scoreResult->description . "\n";
echo 'Scoring Result: ' . $scoreResult->result . "\n";
echo 'Description: ' . $scoreResult->description . "\n";
if ($scoreResult->result !== 'SUCCESS') {
echo "Stopping: Scoring failed.\n";
return;
}
} catch (\Exception $e) {
echo "Scoring Error: " . $e->getMessage() . "\n";
echo 'Scoring Error: ' . $e->getMessage() . "\n";
return;
}
@@ -69,7 +71,7 @@ $createData = new CreateBeneficiaryRequestData(
type: 'REGISTRATION_ADDRESS',
address: '123456, г. Москва, ул. Тверская, д. 1',
country: 'RU'
)
),
])
);
@@ -83,14 +85,13 @@ try {
$beneficiary = $createResponse->dto(); // CreateBeneficiaryResponseData
echo "SUCCESS! Beneficiary Created.\n";
echo "ID: " . $beneficiary->id . "\n";
echo "Status: " . $beneficiary->status . "\n";
echo "Request ID: " . $beneficiary->requestId . "\n";
echo 'ID: ' . $beneficiary->id . "\n";
echo 'Status: ' . $beneficiary->status . "\n";
echo 'Request ID: ' . $beneficiary->requestId . "\n";
} catch (\Exception $e) {
echo "Creation Error: " . $e->getMessage() . "\n";
echo 'Creation Error: ' . $e->getMessage() . "\n";
if (method_exists($e, 'getResponse')) {
echo "Response Body: " . $e->getResponse()->body() . "\n";
echo 'Response Body: ' . $e->getResponse()->body() . "\n";
}
}

View File

@@ -2,30 +2,30 @@
/**
* LARAVEL TINKER WORKFLOW: Secure Card Registration -> Payout by ID
*
* Scenario:
*
* Scenario:
* 1. User enters Card Number (PAN).
* 2. You encrypt PAN and register it as a "Requisite" in Alfa Bank.
* 3. You save only the `requisiteId` in your database.
* 4. Later, you pay out to this user using only the ID (Zero PAN storage).
*
*
* Usage: Copy-paste into `php artisan tinker`.
*/
use Apoloz\AlfaBank\Core\AlfaBankConnector;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequest;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequestData;
use Apoloz\AlfaBank\Requests\NominalAccounts\Payouts\PayoffRequest;
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\PayoffRequestData;
use Apoloz\AlfaBank\Data\Common\RecipientData;
use Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequestData;
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\PayoffRequestData;
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\PayoutRequisiteData;
use Apoloz\AlfaBank\Requests\NominalAccounts\Beneficiaries\Requisites\CreateRequisiteRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Payouts\PayoffRequest;
use Apoloz\AlfaBank\Services\PhpseclibCardEncryptor;
// --- CONFIGURATION ---
$nominalAccount = '40702810...';
$beneficiaryId = 'BEN-123...';
$rawPan = '4276000000001234'; // Вводится пользователем (не сохранять в БД!)
$cardPubKeyPath = storage_path('certs/alfa_card_enc_key.pub');
$beneficiaryId = 'BEN-123...';
$rawPan = '4276000000001234'; // Вводится пользователем (не сохранять в БД!)
$cardPubKeyPath = storage_path('certs/alfa_card_enc_key.pub');
// 1. Setup
$baas = app(AlfaBankConnector::class);
@@ -34,8 +34,8 @@ $baas->login();
// ==========================================
// STEP 1: SECURE REGISTRATION (Tokenization)
// ==========================================
echo "--- Step 1: Registering Card Requisite ---
";
echo '--- Step 1: Registering Card Requisite ---
';
// A. Encrypt PAN for transport
$encryptor = new PhpseclibCardEncryptor(file_get_contents($cardPubKeyPath));
@@ -55,20 +55,20 @@ try {
$reqResponse = $baas->send(new CreateRequisiteRequest($reqData));
$requisiteId = $reqResponse->dto()->id; // E.g. "REQ-998877"
echo "SUCCESS! Card Registered.
";
echo 'SUCCESS! Card Registered.
';
echo "Requisite ID: $requisiteId (SAVE THIS TO DATABASE)
";
echo "Mask: " . substr($rawPan, 0, 6) . "******" . substr($rawPan, -4) . "
";
echo 'Mask: ' . substr($rawPan, 0, 6) . '******' . substr($rawPan, -4) . '
';
} catch (\Exception $e) {
echo "Registration Failed: " . $e->getMessage() . "
";
echo 'Registration Failed: ' . $e->getMessage() . '
';
return;
}
// ==========================================
// STEP 2: PAYOUT (Using Requisite ID)
// ==========================================
@@ -82,11 +82,11 @@ $payoutData = new PayoffRequestData(
recipient: new RecipientData($beneficiaryId),
amount: '100.00',
purpose: 'Выплата вознаграждения',
// Instead of PAN, we provide the Requisite ID
payoutRequisite: new PayoutRequisiteData(
type: 'CARD',
requisiteId: $requisiteId
requisiteId: $requisiteId
)
);
@@ -96,12 +96,12 @@ try {
$payResponse = $baas->send(new PayoffRequest($payoutData));
$result = $payResponse->dto();
echo "Payout Sent!
";
echo "ID: " . ($result->id ?? 'N/A') . "
";
echo 'Payout Sent!
';
echo 'ID: ' . ($result->id ?? 'N/A') . '
';
} catch (\Exception $e) {
echo "Payout Failed: " . $e->getMessage() . "
";
echo 'Payout Failed: ' . $e->getMessage() . '
';
}

View File

@@ -0,0 +1,271 @@
<?php
declare(strict_types=1);
/**
* Пример: SBP QR → Номинальный счёт → Идентификация → Бенефициар
*
* Сценарий:
* 1. Генерируем SBP QR код для пополнения номинального счёта
* 2. Клиент оплачивает через QR (переводит деньги на номинальный счёт)
* 3. Получаем список неидентифицированных пополнений
* 4. Идентифицируем платёж (привязываем к конкретному бенефициару)
* 5. Проверяем статус идентификации
*/
require_once __DIR__ . '/../vendor/autoload.php';
use Apoloz\AlfaBank\AlfaBank;
use Apoloz\AlfaBank\Core\AlfaConfig;
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetIdentifyStatusRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetUnidentifiedTransactionsRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\IdentifyTransactionRequest;
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
use Apoloz\AlfaBank\Sbp\SbpConnector;
use Spatie\LaravelData\DataCollection;
echo "=== SBP QR → Номинальный счёт → Идентификация ===\n\n";
// =============================================================================
// КОНФИГУРАЦИЯ
// =============================================================================
// SBP QR конфигурация (mTLS + подпись)
$sbpMtlsCert = __DIR__ . '/certs/sbp_mtls.crt';
$sbpMtlsKey = __DIR__ . '/certs/sbp_mtls.key';
$sbpSigningKey = __DIR__ . '/certs/sbp_signing.key'; // 4096-bit для подписи
$sbpKeyAlias = 'your-alias-from-bank';
$sbpTermNo = '30003970'; // Номер терминала
$sbpCaBundle = __DIR__ . '/certs/russian_trusted_ca-bundle.crt';
// BaaS конфигурация (для номинальных счетов)
$baasCert = __DIR__ . '/certs/baas_transport.crt';
$baasKey = __DIR__ . '/certs/baas_transport.key';
$baasClientId = getenv('ALFA_BAAS_CLIENT_ID');
$baasClientSecret = getenv('ALFA_BAAS_CLIENT_SECRET');
$baasCaBundle = __DIR__ . '/certs/russian_trusted_ca-bundle.crt';
// Данные для идентификации
$nominalAccountNumber = '40702810XXXXXXXXXXX'; // Ваш номинальный счёт
$beneficiaryId = '3fa85f64-5717-4562-b3fc-2c963f66afa6'; // ID бенефициара
echo "Конфигурация:\n";
echo " Номинальный счёт: $nominalAccountNumber\n";
echo " Бенефициар ID: $beneficiaryId\n\n";
// =============================================================================
// ЭТАП 1: Генерация SBP QR кода для пополнения номинального счёта
// =============================================================================
echo "=== ЭТАП 1: Генерация SBP QR кода ===\n";
try {
// Создаём SBP connector с раздельными ключами (mTLS + signing)
$sbpConfig = new AlfaConfig(
baseUrl: Environment::SBP_SANDBOX->value,
certificatePath: $sbpMtlsCert,
privateKeyPath: $sbpMtlsKey,
caBundlePath: $sbpCaBundle,
signingPrivateKeyPath: $sbpSigningKey // 4096-bit ключ для подписи
);
$sbp = new SbpConnector($sbpConfig, $sbpKeyAlias);
// Создаём динамический QR код с уникальным OrderNumber для идентификации
$orderNumber = 'ORDER-' . uniqid();
$qrPayload = new QrCodeRequestData(
termNo: $sbpTermNo,
qrcType: '02', // Dynamic QR
amount: '50000', // 500.00 RUB
currency: 'RUB',
paymentPurpose: "Пополнение номинального счета {$nominalAccountNumber}",
orderNumber: $orderNumber, // Уникальный номер заказа для отслеживания
messageID: 'sbp-' . uniqid(),
qrTtl: '60', // QR активен 60 минут
notificationUrl: 'https://your-domain.com/webhooks/sbp', // Webhook для уведомлений
width: '300',
height: '300'
);
$request = new GetQrCodeRequest($qrPayload);
$response = $sbp->send($request);
$qrData = $response->dto();
if ($qrData->ErrorCode !== 0) {
throw new \RuntimeException("QR generation failed: {$qrData->message}");
}
echo "✅ QR код сгенерирован!\n";
echo " Order Number: $orderNumber\n";
echo " QRC ID: {$qrData->qrcId}\n";
echo " QR Payload: {$qrData->payload}\n";
echo " Status: {$qrData->status}\n";
echo "\n💡 Клиент должен отсканировать QR и оплатить {$qrData->payload}\n\n";
// Сохраняем QR изображение для показа клиенту
if (! empty($qrData->image)) {
$qrImagePath = __DIR__ . '/qr_payment.png';
file_put_contents($qrImagePath, base64_decode($qrData->image));
echo " 📁 QR изображение сохранено: $qrImagePath\n\n";
}
echo "⏳ Ждём, пока клиент оплатит...\n";
echo " (В тестовой среде используйте Sandbox для эмуляции оплаты)\n\n";
// =============================================================================
// ЭТАП 2: Получение неидентифицированных пополнений
// =============================================================================
echo "=== ЭТАП 2: Поиск неидентифицированных пополнений ===\n";
echo " (После оплаты через SBP деньги поступают на номинальный счёт\n";
echo " как 'неидентифицированное пополнение')\n\n";
// Инициализируем BaaS connector (требуется H2H авторизация)
$baas = AlfaBank::baas(
certificatePath: $baasCert,
privateKeyPath: $baasKey,
environment: Environment::SANDBOX,
clientId: $baasClientId,
clientSecret: $baasClientSecret
);
// Авторизация через Client Credentials Flow
$baas->login($baasClientId, $baasClientSecret, ['beneficiary-payments']);
// Получаем список неидентифицированных пополнений
$unidentifiedRequest = new GetUnidentifiedTransactionsRequest(
accountNumber: $nominalAccountNumber,
limit: 10,
offset: 0
);
$unidentifiedResponse = $baas->send($unidentifiedRequest);
$unidentifiedCollection = $unidentifiedResponse->dto();
echo 'Найдено неидентифицированных пополнений: ' . count($unidentifiedCollection->items) . "\n\n";
if (count($unidentifiedCollection->items) === 0) {
echo "⚠️ Нет неидентифицированных пополнений. Возможные причины:\n";
echo " - Платёж ещё не поступил (нужно время на обработку)\n";
echo " - Неправильный номер номинального счёта\n";
echo " - Платёж уже идентифицирован\n";
exit(0);
}
// Ищем нужную транзакцию (обычно по сумме или назначению платежа)
$targetTransaction = null;
foreach ($unidentifiedCollection->items as $transaction) {
echo " Транзакция ID: {$transaction->id}\n";
echo " Сумма: {$transaction->amount} RUB\n";
echo " Назначение: {$transaction->purpose}\n";
echo " Дата: {$transaction->date}\n";
echo " Плательщик: {$transaction->payer?->name}\n\n";
// В реальном сценарии ищем по сумме, назначению или другим критериям
// Здесь берём первую для примера
if ($targetTransaction === null) {
$targetTransaction = $transaction;
}
}
if ($targetTransaction === null) {
throw new \RuntimeException('Не найдена подходящая транзакция для идентификации');
}
echo "✅ Выбрана транзакция для идентификации: {$targetTransaction->id}\n";
echo " Сумма: {$targetTransaction->amount} RUB\n\n";
// =============================================================================
// ЭТАП 3: Идентификация платежа (привязка к бенефициару)
// =============================================================================
echo "=== ЭТАП 3: Идентификация платежа ===\n";
echo " Привязываем платёж к бенефициару: $beneficiaryId\n\n";
// Подготавливаем распределение суммы
// Можно распределить между несколькими бенефициарами
$amountDistribution = DataCollection::create([
new AmountDistributionData(
beneficiaryId: $beneficiaryId,
amount: $targetTransaction->amount
),
], AmountDistributionData::class);
// Подготавливаем данные для идентификации
$identifyData = new IdentifyRequestData(
transactionId: $targetTransaction->id,
accountNumber: $nominalAccountNumber,
amountDistribution: $amountDistribution,
// Подпись добавляется через sign() метод
digestSignatures: DataCollection::create([
new DigestSignatureData(
base64Encoded: 'base64-encoded-signature-here', // Реальная подпись
signatureType: 'rsa'
),
], DigestSignatureData::class)
);
// Создаём запрос на идентификацию
$identifyRequest = new IdentifyTransactionRequest(
id: $targetTransaction->id,
data: $identifyData
);
$identifyResponse = $baas->send($identifyRequest);
$identifyResult = $identifyResponse->dto();
echo "✅ Запрос на идентификацию создан!\n";
echo " Identify ID: {$identifyResult->identifyId}\n";
echo " Статус: {$identifyResult->status}\n\n";
// =============================================================================
// ЭТАП 4: Проверка статуса идентификации
// =============================================================================
echo "=== ЭТАП 4: Проверка статуса ===\n\n";
$statusRequest = new GetIdentifyStatusRequest($identifyResult->identifyId);
$statusResponse = $baas->send($statusRequest);
$statusResult = $statusResponse->dto();
echo "Статус идентификации: {$statusResult->status}\n";
echo "Возможные статусы:\n";
echo " - PENDING: В обработке\n";
echo " - VALIDATED: Провалидировано\n";
echo " - COMPLETE: Успешно завершено\n";
echo " - FAILED: Ошибка\n\n";
if ($statusResult->status === 'COMPLETE') {
echo "🎉 ИДЕНТИФИКАЦИЯ УСПЕШНО ЗАВЕРШЕНА!\n";
echo " Деньги {$targetTransaction->amount} RUB зачислены бенефициару $beneficiaryId\n\n";
}
// =============================================================================
// РЕЗЮМЕ
// =============================================================================
echo "=== РЕЗЮМЕ ===\n";
echo "✅ 1. Сгенерирован SBP QR код\n";
echo "✅ 2. Клиент оплатил через SBP (эмитация в тесте)\n";
echo "✅ 3. Деньги поступили на номинальный счёт\n";
echo "✅ 4. Платёж идентифицирован и привязан к бенефициару\n";
echo "\n💡 Теперь бенефициар может распоряжаться этими средствами\n";
echo " (например, запросить выплату через CreatePayoffRequest)\n";
} catch (\Apoloz\AlfaBank\Exceptions\AlfaBankException $e) {
echo "\n❌ AlfaBankException: {$e->getMessage()}\n";
if ($e->getResponse()) {
echo "Ответ API: {$e->getResponse()->body()}\n";
}
} catch (\Exception $e) {
echo "\n❌ Ошибка: {$e->getMessage()}\n";
echo "Файл: {$e->getFile()}:{$e->getLine()}\n";
}
echo "\n=== Пример завершён ===\n";

View File

@@ -0,0 +1,179 @@
<?php
declare(strict_types=1);
/**
* Laravel Tinker: SBP QR → Номинальный счёт → Идентификация
*
* Использование:
* docker compose exec php-fpm php artisan tinker
* >>> include 'examples/21_laravel_tinker_sbp_identification.php'
*/
use Apoloz\AlfaBank\Core\AlfaBankConnector;
use Apoloz\AlfaBank\Core\AlfaConfig;
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\AmountDistributionData;
use Apoloz\AlfaBank\Data\NominalAccounts\Identification\IdentifyRequestData;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetIdentifyStatusRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\GetUnidentifiedTransactionsRequest;
use Apoloz\AlfaBank\Requests\NominalAccounts\Identification\IdentifyTransactionRequest;
use Apoloz\AlfaBank\Sbp\Data\QrCodeRequestData;
use Apoloz\AlfaBank\Sbp\Requests\GetQrCodeRequest;
use Apoloz\AlfaBank\Sbp\SbpConnector;
use Spatie\LaravelData\DataCollection;
echo "=== SBP QR → Номинальный счёт → Идентификация (Tinker) ===\n\n";
// =============================================================================
// КОНФИГУРАЦИЯ
// =============================================================================
$nominalAccountNumber = '40702810601880001584'; // Номинальный счёт из sandbox
$beneficiaryId = 'your-beneficiary-id-here'; // ID бенефициара (получить из списка)
$amount = '15000'; // 150.00 RUB в копейках
echo "Номинальный счёт: $nominalAccountNumber\n";
echo 'Сумма: ' . number_format($amount / 100, 2) . " RUB\n\n";
// =============================================================================
// ШАГ 1: Генерация SBP QR
// =============================================================================
echo "=== ШАГ 1: Генерация SBP QR кода ===\n";
try {
// SBP Connector
$sbpConfig = new AlfaConfig(
baseUrl: Environment::SBP_SANDBOX->value,
certificatePath: config('alfa-bank.sbp.certificate_path'),
privateKeyPath: config('alfa-bank.sbp.private_key_path'),
caBundlePath: config('alfa-bank.sbp.ca_bundle'),
signingPrivateKeyPath: config('alfa-bank.sbp.signing_private_key_path')
);
$sbp = new SbpConnector($sbpConfig, config('alfa-bank.sbp.key_name_alias'));
$orderNumber = 'ORDER-' . uniqid();
$qrResponse = $sbp->send(new GetQrCodeRequest(
new QrCodeRequestData(
termNo: config('alfa-bank.sbp.terminal_no'),
qrcType: '02', // Dynamic QR
amount: $amount,
currency: 'RUB',
paymentPurpose: "Пополнение счета $nominalAccountNumber",
orderNumber: $orderNumber,
messageID: 'sbp-' . uniqid(),
qrTtl: '60'
)
));
$qrData = $qrResponse->dto();
if ($qrData->ErrorCode !== 0) {
echo "❌ Ошибка генерации QR: {$qrData->message}\n";
return;
}
echo "✅ QR код сгенерирован!\n";
echo " Order: $orderNumber\n";
echo " QRC ID: {$qrData->qrcId}\n";
echo " Payload: {$qrData->payload}\n\n";
// =============================================================================
// ШАГ 2: Получение неидентифицированных пополнений
// =============================================================================
echo "=== ШАГ 2: Поиск неидентифицированных пополнений ===\n";
echo "(После оплаты клиентом через SBP)\n\n";
$baas = app(AlfaBankConnector::class);
// Получаем список
$unidentifiedResponse = $baas->send(
new GetUnidentifiedTransactionsRequest($nominalAccountNumber, limit: 5)
);
$transactions = $unidentifiedResponse->dto()->items;
echo 'Найдено транзакций: ' . count($transactions) . "\n\n";
if (count($transactions) === 0) {
echo "⚠️ Нет неидентифицированных пополнений\n";
return;
}
// Показываем список
foreach ($transactions as $i => $tx) {
echo " [$i] ID: {$tx->id}\n";
echo " Сумма: {$tx->amount} RUB\n";
echo " Назначение: {$tx->purpose}\n";
echo " Плательщик: {$tx->payer?->name}\n\n";
}
// Берём первую для примера
$transaction = $transactions[0];
echo "✅ Выбрана транзакция: {$transaction->id} ({$transaction->amount} RUB)\n\n";
// =============================================================================
// ШАГ 3: Идентификация (привязка к бенефициару)
// =============================================================================
echo "=== ШАГ 3: Идентификация платежа ===\n";
if (empty($beneficiaryId) || $beneficiaryId === 'your-beneficiary-id-here') {
echo "⚠️ Укажите правильный beneficiaryId!\n";
echo " Получите список бенефициаров через:\n";
echo " >>> \$baas->send(new GetBeneficiariesRequest())->dto()\n";
return;
}
$identifyData = new IdentifyRequestData(
transactionId: $transaction->id,
accountNumber: $nominalAccountNumber,
amountDistribution: DataCollection::create([
new AmountDistributionData(
beneficiaryId: $beneficiaryId,
amount: $transaction->amount
),
], AmountDistributionData::class)
);
$identifyResponse = $baas->send(
new IdentifyTransactionRequest($transaction->id, $identifyData)
);
$result = $identifyResponse->dto();
echo "✅ Запрос создан!\n";
echo " Identify ID: {$result->identifyId}\n";
echo " Статус: {$result->status}\n\n";
// =============================================================================
// ШАГ 4: Проверка статуса
// =============================================================================
echo "=== ШАГ 4: Проверка статуса ===\n";
$statusResponse = $baas->send(
new GetIdentifyStatusRequest($result->identifyId)
);
$status = $statusResponse->dto();
echo "Текущий статус: {$status->status}\n\n";
echo "=== РЕЗУЛЬТАТ ===\n";
echo "✅ SBP QR: {$qrData->payload}\n";
echo "✅ Транзакция: {$transaction->id}\n";
echo "✅ Бенефициар: $beneficiaryId\n";
echo "✅ Сумма: {$transaction->amount} RUB\n";
echo "✅ Статус идентификации: {$status->status}\n";
} catch (\Exception $e) {
echo "\n❌ Ошибка: {$e->getMessage()}\n";
echo 'Класс: ' . get_class($e) . "\n";
}
echo "\n=== Готово ===\n";

View File

@@ -9,9 +9,9 @@ namespace Apoloz\AlfaBank;
use Apoloz\AlfaBank\Core\AlfaBankConnector;
use Apoloz\AlfaBank\Core\AlfaConfig;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Services\OpenSslCmsSigner;
use Apoloz\AlfaBank\Sbp\SbpConnector;
use Apoloz\AlfaBank\Requests\Accounts\GetAccountsRequest;
use Apoloz\AlfaBank\Sbp\SbpConnector;
use Apoloz\AlfaBank\Services\OpenSslCmsSigner;
class AlfaBank
{
@@ -29,7 +29,8 @@ class AlfaBank
): bool {
$baas = self::baas($certificatePath, $privateKeyPath, $environment, $caBundlePath);
$baas->login($clientId, $clientSecret);
$baas->send(new GetAccountsRequest());
$baas->send(new GetAccountsRequest);
return true;
}
@@ -76,8 +77,8 @@ class AlfaBank
?string $signingCertificatePath = null,
?string $signingPrivateKeyPath = null
): SbpConnector {
$baseUrl = $environment === Environment::PRODUCTION
? Environment::SBP_PRODUCTION->value
$baseUrl = $environment === Environment::PRODUCTION
? Environment::SBP_PRODUCTION->value
: Environment::SBP_SANDBOX->value;
$config = new AlfaConfig(
@@ -92,4 +93,4 @@ class AlfaBank
return new SbpConnector($config, $keyNameAlias);
}
// </SECTION>
}
}

View File

@@ -7,29 +7,33 @@ namespace Apoloz\AlfaBank\Core;
// <SECTION name="module_imports" intent="Import necessary contracts, services, and base framework components for the connector's operation.">
// <BELIEF_STATE "Saloon's plugin architecture requires importing traits for features like retries and timeouts. Local contracts (SignerInterface) are imported for dependency injection.">
use Apoloz\AlfaBank\Contracts\SignerInterface;
use Apoloz\AlfaBank\Enums\Environment;
use Apoloz\AlfaBank\Http\Middleware\LoggingRequestMiddleware;
use Apoloz\AlfaBank\Http\Middleware\LoggingResponseMiddleware;
use Apoloz\AlfaBank\Http\Middleware\RequestIdMiddleware;
use Apoloz\AlfaBank\Http\Middleware\VerifyJwsResponseMiddleware;
use Apoloz\AlfaBank\Http\Pagination\AlfaOffsetPaginator;
use Apoloz\AlfaBank\Requests\Auth\GetTokenRequest; // Will be removed
use Apoloz\AlfaBank\Traits\HasAlfaErrorHandling;
use Psr\Log\LoggerInterface;
use Saloon\Helpers\OAuth2\OAuthConfig;
use Saloon\Http\Connector;
use Saloon\Http\OAuth2\GetClientCredentialsTokenRequest;
use Saloon\Http\PendingRequest;
use Saloon\Http\Request;
use Saloon\PaginationPlugin\Contracts\HasPagination;
use Saloon\PaginationPlugin\OffsetPaginator;
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;
use Saloon\Traits\RequestProperties\HasTries;
use Saloon\Traits\Plugins\HasTimeout;
use Saloon\Contracts\OAuth2\OAuth2Api;
use Saloon\Traits\OAuth2\AuthorizationCodeGrant;
use Apoloz\AlfaBank\Enums\Environment;
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;
use Saloon\Traits\Plugins\HasTimeout;
use Saloon\Traits\RequestProperties\HasTries;
class AlfaBankConnector extends Connector implements HasPagination, OAuth2Api
class AlfaBankConnector extends Connector implements HasPagination
{
use AlwaysThrowOnErrors;
use AuthorizationCodeGrant;
use HasAlfaErrorHandling;
use HasTimeout;
use HasTries;
use AlwaysThrowOnErrors;
use HasAlfaErrorHandling;
use AuthorizationCodeGrant;
public function __construct(
protected AlfaConfig $alfaConfig,
@@ -44,51 +48,7 @@ class AlfaBankConnector extends Connector implements HasPagination, OAuth2Api
return $this->alfaConfig->baseUrl;
}
protected function resolveOauth2Config(): OAuthConfig
{
$idUrl = $this->alfaConfig->baseUrl === Environment::PRODUCTION->value
? Environment::ID_PRODUCTION->value
: Environment::ID_SANDBOX->value;
return OAuthConfig::make()
->setClientId($this->alfaConfig->clientId ?? '')
->setClientSecret($this->alfaConfig->clientSecret ?? '')
->setRedirectUri($this->alfaConfig->redirectUri ?? '')
->setAuthorizeEndpoint($idUrl . '/oidc/authorize')
->setTokenEndpoint('/oidc/token');
}
protected function defaultConfig(): array
{
$config = [
'cert' => $this->alfaConfig->certificatePath,
'ssl_key' => $this->alfaConfig->privateKeyPath,
'verify' => true,
];
if ($this->alfaConfig->caBundlePath) {
$config['verify'] = $this->alfaConfig->caBundlePath;
}
return $config;
}
protected function defaultHeaders(): array
{
return [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
];
}
protected function defaultMiddleware(): array
{
return [
new RequestIdMiddleware(),
];
}
public function boot(\Saloon\Http\PendingRequest $pendingRequest): void
public function boot(PendingRequest $pendingRequest): void
{
//
}
@@ -99,7 +59,7 @@ class AlfaBankConnector extends Connector implements HasPagination, OAuth2Api
}
// login() kept for ClientCredentials compatibility (legacy/simple flow)
public function login(?string $clientId = null, ?string $clientSecret = null): static
public function login(?string $clientId = null, ?string $clientSecret = null, array $scopes = []): static
{
$oauthConfig = $this->oauthConfig();
@@ -112,41 +72,42 @@ class AlfaBankConnector extends Connector implements HasPagination, OAuth2Api
}
if (empty($oauthConfig->getClientId()) || empty($oauthConfig->getClientSecret())) {
throw new \RuntimeException("Client ID/Secret not configured.");
throw new \RuntimeException('Client ID/Secret not configured.');
}
$request = new \Saloon\Http\OAuth2\GetClientCredentialsTokenRequest($oauthConfig);
$request = new GetClientCredentialsTokenRequest($oauthConfig, $scopes);
$response = $this->send($request);
// Use the trait's helper to parse the token
$authenticator = $this->createOAuthAuthenticatorFromResponse($response);
$this->authenticate($authenticator);
return $this;
}
// </SECTION>
// </SECTION>
// <SECTION name="signer_accessor" intent="Provide access to the configured signing service for requests that require a digital signature.">
// <BELIEF_STATE "Requests should not instantiate their own signing logic. The connector acts as a service locator, providing the globally-configured Signer service. This ensures that all signatures are generated consistently.">
public function getSigner(): SignerInterface
{
if (!$this->signer) {
throw new \RuntimeException("No signer configured for this connector.");
if (! $this->signer) {
throw new \RuntimeException('No signer configured for this connector.');
}
return $this->signer;
}
// </SECTION>
// <SECTION name="logging_mutator" intent="Allow attaching a PSR-3 logger to the connector for debugging.">
// <BELIEF_STATE "Logging should be an optional, opt-in feature. This method provides a fluent interface to attach a logging middleware, which will automatically sanitize sensitive data before output.">
public function withLogging(\Psr\Log\LoggerInterface $logger): static
public function withLogging(LoggerInterface $logger): static
{
$this->middleware()->onRequest(new \Apoloz\AlfaBank\Http\Middleware\LoggingRequestMiddleware($logger));
$this->middleware()->onResponse(new \Apoloz\AlfaBank\Http\Middleware\LoggingResponseMiddleware($logger));
$this->middleware()->onRequest(new LoggingRequestMiddleware($logger));
$this->middleware()->onResponse(new LoggingResponseMiddleware($logger));
return $this;
}
@@ -155,9 +116,55 @@ class AlfaBankConnector extends Connector implements HasPagination, OAuth2Api
*/
public function withJwsVerification(string $publicKeyPem): static
{
$this->middleware()->onResponse(new \Apoloz\AlfaBank\Http\Middleware\VerifyJwsResponseMiddleware($publicKeyPem));
$this->middleware()->onResponse(new VerifyJwsResponseMiddleware($publicKeyPem));
return $this;
}
protected function defaultOauthConfig(): OAuthConfig
{
$idUrl = $this->alfaConfig->baseUrl === Environment::PRODUCTION->value
? Environment::ID_PRODUCTION->value
: Environment::ID_SANDBOX->value;
return OAuthConfig::make()
->setClientId($this->alfaConfig->clientId ?? '')
->setClientSecret($this->alfaConfig->clientSecret ?? '')
->setRedirectUri($this->alfaConfig->redirectUri ?? '')
->setAuthorizeEndpoint($idUrl.'/oidc/authorize')
->setTokenEndpoint('/oidc/token')
->setAllowBaseUrlOverride();
}
protected function defaultConfig(): array
{
$config = [
'cert' => $this->alfaConfig->certificatePath,
'ssl_key' => $this->alfaConfig->privateKeyPath,
'verify' => true,
];
if ($this->alfaConfig->caBundlePath) {
$config['verify'] = $this->alfaConfig->caBundlePath === 'false' ? false : $this->alfaConfig->caBundlePath;
}
return $config;
}
protected function defaultHeaders(): array
{
return [
'Accept' => 'application/json',
// Content-Type не устанавливаем здесь, каждый Request сам определяет его через трейты (HasJsonBody, HasFormBody и т.д.)
// OAuth токен запросы требуют application/x-www-form-urlencoded
];
}
protected function defaultMiddleware(): array
{
return [
new RequestIdMiddleware,
];
}
// </SECTION>
}
}

View File

@@ -41,17 +41,17 @@ readonly class AlfaConfig
public ?string $signingPrivateKeyPath = null,
) {
// <BELIEF_STATE "This runtime check ensures that the provided certificate and key paths are not just valid strings, but point to actual, accessible files on the filesystem. This prevents configuration errors that would otherwise only surface during an HTTP request.">
if (!file_exists($this->certificatePath)) {
if (! file_exists($this->certificatePath)) {
throw new \InvalidArgumentException("Certificate not found: {$this->certificatePath}");
}
if (!file_exists($this->privateKeyPath)) {
if (! file_exists($this->privateKeyPath)) {
throw new \InvalidArgumentException("Private key not found: {$this->privateKeyPath}");
}
if ($this->signingCertificatePath && !file_exists($this->signingCertificatePath)) {
throw new \InvalidArgumentException("Signing certificate not found: {$this->signingCertificatePath}");
if ($this->signingCertificatePath && ! file_exists($this->signingCertificatePath)) {
throw new \InvalidArgumentException("Signing certificate not found: {$this->signingCertificatePath}");
}
if ($this->signingPrivateKeyPath && !file_exists($this->signingPrivateKeyPath)) {
throw new \InvalidArgumentException("Signing private key not found: {$this->signingPrivateKeyPath}");
if ($this->signingPrivateKeyPath && ! file_exists($this->signingPrivateKeyPath)) {
throw new \InvalidArgumentException("Signing private key not found: {$this->signingPrivateKeyPath}");
}
}
// </SECTION>

View File

@@ -13,6 +13,6 @@ class AccountData extends Data
public string $openDate,
public string $type,
public ?string $mnemonic = null,
public ?array $balance = null,
public ?array $balance = null,
) {}
}

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\Auth;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for OAuth 2.0 token responses.">

View File

@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a collection of client consents.">

View File

@@ -14,9 +14,10 @@ namespace Apoloz\AlfaBank\Data\Auth\UserInfo;
// <SECTION name="module_imports" intent="Import necessary DTOs and Spatie Laravel Data components.">
// <BELIEF_STATE "This DTO represents a single consent entry. The `PaginationData` import here is likely due to prior usage or template, but not directly used within this single DTO.">
use Apoloz\AlfaBank\Data\PaginationData; // This import is likely extraneous for a single DTO, but kept for context consistency.
use Spatie\LaravelData\Attributes\DataCollectionOf; // This is also likely extraneous for a single DTO.
// This is also likely extraneous for a single DTO.
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection; // This is also likely extraneous for a single DTO.
// This is also likely extraneous for a single DTO.
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a single client consent.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\Auth\UserInfo;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for OpenID Connect UserInfo claims.">

View File

@@ -4,9 +4,7 @@ declare(strict_types=1);
namespace Apoloz\AlfaBank\Data\B2C;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
class B2CPaymentResponseData extends Data
{

View File

@@ -14,4 +14,4 @@ class CertificateData extends Data
public string $status,
public ?string $thumbprint = null,
) {}
}
}

View File

@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\FileExchange;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for file download response data.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\FileExchange;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for file link details.">

View File

@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\FileExchange;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for file upload response data.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for address details.">

View File

@@ -16,6 +16,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a beneficiary's balance details.">

View File

@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define the paginated collection for beneficiary transactions.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import the base Spatie\LaravelData class.">
// <BELIEF_STATE "This class extends `Spatie\LaravelData\Data` to leverage its robust data mapping and type safety, ensuring consistent and predictable handling of individual transaction payloads.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define the beneficiary transaction data structure.">

View File

@@ -20,6 +20,7 @@ use Spatie\LaravelData\Attributes\Validation\Email;
use Spatie\LaravelData\Attributes\Validation\Numeric;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for creating a new beneficiary.">
@@ -35,6 +36,7 @@ class CreateBeneficiaryRequestData extends Data
public string $countryOfTaxResidence,
#[DataCollectionOf(AddressData::class)]
public DataCollection $addresses,
public ?bool $isBeneficiary = null,
#[DataCollectionOf(DigestSignatureData::class)]
public ?DataCollection $digestSignatures = null,
public ?string $accountNumber = null,

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for the response of creating a beneficiary.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for an identification document.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for personal identification details.">

View File

@@ -18,6 +18,7 @@ use Apoloz\AlfaBank\Traits\SignableData;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for creating a new requisite.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a single payment requisite.">

View File

@@ -16,9 +16,9 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries\Requisites;
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
use Apoloz\AlfaBank\Traits\SignableData;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Attributes\Validation\Numeric;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for updating an existing requisite.">

View File

@@ -20,6 +20,7 @@ use Spatie\LaravelData\Attributes\Validation\Email;
use Spatie\LaravelData\Attributes\Validation\Numeric;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for updating an existing beneficiary.">
@@ -39,3 +40,23 @@ class UpdateBeneficiaryRequestData extends Data
public ?DataCollection $addresses = null,
public ?string $accountNumber = null,
public ?bool $taxResidentUS = null,
public ?bool $foreignTaxResident = null,
public ?bool $financialActivities = null,
public ?string $name = null,
public ?string $registrationDate = null,
#[Numeric]
public ?string $inn = null,
#[Numeric]
public ?string $kpp = null,
#[Numeric]
public ?string $ogrn = null,
public ?PersonalInformationData $personalInformation = null,
public ?string $phoneNumber = null,
#[Email]
public ?string $email = null,
#[DataCollectionOf(DocumentData::class)]
public ?DataCollection $documents = null,
) {}
// </SECTION>
}
// </SECTION>

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Beneficiaries;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a specific wallet's balance.">

View File

@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a collection of beneficiaries.">

View File

@@ -16,7 +16,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts;
use Apoloz\AlfaBank\Data\PaginationData; // This import might be misleading for a single DTO, but kept for context consistency.
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a single beneficiary's details.">
@@ -45,4 +45,4 @@ class BeneficiaryData extends Data
public ?bool $isVpr = null,
) {}
// </SECTION>
}
}

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for the status of a counterparty request.">

View File

@@ -17,6 +17,7 @@ use Apoloz\AlfaBank\Data\PaginationData;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a collection of deals.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a single deal's details.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for a payoff associated with a deal.">

View File

@@ -14,6 +14,7 @@ namespace Apoloz\AlfaBank\Data\NominalAccounts\Deals;
// <SECTION name="module_imports" intent="Import the base Spatie Laravel Data class.">
// <BELIEF_STATE "Extending `Spatie\LaravelData\Data` enables automatic casting from JSON and provides other DTO benefits.">
use Spatie\LaravelData\Data;
// </SECTION>
// <SECTION name="class_definition" intent="Define a DTO for the status of a deal request.">

Some files were not shown because too many files have changed in this diff Show More