Payment callback (Payment notification) will be sent to merchant's callback_url when order status is changed to pending confirming, paid, invalid, canceled, refunded or expired.
Callback data is sent in POST method.
Testing
For payment callback handling you can use requestcatcher.com tool.
CoinGate callback sends data below:
Name | Value |
---|---|
id | CoinGate order (invoice) ID. |
order_id | Custom order ID of the merchant. Should be used to identify order or invoice number. |
status | CoinGate payment status. |
price_amount | The price set by the merchant; for example, 499.95. |
price_currency | The currency code which defines the currency in which the merchant's goods/services are priced; for example, USD, CHF, BTC (see supported currencies). |
receive_currency | The currency code which defines the currency in which the merchant's settlements will be paid. Currency conversions are done by CoinGate automatically. For example: EUR, USD, BTC, USDT, etc. |
receive_amount | The amount which will be credited to the merchant when the invoice is paid. It is calculated by taking the price amount (converted to currency units set in receive_currency ) and subtracting CoinGate processing fee from it. |
pay_amount | The amount of cryptocurrency (defined by pay_currency ) paid by the shopper. |
pay_currency | The cryptocurrency in which the payment was made; for example, BTC, LTC, ETH. |
underpaid_amount | The amount of cryptocurrency (defined by pay_currency ) underpaid by the shopper; for example, if pay_amount => 0.123 , pay_currency => BTC , and the shopper paid 0.12 BTC, then underpaid_amount => 0.003 . Changes in underpaid_amount will not trigger additional callbacks, but when order information is retrieved using GET or LIST, latest value will be shown. |
overpaid_amount | The amount of cryptocurrency (defined by pay_currency ) overpaid by the shopper; for example, if pay_amount => 0.123 , pay_currency => BTC , and the shopper paid 0.15 BTC, then overpaid_amount => 0.027 . Changes in overpaid_amount will not trigger additional callbacks, but when order information is retrieved using GET or LIST, latest value will be shown. |
is_refundable | Possible values: true, false. Indicates whether or not the shopper can request a refund on the invoice. Changes in is_refundable will not trigger additional callbacks, but when order information is retrieved using GET or LIST, latest value will be shown. |
created_at | Invoice creation time. |
token | Your custom token (or generated by CoinGate) to validate payment callback. |
Fields pay_currency, pay_amount, expire_at, payment_address
are only sent when the customer chooses the currency with which he is going to pay for the invoice.
Content-Type: application/x-www-form-urlencoded
// print_r($_POST)
Array
(
[id] => 343
[order_id] => 14037
[status] => paid
[price_amount] => 1050.99
[price_currency] => USD
[receive_amount] => 926.73
[receive_currency] => EUR
[pay_amount] => 4.81849315
[pay_currency] => BTC
[created_at] => 2014-11-03T13:07:28+00:00
[token] => ff7a7343-93bf-42b7-b82c-b38687081a4e
)
See the code below how to accept callback.
Callback Retry Time
CoinGate sends payment notification while your application returns response 200 (OK) HTTP or 204 (No Content) status code.
- Sends every 1 minute if retry count is <= 5
- Sends every 5 minutes if retry count is > 5 and <= 10
- Sends every 10 minutes if retry count is > 10 and <= 15
- Sends every 20 minutes if retry count is > 15 and <= 20
- Sends every 30 minutes if retry count is > 20 and <= 25
- Sends every 1 hour if retry count is > 25 and <= 30
- Sends every 5 hours if retry count is > 30 and <= 35
- Sends every 1 day if try count is > 35 and <= 40
- Callback will be canceled if retry count is >= 41
After sending payment notification, CoinGate waits for a response for 20 seconds.
Payment notification will be canceled and terminated if one of the following conditions occur:
- Payment notification is sent 40 times.
- After sending payment notification, response status received is 301, 302 (Redirect). This commonly happens if you use "http" in your URL and it gets redirected to "https".
- After sending payment notification, response status received is 401 (Unauthorized). This commonly happens when your website is password-protected (Basic access authentication). Ensure your website is publicly accessible.
- Payment notification is sent to TOR network.
- Payment notification is sent to a private network, such as localhost.
IP Addresses
Payment Callback is sent from servers described in API endpoint. This API endpoint is public, authentication is not required.
Live: https://api.coingate.com/v2/ips-v4
Sandbox: https://api-sandbox.coingate.com/v2/ips-v4
Each IP is separated by a new line. Make sure that your server, as well as third-party security services (cloudflare, incapsula, etc.), are not blocking these IP addresses.
We recommend update your IP whitelist from this API endpoint regularly.
Private Nework & Localhost
CoinGate payment callback will not send notifications to private networks (for example: localhost).
In localhost, you can send test payment notification with cURL library:
curl -X POST -d "id=343&order_id=ORDER-1415020039&status=paid&price_amount=1050.99&price_currency=USD&receive_currency=EUR&receive_amount=926.73&pay_amount=4.81849315&pay_currency=BTC&created_at=2014-11-03T13:07:28%2B00:00" https://coingate.requestcatcher.com/payment
Payment Callback Logs
You can review payment callbacks and your server response to callback in your account panel. Login to your account and locate API » Payment Callbacks.
Accepting Payment Callback
Example: save the code below as accept-coingate-callback.php
and execute cURL command in your command line tool:
curl -X POST -d "id=343&order_id=ORDER-1415020039&status=paid&price_amount=1050.99&price_currency=USD&receive_currency=EUR&receive_amount=926.73&pay_amount=4.81849315&pay_currency=BTC&created_at=2014-11-03T13:07:28%2B00:00" http://localhost/accept-coingate-callback.php?token=5d02161be9bfb6192a33
<?php
// Your custom order_id is defined when you creating new order: https://developer.coingate.com/docs/create-order
// Also don't forget to prevent SQL injection
$result = mysql_query("SELECT * FROM orders WHERE id = " . $_POST['order_id']);
$order = mysql_fetch_assoc($result);
// token is your random secure string (for example: 5d02161be9bfb6192a33) for each order
if ($_POST['token'] == $order['token']) {
// Handle CoinGate order status: https://developer.coingate.com/docs/order-statuses
$status = NULL;
if ($_POST['status'] == 'paid') {
if ($_POST['price_amount'] >= $order['amount']) {
$status = 'paid';
}
}
else {
$status = $_POST['status'];
}
if (!is_null($status)) {
mysql_query("UPDATE orders SET status = '".$status."' WHERE id = ".$_POST['order_id']);
}
}
class CoingateCallbackController < ApplicationController
skip_before_action :verify_authenticity_token, only: :create
def create
order = Order.find_by(id: params[:order_id])
if order.present?
if params[:token].present? && order.token == params[:token]
status = nil
if params[:status] == 'paid'
if params[:price].to_d >= order.amount # in addition you can check currency (params[:currency] == order.currency)
status = 'paid'
end
else
status = params[:status]
end
if status.present?
order.update_attribute(:status, status)
end
end
end
end
end