Перейти к содержанию

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:

  1. Тайм-аут соединения (Connection Timeout): граничное время для установления начального соединения с HTTP-сервером URL Callbacks.
  2. Тайм-аут чтения (Read Timeout): граничное время сообщения о получении данных HTTP сервером после установки соединения.
  3. Общий тайм-аут отправки 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 и кнопку Отправить заново.

Resend Callback

Дублирование

Из-за повторной отправки Callbacks есть вероятность, что приложение получит одни и те же данные несколько раз. Вы можете убедиться в идемпотентности операции (свойстве объекта или операции при повторном применении операции к объекту давать тот же результат, что и при первом), обнаружив такие дубликаты в данных приложения.

Это не является проблемой, если приложение определяет идемпотентность. Для контроля используйте параметр id в данных запроса Callbacks, т.к. его значение является уникальным для операции.

Пакетная обработка

Мы связываем Callbacks для близких статусов. Так, если платеж сразу же перешел из статуса created (создан) в статус pending (в обработке) и в статус processed (обработан), вы получите только один Callback с последним по времени статусом (т.е. processed).

Преимущество такого подхода: возможность избежать перегрузки ваших серверов HTTP запросами и избавить ваше приложение от необходимости усложнять логику взаимодействия с последовательными изменениями статуса. Ваше приложение должен заботить только последний статус объекта.

Доставка не по порядку

Callbacks могут приходить не по порядку из-за неполадок сети или сбоев отправки. Вы все равно можете установить правильную последовательность событий, ориентируясь на атрибут updated в Callbacks — временную отметку в Timestamp формате.

IP-адреса

Для повышения безопасности взаимодействия между платформой MilkyPay и вашим сервером, необходимо использовать белый список IP-адресов.

Детальнее о доменах и IP адресах →