{"metadata":{"image":[],"title":"","description":""},"api":{"url":"","auth":"required","results":{"codes":[]},"settings":"","params":[]},"next":{"description":"","pages":[]},"title":"Payment Callback","type":"basic","slug":"payment-callback","excerpt":"","body":"Payment callback (Payment notification) will be sent to merchant's ***callback_url*** when [order status](doc:order-statuses) is changed to *pending* *confirming*, *paid*, *invalid*, *canceled*, *refunded* or *expired*.\n[block:callout]\n{\n \"type\": \"warning\",\n \"body\": \"Callback data is sent in **POST** method.\"\n}\n[/block]\n\n[block:callout]\n{\n \"type\": \"info\",\n \"body\": \"For payment callback handling you can use [requestcatcher.com](https://requestcatcher.com/) tool.\",\n \"title\": \"Testing\"\n}\n[/block]\nCoinGate callback sends data below:\n[block:parameters]\n{\n \"data\": {\n \"h-0\": \"Name\",\n \"h-1\": \"Value\",\n \"0-0\": \"`id`\",\n \"0-1\": \"CoinGate order (invoice) ID.\",\n \"1-0\": \"`order_id`\",\n \"1-1\": \"Custom order ID of the merchant. Should be used to identify order or invoice number.\",\n \"2-0\": \"`status`\",\n \"2-1\": \"CoinGate [payment status](doc:order-statuses).\",\n \"3-0\": \"`price_amount`\",\n \"3-1\": \"The price set by the merchant; for example, *499.95*.\",\n \"4-0\": \"`price_currency`\",\n \"4-1\": \"The currency code which defines the currency in which the merchant's goods/services are priced; for example, *USD*, *CHF*, *BTC* (see [supported currencies](https://coingate.com/currencies)).\",\n \"5-0\": \"`receive_currency`\",\n \"5-1\": \"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.\",\n \"6-0\": \"`receive_amount`\",\n \"12-0\": \"`created_at`\",\n \"12-1\": \"Invoice creation time.\",\n \"6-1\": \"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.\",\n \"13-0\": \"`token`\",\n \"7-0\": \"`pay_amount`\",\n \"8-0\": \"`pay_currency`\",\n \"13-1\": \"Your custom token (or generated by CoinGate) to validate payment callback.\",\n \"7-1\": \"The amount of cryptocurrency (defined by `pay_currency`) paid by the shopper.\",\n \"8-1\": \"The cryptocurrency in which the payment was made; for example, *BTC*, *LTC*, *ETH*.\",\n \"9-0\": \"`underpaid_amount`\",\n \"10-0\": \"`overpaid_amount`\",\n \"10-1\": \"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.\",\n \"9-1\": \"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.\",\n \"11-0\": \"`is_refundable`\",\n \"11-1\": \"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.\"\n },\n \"cols\": 2,\n \"rows\": 14\n}\n[/block]\nFields `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.\n\n**Content-Type: application/x-www-form-urlencoded** \n[block:code]\n{\n \"codes\": [\n {\n \"code\": \"// print_r($_POST)\\n\\nArray\\n(\\n [id] => 343\\n [order_id] => 14037\\n [status] => paid\\n [price_amount] => 1050.99\\n [price_currency] => USD\\n [receive_amount] => 926.73\\n [receive_currency] => EUR\\n [pay_amount] => 4.81849315\\n [pay_currency] => BTC\\n [created_at] => 2014-11-03T13:07:28+00:00\\n\\t\\t[token] => ff7a7343-93bf-42b7-b82c-b38687081a4e\\n)\",\n \"language\": \"php\"\n }\n ]\n}\n[/block]\nSee the code below how to accept callback.\n[block:api-header]\n{\n \"type\": \"basic\",\n \"title\": \"Callback Retry Time\"\n}\n[/block]\n\n[block:callout]\n{\n \"type\": \"info\",\n \"body\": \"CoinGate sends payment notification while your application returns response **200 (OK) HTTP** or **204 (No Content)** status code.\"\n}\n[/block]\n* Sends every 1 minute if retry count is <= 5\n* Sends every 5 minutes if retry count is > 5 and <= 10\n* Sends every 10 minutes if retry count is > 10 and <= 15\n* Sends every 20 minutes if retry count is > 15 and <= 20\n* Sends every 30 minutes if retry count is > 20 and <= 25\n* Sends every 1 hour if retry count is > 25 and <= 30\n* Sends every 5 hours if retry count is > 30 and <= 35\n* Sends every 1 day if try count is > 35 and <= 40\n* Callback will be canceled if retry count is >= 41\n\nAfter sending payment notification, CoinGate waits for a response for 20 seconds.\n\nPayment notification will be canceled and terminated if one of the following conditions occur:\n\n* Payment notification is sent 40 times.\n* 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\".\n* 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.\n* Payment notification is sent to TOR network.\n* Payment notification is sent to a private network, such as localhost.\n[block:api-header]\n{\n \"title\": \"IP Addresses\"\n}\n[/block]\nPayment Callback is sent from servers described in API endpoint. This API endpoint is public, authentication is not required.\nLive: https://api.coingate.com/v2/ips-v4\nSandbox: https://api-sandbox.coingate.com/v2/ips-v4\n\nEach 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.\n\nWe recommend update your IP whitelist from this API endpoint regularly.\n[block:api-header]\n{\n \"type\": \"basic\",\n \"title\": \"Private Nework & Localhost\"\n}\n[/block]\nCoinGate payment callback will not send notifications to private networks (for example: localhost).\nIn localhost, you can send test payment notification with [cURL library](https://curl.haxx.se/):\n[block:code]\n{\n \"codes\": [\n {\n \"code\": \"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\",\n \"language\": \"curl\"\n }\n ]\n}\n[/block]\n\n[block:api-header]\n{\n \"type\": \"basic\",\n \"title\": \"Payment Callback Logs\"\n}\n[/block]\nYou can review payment callbacks and your server response to callback in your account panel. Login to your account and locate API » Payment Callbacks.\n[block:api-header]\n{\n \"type\": \"basic\",\n \"title\": \"Accepting Payment Callback\"\n}\n[/block]\nExample: save the code below as `accept-coingate-callback.php` and execute cURL command in your command line tool:\n\n```\ncurl -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\n```\n[block:code]\n{\n \"codes\": [\n {\n \"code\": \"<?php\\n\\n// Your custom order_id is defined when you creating new order: https://developer.coingate.com/docs/create-order\\n// Also don't forget to prevent SQL injection\\n$result = mysql_query(\\\"SELECT * FROM orders WHERE id = \\\" . $_POST['order_id']);\\n$order = mysql_fetch_assoc($result);\\n\\n// token is your random secure string (for example: 5d02161be9bfb6192a33) for each order\\nif ($_POST['token'] == $order['token']) {\\n // Handle CoinGate order status: https://developer.coingate.com/docs/order-statuses\\n $status = NULL;\\n if ($_POST['status'] == 'paid') {\\n if ($_POST['price_amount'] >= $order['amount']) {\\n $status = 'paid';\\n }\\n }\\n else {\\n $status = $_POST['status'];\\n }\\n\\n if (!is_null($status)) {\\n mysql_query(\\\"UPDATE orders SET status = '\\\".$status.\\\"' WHERE id = \\\".$_POST['order_id']);\\n }\\n}\",\n \"language\": \"php\"\n },\n {\n \"code\": \"class CoingateCallbackController < ApplicationController\\n skip_before_action :verify_authenticity_token, only: :create\\n\\n def create\\n order = Order.find_by(id: params[:order_id])\\n\\n if order.present?\\n if params[:token].present? && order.token == params[:token]\\n status = nil\\n\\n if params[:status] == 'paid'\\n if params[:price].to_d >= order.amount # in addition you can check currency (params[:currency] == order.currency)\\n status = 'paid'\\n end\\n else\\n status = params[:status]\\n end\\n\\n if status.present?\\n order.update_attribute(:status, status)\\n end\\n end\\n end\\n end\\nend\",\n \"language\": \"ruby\",\n \"name\": \"Ruby on Rails\"\n }\n ]\n}\n[/block]","updates":["5aa277f59a7333003cc30725"],"order":5,"isReference":false,"hidden":false,"sync_unique":"","link_url":"","link_external":false,"_id":"5adcc1185cd1890003da8174","category":{"sync":{"isSync":false,"url":""},"pages":[],"title":"Payment Gateway","slug":"orders","order":2,"from_sync":false,"reference":false,"_id":"5adcc1185cd1890003da8167","version":"5adcc1185cd1890003da8165","project":"5530bfac57cea10d00a3aa3b","createdAt":"2015-08-18T18:14:59.726Z","__v":1},"user":"5530bf7457cea10d00a3aa3a","parentDoc":null,"project":"5530bfac57cea10d00a3aa3b","version":{"version":"2","version_clean":"2.0.0","codename":"","is_stable":true,"is_beta":false,"is_hidden":false,"is_deprecated":false,"categories":["5adcc1185cd1890003da8166","5adcc1185cd1890003da8167","5adcf4b3ce4b3f00035317e9","5adfb8e9452bd900036d115b","5e7b51281ac49702d745882c","5e7b526560c6cc004f25ca3e","61c47c8dc69d6b000f961812","62289a8cb831c9003650b36c","62615ded4828c0003015b8a2","627511250a8fbb052a794d80","62b43cee767dd2003ad59e14"],"_id":"5adcc1185cd1890003da8165","project":"5530bfac57cea10d00a3aa3b","createdAt":"2018-04-22T17:06:32.152Z","releaseDate":"2018-04-22T17:06:32.152Z","__v":10},"createdAt":"2015-08-19T09:17:13.529Z","githubsync":"","__v":0}