Вопрос. Оператор мобильной связи, сервис пополнения баланса или сторонний платёжный шлюз часто получают запросы от клиентов: «Кто именно пополнил мой телефон?». Для ответа на такой запрос необходимо иметь чётко определённую структуру данных, в которой фиксируются все детали операции пополнения.
Почему нужна структурированная информация?
- Контроль и аудит финансовых операций (противодействие мошенничеству).
- Поддержка клиентского сервиса – быстрый ответ клиенту о происхождении пополнения.
- Согласование с регуляторами (требования к хранению данных о платежах).
- Интеграция с другими системами (CRM, биллинг, аналитика).
Основные источники данных о пополнении
- Биллинг‑система оператора. Хранит запись о каждой транзакции пополнения.
- Платёжные шлюзы и сервисы быстрых платежей (СБП, QR‑коды, онлайн‑банки). Передают детали операции в виде JSON/XML.
- Терминалы и банкоматы. Генерируют журналы (лог‑файлы) с информацией о платеже.
- Международные сервисы пополнения (Ding, Yolla, iPay и др.). Предоставляют API‑ответы.
Какие поля должны присутствовать в структуре?
Ниже перечислены обязательные и рекомендованные атрибуты, которые позволяют однозначно идентифицировать «кто» и «как» пополнил счёт.
| Поле | Тип | Описание |
|---|---|---|
| transaction_id | VARCHAR(36) | Уникальный идентификатор операции (UUID). |
| timestamp | DATETIME | Дата и время проведения пополнения (в UTC). |
| phone_number | VARCHAR(15) | Номер телефона, который пополняется (в международном формате). |
| amount | DECIMAL(10,2) | Сумма пополнения в рублях (или валюте страны). |
| currency | CHAR(3) | Код валюты (RUB, USD, EUR и т.д.). |
| payer_type | ENUM(‘CARD’,’BANK_ACCOUNT’,’MOBILE_WALLET’,’CASH’,’INTERNET_BANKING’,’SBERBANK_PAY’,’QR’) | Тип источника платежа. |
| payer_identifier | VARCHAR(64) | Идентификатор плательщика (номер карты (masked), номер банковского счёта, телефон плательщика, email и т.п.). |
| payer_name | VARCHAR(255) | ФИО или название организации плательщика (если предоставлено). |
| operator_id | VARCHAR(10) | Код мобильного оператора (MTS, BEELINE, MEGAFON и др.). |
| service_provider | VARCHAR(50) | Название сервиса, через который выполнено пополнение (СБП, Ding, Yolla, iPay и т.д.). |
| status | ENUM(‘SUCCESS’,’FAILED’,’PENDING’,’CANCELLED’) | Текущий статус операции. |
| reference_code | VARCHAR(30) | Код подтверждения от банка/платёжного шлюза (может использоваться для сверки). |
| notes | TEXT | Дополнительные комментарии (например, причина отклонения). |
Примеры структур данных
Таблица в реляционной БД (SQL)
CREATE TABLE phone_topup_log (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
transaction_id CHAR(36) NOT NULL UNIQUE,
timestamp DATETIME NOT NULL,
phone_number VARCHAR(15) NOT NULL,
amount DECIMAL(10,2) NOT NULL,
currency CHAR(3) NOT NULL DEFAULT 'RUB',
payer_type ENUM('CARD','BANK_ACCOUNT','MOBILE_WALLET','CASH','INTERNET_BANKING','SBERBANK_PAY','QR') NOT NULL,
payer_identifier VARCHAR(64) NOT NULL,
payer_name VARCHAR(255) NULL,
operator_id VARCHAR(10) NOT NULL,
service_provider VARCHAR(50) NOT NULL,
status ENUM('SUCCESS','FAILED','PENDING','CANCELLED') NOT NULL,
reference_code VARCHAR(30) NULL,
notes TEXT NULL,
INDEX idx_phone_number (phone_number),
INDEX idx_timestamp (timestamp)
);
JSON‑структура, возвращаемая API
{
"transaction_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"timestamp": "2026-07-17T01:02:47Z",
"phone_number": "+7 -161234567",
"amount": 500.00,
"currency": "RUB",
"payer": {
"type": "CARD",
"identifier": "4111**1111",
"name": "Иван Иванов"
},
"operator_id": "MTS",
"service_provider": "СБП",
"status": "SUCCESS",
"reference_code": "SBP20260717010247",
"notes": null
}
XML‑формат (для старых интеграций)
<TopupTransaction>
<TransactionID>a1b2c3d4-5678-90ab-cdef-1234567890ab</TransactionID>
<Timestamp>2026-07-17T01:02:47Z</Timestamp>
<PhoneNumber>+7 -161234567</PhoneNumber>
<Amount currency="RUB">500.00</Amount>
<Payer type="CARD">
<Identifier>4111**1111</Identifier>
<Name>Иван Иванов</Name>
</Payer>
<OperatorID>MTS</OperatorID>
<ServiceProvider>СБП</ServiceProvider>
<Status>SUCCESS</Status>
<ReferenceCode>SBP20260717010247</ReferenceCode>
</TopupTransaction>
Как собрать информацию о плательщике?
Для получения данных о том, кто пополнил счёт, необходимо:
- Получить идентификатор транзакции из ответа платёжного шлюза (UUID, номер операции).
- Сверить его с записью в биллинговой системе оператора (по
transaction_id). - Извлечь
payer_typeиpayer_identifier. В случае карт – хранить только маскированный номер, а не полные данные. - Если пополнение выполнено через СБП, в ответе будет
payer_identifier= номер телефона плательщика. - При международных сервисах (Ding, Yolla) – использовать поле
service_providerиreference_codeдля дополнительной проверки.
Безопасность и конфиденциальность
- Шифрование. Хранить чувствительные данные (маскированные номера карт, банковские реквизиты) в зашифрованном виде (AES‑256).
- Минимизация. Сохранять только те поля, которые действительно нужны для бизнес‑логики.
- Аудит доступа. Вести журнал чтения/изменения записей (who, when, what).
- Соответствие требованиям. GDPR, ФЗ‑152 «О персональных данных», PCI‑DSS (если хранятся данные карт).
Пример запроса к базе и формирования ответа
Допустим, клиент звонит в службу поддержки и интересуется, кто пополнил его счёт. Оператор вводит номер телефона и период, после чего система формирует ответ.
SQL‑запрос
SELECT
transaction_id,
timestamp,
amount,
currency,
payer_type,
payer_identifier,
payer_name,
service_provider,
status
FROM phone_topup_log
WHERE phone_number = '+7 -161234567'
AND timestamp BETWEEN '2026-07-01' AND '2026-07-31'
ORDER BY timestamp DESC
LIMIT 10;
Преобразование в JSON (пример на Python)
import json
import pymysql
conn = pymysql.connect(host='db.example.com', user='user', password='pwd', db='billing')
cur = conn.cursor(pymysql.cursors.DictCursor)
sql = """SELECT transaction_id, timestamp, amount, currency,
payer_type, payer_identifier, payer_name,
service_provider, status
FROM phone_topup_log
WHERE phone_number = %s
AND timestamp BETWEEN %s AND %s
ORDER BY timestamp DESC
LIMIT 10"""
cur.execute(sql, ('+7 -161234567', '2026-07-01', '2026-07-31'))
rows = cur.fetchall
print(json.dumps(rows, ensure_ascii=False, indent=4, default=str))
Интеграция с внешними сервисами
Большинство современных платёжных шлюзов (СБП, Apple Pay, Google Pay, QR‑коды) предоставляют веб‑хук (webhook)‑уведомления. Формат веб‑хука обычно выглядит так:
{
"event": "topup.completed",
"data": {
"transaction_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"phone_number": "+7 -161234567",
"amount": "500.00",
"currency": "RUB",
"payer": {
"type": "MOBILE_WALLET",
"identifier": "+7 -160001122"
},
"status": "SUCCESS"
}
}
Для надёжного получения и обработки таких уведомлений необходимо:
- Подписывать запросы (HMAC‑SHA256) и проверять подпись.
- Идентифицировать оператора по полю
service_provider. - Записывать полученные данные в локальную структуру (см. раздел 3).
Лучшие практики
- Использовать универсальный идентификатор транзакции (UUID) – упрощает синхронизацию между системами.
- Хранить маскированные данные карты, а полные реквизиты хранить только в платёжном шлюзе.
- Обеспечить идемпотентность записи – повторный запрос от шлюза не создаёт дублирования.
- Регулярно архивировать старые записи (например, старше 5 лет) в холодное хранилище.
- Включать в запись поле
notesдля ручных корректировок (например, возврат средств).
Для того чтобы ответить на вопрос «Кто пополняет счёт на телефонный номер», необходимо иметь чётко определённую структуру данных, в которой фиксируются все атрибуты операции пополнения. Наиболее универсальными являются:
- Таблица в реляционной базе данных с полями, описанными в разделе 3.
- JSON‑ или XML‑форматы для обмена данными между оператором, платёжным шлюзом и клиентскими приложениями.
При правильном проектировании такой структуры можно обеспечить быстрый поиск, высокий уровень безопасности и полную прозрачность для клиентов и регуляторов.