Приём платежей

Возврат платежа

Создайте заявку на полный возврат оплаченной транзакции и отслеживайте результат

POST/integration/transactions/{uuid}/refund

Полный путь: /api/v1/integration/transactions/{uuid}/refund. Используйте UUID транзакции Cashera из ответа создания платежа, а не идентификатор провайдера. Транзакция должна принадлежать мерчанту, указанному API-ключом.

Это заявка, а не мгновенный возврат

Новая заявка получает статус requested и проходит ту же проверку администратором, что и возврат из личного кабинета. Только после одобрения система проверяет возможность возврата у провайдера и отправляет его. Сам POST не меняет баланс и не вызывает провайдера. 201 Created не означает, что плательщик уже получил деньги.

Условия

  • Поддерживается полный возврат оплаченного входящего платежа со статусом paid
  • На первом этапе поддерживаются транзакции Platega с сохранёнными реквизитами провайдера. Возможность возврата конкретного платежа дополнительно проверяется при одобрении
  • Частичный возврат не поддерживается. Не передавайте сумму, валюту, реквизиты получателя или статус
  • Одна транзакция — одна заявка, независимо от того, создана она через API или личный кабинет

Авторизация

Для создания и чтения нужны X-Api-Key, X-Timestamp и X-Signature. Используется тот же HMAC-SHA256 алгоритм, что для выплат, но с путём возврата и соответствующим методом POST или GET. Секрет храните только на сервере. Действуют ограничения мерчанта и список разрешённых IP.

ПолеТипОписание
uuidобязательноеuuid (path)UUID исходной транзакции Cashera. external_id платежа можно найти через поиск транзакции
Тело запросапустоеОтправляйте пустое тело или пустой JSON-объект {}. Любые параметры, в том числе amount: null, отклоняются с 422. Подписывайте точные отправляемые байты

Создание заявки

# Экспортируйте CASHERA_API_KEY, CASHERA_API_SECRET и CASHERA_TRANSACTION_UUID
export CASHERA_REFUND_PATH="/api/v1/integration/transactions/$CASHERA_TRANSACTION_UUID/refund"
export CASHERA_REFUND_TIMESTAMP=$(date +%s)
signature=$(python3 - <<'PY'
import hashlib, hmac, os
parts = [os.environ["CASHERA_REFUND_TIMESTAMP"], "POST",
os.environ["CASHERA_REFUND_PATH"], hashlib.sha256(b"").hexdigest()]
print(hmac.new(os.environ["CASHERA_API_SECRET"].encode("utf-8"),
"\n".join(parts).encode("utf-8"), hashlib.sha256).hexdigest())
PY
)
curl --fail-with-body --request POST \
"https://api.cashera.cash/api/v1/integration/transactions/$CASHERA_TRANSACTION_UUID/refund" \
--header "X-Api-Key: $CASHERA_API_KEY" \
--header "X-Timestamp: $CASHERA_REFUND_TIMESTAMP" \
--header "X-Signature: $signature" \
--header 'Accept: application/json'

Повторный POST по той же транзакции возвращает ту же заявку с текущим статусом и кодом 201. Новый external_id не нужен: ключом идемпотентности служит UUID транзакции. Повтор не открывает заново отклонённый или завершённый возврат.

Получение статуса

GET/integration/transactions/{uuid}/refund

Тот же UUID исходной транзакции, пустое тело и новая подпись для метода GET. Ответ 200 OK содержит тот же объект заявки. Если заявки ещё нет, вернётся 404.

ПолеТипОписание
uuidstringИдентификатор заявки на возврат. В URL используется transaction_uuid, а не это поле
transaction_uuidstringUUID возвращаемого платежа
statusstringСтатус заявки из таблицы ниже
decision_reasonstring | nullПричина решения администратора, если указана
created_at / updated_atstringВремя создания и последнего изменения, ISO 8601
ПолеТипОписание
requestedОжидает решенияЗаявка создана, нужно одобрение администратора
checkingПроверкаПроверяется возможность возврата у провайдера
check_failedОшибка проверкиПроверка не завершилась; дальнейшую сверку выполняет администратор
unsupportedВозврат недоступенПровайдер не разрешил возврат. Повторный POST не отправляет его заново
submittingОтправкаЗапрос возврата отправляется провайдеру
submittedПринят провайдеромОжидается подтверждение результата
manual_reviewРучная проверкаПровайдер запросил ручную обработку
ambiguousРезультат неизвестенТребуется сверка, например после таймаута. Не отправляйте отдельный возврат напрямую провайдеру
rejectedОтклонёнАдминистратор отклонил заявку; см. decision_reason
supersededБольше не применимСостояние исходного платежа изменилось, например зарегистрирован chargeback
completedВозврат подтверждёнПолучено подтверждение провайдера, финансовые изменения отражены в системе

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

Ошибки

ПолеТипОписание
401UnauthorizedНет или неверны ключ, подпись, timestamp; время запроса вышло за допустимое окно
403ForbiddenМерчант отключён, баланс заморожен, секрет не настроен или IP не разрешён
404Not FoundПлатёж не найден, принадлежит другому мерчанту, некорректен UUID или отсутствует заявка при GET
409ConflictДля новой заявки исходный платёж должен быть paid
422Unprocessable EntityНеподдерживаемый тип/провайдер платежа, нет идентификаторов провайдера, повреждён JSON или переданы параметры запроса
429Too Many RequestsПревышен лимит интеграционного API

После сетевого сбоя проверьте заявку через GET или повторите POST с тем же UUID и свежей подписью