Callbacks¶
Callbacks позволяют получать уведомления, когда изменяется статус операции.
Чтобы настроить Callbacks для операций, необходимо задать адрес в callback_url
в настройках интеграции или отправлять этот параметр в запросе.
Note
Callback — асинхронная функция, поэтому не рекомендуется для задач с жестким ограничением по времени. Существует вероятность, что ваше приложение получит сообщения не в порядке отправки или они продублируются. Поэтому в дополнение к Callbacks мы рекомендуем использовать реконсиляцию (сверку) по API для обновления данных в системе.
Настройка¶
Для настройки Callbacks вам нужно перейти к настройкам аккаунта и добавить значение «Callback URL».
Формат сообщения¶
HTTP запрос, который мы отправим на ваш callback_url
, будет обладать следующими характеристиками:
- это будет POST запрос;
- тело запроса будет передано в JSON API формате;
- объекты
type
иid
обязательно будут в теле запроса (а не в URL-параметре).
{
"data": {
"type": "payment-invoices",
"id": "cpi_yv1RgJ2l8ty2AxIs",
"attributes": {
"serial_number": "yv1RgJ2l8ty2AxIs",
"status": "processed",
"resolution": "ok",
"moderation_required": false,
"amount": 22,
"payment_amount": 22,
"currency": "USD",
"service_currency": "USD",
"reference_id": "da1b0b9d-c249-4f6e-9949-2a2f2d4b1758",
"test_mode": true,
"fee": 0,
"deposit": 22,
"processed": 1592232071,
"processed_amount": 22,
"refunded_amount": null,
"processed_fee": 0,
"processed_deposit": 22,
"metadata": {
"merchant_url": "https://yu.test.this"
},
"flow_data": {
"action": "https://example.domain/hpp/cgi_Q0fYDFaHlqb5MCdl",
"method": "GET",
"params": [],
"metadata": {
"sid": "cgi_Q0fYDFaHlqb5MCdl",
"token": "eyJ0eXAiOiJKV1QiLRiGCg2O...nGE7E"
}
},
"flow": "hpp",
"payment_flow": "charge",
"created": 1592232050,
"updated": 1592232071,
"payload": {
"token": null,
"client_ip": "54.36.117.30",
"payment_card": {
"last": "0000",
"mask": "512381******0000",
"brand": "mastercard",
"first": "512381",
"holder": null,
"expiry_year": "33",
"issuer_name": "FIRST DATA CORPORATION",
"expiry_month": "11",
"issuer_country": "US"
}
},
"description": null,
"descriptor": null,
"callback_url": "https://test.doc.home",
"return_url": "https://example.com",
"return_urls": {
"fail": "https://example.com/sorry-page",
"pending": "https://example.com/wait-for-it-page",
"success": "https://example.com/thank-you-page"
},
"original_data": null,
"rrn": null,
"approval_code": null,
"reserved_amount": null,
"reserve_expires": null,
"unreserved": null,
"source": null,
"callback_logs": []
},
"relationships": {
"payment-service": {
"data": {
"type": "payment-services",
"id": "payment_card_usd_hpp"
}
},
"payment-method": {
"data": {
"type": "payment-methods",
"id": "payment_card"
}
},
"customer": {
"data": null
}
},
"links": {
"self": "/api/payment-invoices/cpi_yv1RgJ2l8ty2AxIs"
}
}
}
{
"data": {
"type": "payout-invoices",
"id": "cpoi_sIzOuMKJg98J22NC",
"attributes": {
"serial_number": "sIzOuMKJg98J22NC",
"status": "processed",
"resolution": "ok",
"amount": 100,
"payout_amount": 100,
"currency": "USD",
"service_currency": "USD",
"service_amount": 100,
"service_payout_amount": 100,
"reference_id": "45284707-d243-439e-8b41-d657322e693b",
"test_mode": true,
"description": null,
"fee": 0,
"writeoff": 100,
"exchange_rate": 1,
"processed": 1621335982,
"processed_amount": 100,
"processed_fee": 0,
"processed_writeoff": 100,
"metadata": [],
"created": 1621335974,
"updated": 1621335982,
"fields": {
"card_number": "512381******0000"
},
"callback_url": "https://test.doc.home",
"source": "merchant_dashboard",
"callback_logs": [],
"payouts": [
{
"id":"po_4a3Bgz6YR3cRjW6k",
"rrn":null,
"amount":72.5,
"currency":"USD",
"status":"processed"
},
{
"id":"po_3cR4z6kgYR6aj3BW",
"rrn":null,
"amount":27.5,
"currency":"USD",
"status":"processed"
}
]
},
"relationships": {
"payout-service": {
"data": {
"type": "payout-services",
"id": "payment_card_usd"
}
},
"payout-method": {
"data": {
"type": "payout-methods",
"id": "payment_card"
}
},
"customer": {
"data": null
}
},
"links": {
"self": "/api/payout-invoices/cpoi_sIzOuMKJg98J22NC"
}
}
}
Тело запроса Callback содержит тело соответствующей операции инвойса.
Статусы инвойсов описаны в руководствах:
Проверка подлинности¶
MilkyPay подписывает данные, используя ключи в хедере запроса X-Signature
.
Алгоритм генерации подписи (PHP)
<?php
$secret="yourPrivateKey";
$callbackData='{"data":{"type":"payment-invoices","id":"cpi_exampleID","attributes":{"serial_number":"exampleID","status":"processed","resolution":"ok","moderation_required":false,"amount":1000,"payment_amount":1000,"currency":"USD","service_currency":"USD","reference_id":"yourReferenceId","test_mode":true,"fee":38,"deposit":962,"processed":1647077297,"processed_amount":1000,"refunded_amount":null,"processed_fee":38,"processed_deposit":962,"metadata":[],"flow_data":{"action":"https:\/\/pay.example.com\/hpp\/cgi_exampleId","method":"GET","params":[],"metadata":{"sid":"cgi_exampleId","token":"bearerToken-for-H2H-api-auth"}},"flow":"hpp","payment_flow":"charge","created":1647077285,"updated":1647077297,"payload":{"token":"token-if-tokenize-true","auth_type":"card","client_ip":"192.168.0.1","payment_card":{"last":"0000","mask":"512381******0000","brand":null,"first":"512381","holder":"Test Customer","network":"mastercard","expiry_year":"99","issuer_name":"FIRST DATA CORPORATION","expiry_month":"09","issuer_country":"US"}},"description":null,"descriptor":null,"callback_url":"https:\/\/your.callback.url","return_url":null,"return_urls":{"fail":"https:\/\/your.fail-return.url","pending":"https:\/\/your.default-return.url","success":"https:\/\/your.success-return.url"},"original_data":null,"rrn":null,"approval_code":null,"reserved_amount":null,"reserve_expires":null,"unreserved":null,"source":"merchant_api","callback_logs":[],"charged_back_amount":null,"resolution_message":null,"hpp_url":"https:\/\/api.example.com\/hpp?cpi=cpi_exampleID"},"relationships":{"payment-service":{"data":{"type":"payment-services","id":"payment_card_usd_hpp"}},"payment-method":{"data":{"type":"payment-methods","id":"payment_card"}},"customer":{"data":{"type":"customers","id":"cus_exampleID"}},"active-payment":{"data":{"type":"payments","id":"pay_exampleID"}}},"links":{"self":"\/api\/payment-invoices\/cpi_exampleID"}},"included":[{"type":"customers","id":"cus_exampleID","attributes":{"reference_id":"example-customer-id","email":null,"name":null,"phone":null,"description":null,"created":1646833439,"metadata":[],"avatar":"https:\/\/www.gravatar.com\/avatar\/exampleAvatarID?s=20&d=mm&r=g","archived":false,"processing_options":{"payment_enabled":true,"payout_enabled":true},"address":{"street":null,"country":null,"region":null,"city":null,"full_address":null,"post_code":null}},"relationships":{"commerce-account":{"data":{"type":"commerce-accounts","id":"coma_exampleID"}}}}]}';
$signature = base64_encode(sha1($secret . $callbackData . $secret, true));
echo $signature;
- В примере выше:
-
$secret
— это боевой ("Live key") или тестовый ("Test key") приватный ключ, который находится в настройках аккаунта; -
$callbackData
— неформатированные данные в JSON, полученные в сообщении Callback; -
$signature
— алгоритм генерации.
Чтобы убедиться в достоверности источника, сгенерируйте подпись, используя соответствующий приватный ключ и raw JSON тело Callback.
В результате вы получите строку base64 вида:
B86Af35b/IfM0z0rGROHw5gVw14=
которая должна быть идентична подписи в хедере Callback.
Превышение времени ожидания (тайм-аут)¶
MilkyPay выделяет три типа тайм-аутов для Callbacks:
- Тайм-аут соединения (Connection Timeout): граничное время для установления начального соединения с HTTP-сервером URL Callbacks.
- Тайм-аут чтения (Read Timeout): граничное время сообщения о получении данных HTTP сервером после установки соединения.
- Общий тайм-аут отправки Callbacks (Execution Timeout): в дополнение к предыдущим MilkyPay также проверяет общее время выполнения Callbacks.
Значения тайм-аутов:
Тип | Для тестового соединения | Для боевого соединения |
---|---|---|
Connection Timeout | 10,000 мс | 20,000 мс |
Read Timeout | 10,000 мс | 20,000 мс |
Execution Timeout | 20,000 мс | 60,000 мс |
Доставка Calbacks и автоповтор отправки¶
Дальнейшие действия определяются по HTTP-коду, полученному в ответе на отправку Callbacks:
Код | Значение | Дальнейшие действия системы |
---|---|---|
200 | Callback успешно доставлен | Повторная отправка не требуется, следующие запланированные попытки доставки аннулируются |
429 | Слишком много запросов, Callback не принят | Повторная отправка принудительно остановлена, следующие запланированные попытки доставки аннулируются |
Любой другой HTTP-код в ответе означает, что запрос не доставлен. По умолчанию запрос повторно отправляется с промежутком ожидания между попытками:
- 1-й повтор запроса будет отправлен спустя 1 минуту после начальной попытки;
- 2-й повтор — спустя 2 минуты после 1-го повтора;
- 3-й — спустя 3 минуты после 2-го;
- 4-й — спустя 4 минуты после 3-го;
- 5-й — спустя 5 минут после 4-го;
- и 6-й — спустя 6 минут после 5го.
- и т.д. до 100 попыток или до получения
200
или429
HTTP-кода.
Существует возможность настройки интервала отправки и количества попыток
Отправьте запрос нашей службе поддержки , чтобы мы вместе подобрали наиболее подходящий вариант.
Note
Вы можете переотправить запрос c панели управления, если хотите синхронизировать данные немедленно. Для этого нужно перейти к обзору транзакции, выбрать вкладку Callbacks и кнопку Отправить заново.
Дублирование¶
Из-за повторной отправки Callbacks есть вероятность, что приложение получит одни и те же данные несколько раз. Вы можете убедиться в идемпотентности операции (свойстве объекта или операции при повторном применении операции к объекту давать тот же результат, что и при первом), обнаружив такие дубликаты в данных приложения.
Это не является проблемой, если приложение определяет идемпотентность. Для контроля используйте параметр id
в данных запроса Callbacks, т.к. его значение является уникальным для операции.
Пакетная обработка¶
Мы связываем Callbacks для близких статусов. Так, если платеж сразу же перешел из статуса created
(создан) в статус pending
(в обработке) и в статус processed
(обработан), вы получите только один Callback с последним по времени статусом (т.е. processed
).
Преимущество такого подхода: возможность избежать перегрузки ваших серверов HTTP запросами и избавить ваше приложение от необходимости усложнять логику взаимодействия с последовательными изменениями статуса. Ваше приложение должен заботить только последний статус объекта.
Доставка не по порядку¶
Callbacks могут приходить не по порядку из-за неполадок сети или сбоев отправки. Вы все равно можете установить правильную последовательность событий, ориентируясь на атрибут updated
в Callbacks — временную отметку в Timestamp формате.
IP-адреса¶
Для повышения безопасности взаимодействия между платформой MilkyPay и вашим сервером, необходимо использовать белый список IP-адресов.