Skip to content

Массовая выдача наград через CSV ​

Когда наградить нужно тысячи игроков разом — компенсация за баг, выплата по инциденту — награды загружаются файлом из ACP: Почта → Массовая загрузка. Панель разбирает файл на глазах у оператора, показывает построчный разбор до отправки и отчёт после.

Формат файла ​

Первая строка — заголовок с названиями колонок. Порядок любой, колонки, которых импорт не знает, просто игнорируются: выгрузка из аналитики вместе со всей рабочей арифметикой загружается как есть.

csv
api_uid,api_type,award:soft_currency,award:hard_currency,text:en,text:ru
t2_klwd697t,39,24000,5,Sorry about that,Извините
t2_mm1a2b3c,39,22000,0,Sorry about that,Извините
КолонкаОбязательнаЧто значит
api_uidдаUID получателя на платформе
api_typeнетплатформа строки; иначе берётся выбранная в форме
award:<ключ>для режима «у каждого своя»сколько этой награды выдать строке
text:<язык>неттекст сообщения на этом языке

<ключ> — ключ награды проекта (soft_currency, hard_currency), <язык> — язык проекта (en, ru). Колонок award: и text: может быть сколько угодно — по одной на награду и на язык, поэтому строка не ограничена одной наградой и одним переводом. Ноль или пустая ячейка в award: означают «эту награду этой строке не выдаём».

Колонка award: или text:, называющая награду или язык, которых у проекта нет, пропускается, и панель говорит об этом один раз по заголовку, а не тысячей одинаковых отказов по строкам.

Пустая ячейка api_type, ноль и отсутствие колонки означают одно и то же — «платформа не указана», и берётся выбранная в форме. Ноль читается именно так, а не как платформа №0, на которой нет ни одного аккаунта. Поле «Платформа по умолчанию» в форме обязательно ровно тогда, когда хоть одна строка платформу не называет; если её называет каждая — поле не используется.

Текст задаётся колонками text:<язык>. Общий текст в форме предлагается только в режиме «одна награда на всех» — там же, где и общая награда; в построчном режиме его нет, чтобы не было двух источников одного и того же. Строка со своим текстом перекрывает общий, строка без текста в построчном режиме уходит с одной наградой.

Колонки определяются только по заголовку — сопоставлять их в панели вручную не нужно и нельзя: в award: и text: заголовок и есть ответ, а для получателя понимаются, кроме api_uid и api_type, и обиходные имена (uid, user_id, player_id, platform).

Разделитель определяется сам (,, ;, табуляция, |) по строке заголовка. Кавычки, кавычки внутри кавычек и переводы строк внутри кавычек читаются по правилам CSV, BOM от Excel отбрасывается. Суммы принимаются в том виде, в каком их пишет таблица: 24000, 24 000, 24 000 с неразрывным пробелом, 1,5.

Всё это есть и в самом диалоге — блок «Как подготовить файл» над зоной загрузки, с примером на наградах и языках конкретного проекта.

Тип сообщения у массовой выдачи всегда «прямая награда игроку» — выбора нет: массово рассылают именно её.

Два режима ​

  • Одна награда на всех — награда и текст задаются в форме, колонки award: не нужны, от файла нужен только список получателей. Колонки text: при этом работают: одинаковая награда не значит одинаковую формулировку, и строка со своим текстом перекрывает общий.
  • У каждого своя — награды берутся из колонок award: построчно. Строка, которая по итогу не выдаёт ничего (пусто или везде ноль), не отправляется: это не компенсация.

Что не отправится ​

Строка не выбрасывается молча — она остаётся в таблице с причиной: нет UID, платформа не число, нет награды, награда не читается, дубликат. Дубликатом считается повтор пары платформа+UID; побеждает первая строка.

Получатели, за которыми нет аккаунта, не создаются — они попадают в отчёт как no_account. Файл с ошибочной платформой иначе завёл бы тысячи пустых аккаунтов, которые потом кому-то разгребать.

Ограничения ​

За один импорт — не больше 10 000 наград. Панель режет файл на запросы по 500 строк и шлёт их последовательно, показывая прогресс.

Повторная отправка ничего не оплачивает дважды ​

Каждый импорт получает batch_key — имя одного решения оператора. Все запросы одного файла несут его, а база отказывается записать второе сообщение тому же получателю под тем же ключом.

Отсюда следует главное: повторить импорт всегда безопасно. Оборвалось соединение на середине, оператор нажал дважды, перезагрузил страницу и положил тот же файл снова — отправится только то, что не дошло. Разные импорты — разные ключи, поэтому наградить тех же игроков ещё раз в следующем месяце можно обычным способом.

Отчёт ​

После импорта показываются счётчики — отправлено, уже было отправлено, аккаунт не найден, пропущено в файле — и отчёт выгружается в CSV: каждая строка исходного файла с тем, что с ней стало, адресованная так же, как в исходнике, чтобы строку можно было найти в своей таблице.

API ​

POST /acp/messages/bulk-create — один чанк импорта. Требует права AccessMessage.

json
{
  "batch_key": "mail-20260923T120000-a1b2c3",
  "type": 2,
  "api_type": 39,
  "award": { "soft_currency": 5000 },
  "description": [{ "lang": "en", "text": "Sorry about that" }],
  "attributes": {},
  "expired_at": "2026-10-23T08:00:00.000Z",
  "entries": [
    {
      "api_uid": "t2_klwd697t",
      "award": { "soft_currency": 24000, "hard_currency": 5 },
      "description": [{ "lang": "ru", "text": "Извините" }]
    },
    { "api_uid": "t2_mm1a2b3c", "award": { "soft_currency": 22000 } }
  ]
}

award и description на верхнем уровне применяются ко всем; те же поля внутри entries перекрывают их для конкретного получателя. api_type внутри записи перекрывает верхний. batch_key обязателен, в одном запросе не больше 1000 записей.

Автор сообщения проставляется сервером по авторизованному оператору — в теле запроса его задать нельзя.

Ответ — отчёт по этому чанку:

json
{
  "report": {
    "requested": 2,
    "sent": 2,
    "already_sent": 0,
    "no_account": 0,
    "rows": [
      { "api_type": 39, "api_uid": "t2_klwd697t", "outcome": "sent" },
      { "api_type": 39, "api_uid": "t2_mm1a2b3c", "outcome": "sent" }
    ]
  }
}

outcome принимает значения sent, already_sent (получатель уже получил сообщение под этим batch_key) и no_account.