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