Payment callback (Payment notification) will be sent to merchant's callback_url when order status or refund status or billing status is changed. Parameter callback_url is defined by creating object:

📘

Testing

For payment callback handling you can use requestcatcher.com tool.

Callback Format

🚧

Callback data is sent in POST method.

By creating new API App you can choose in which format you want to receive callbacks:

  • Form Encoding (application/x-www-form-urlencoded)
  • JSON (application/json)

Change callback format for existing API App go to Merchant » API » Apps » Edit.

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