Header

All private REST requests must contain the following headers:

CF-API-KEY The api key as a string.
CF-API-TIMESTAMP A timestamp for your request, 10 digital.
CF-API-SIGNATURE The signature for your request (see Signing a Message).

All request bodies should have 'Content-Type': 'application/json' and be valid JSON.

require 'awesome_print'
require 'rest-client'
require 'json'
require 'pry'

class CoinfalconExchange
  def initialize(key, secret)
    @key = key
    @secret = secret
    @end_point = 'https://coinfalcon.com/api/v1/'
  end

  def headers(request_path, body, method)
    timestamp = Time.now.to_i
    signature = get_signature(timestamp, request_path, body, method)
    ap signature
    {
        "CF-API-KEY" => @key,
        "CF-API-TIMESTAMP" => timestamp,
        "CF-API-SIGNATURE" => signature
    }
  end

  def get_signature(timestamp, request_path='', body={}, method='GET')
    # Example for get
    # request_path = '/api/v1/user/orders'
    # timestamp = 1513411769
    # method = 'GET'
    # payload = '1513411769|GET|/api/v1/user/orders'

    # Example for post
    # request_path = '/api/v1/user/orders'
    # timestamp = 1513411657
    # method = 'POST'
    # body {market: 'IOT-BTC', operation_type: 'market_order', order_type: 'buy', size: '1'}
    # payload = '1513411657|POST|/api/v1/user/orders|{"market":"IOT-BTC","operation_type":"market_order","order_type":"buy","size":"1"}'

    if method == 'GET'
      payload = [timestamp, method, request_path].join("|")
    else
      body = URI.unescape(body.to_json) if body.is_a?(Hash)
      payload = [timestamp, method, request_path, body].join("|")
    end

    puts payload
    # create a sha256 hmac with the secret
    OpenSSL::HMAC.hexdigest('sha256', @secret, payload)
  end

  def accounts
    url = @end_point + "user/accounts"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def fees
    url = @end_point + "user/fees"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def orderbook(market)
    url = @end_point + "markets/#{market}/orders"
    JSON.parse(RestClient.get(url).body)
  end

  def my_orders
    url = @end_point + "user/orders"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def my_trades(market, since = nil)
    url = @end_point + "user/trades?market=#{market}"
    url += "&since_time=#{URI.encode_www_form_component(since)}" if !since.nil?
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def create_order(body)
    url = @end_point + "user/orders"
    result = RestClient.post(url, body,headers(URI(url).request_uri, body, 'POST'))
    JSON.parse(result.body)
  end

  def order(id)
    url = @end_point + "user/orders/#{id}"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def order_trades(id)
    url = @end_point + "user/orders/#{id}/trades"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def cancel_order(id)
    url = @end_point + "user/orders/#{id}"
    begin
      result = RestClient.delete(url, headers(URI(url).request_uri, {}, 'DELETE'))
      JSON.parse(result.body)
    rescue RestClient::ExceptionWithResponse => e
      JSON.parse(e.response.body)
    end
  end

  def deposit_address(currency)
    url = @end_point + "account/deposit_address?currency=#{currency}"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def deposits(query = {})
    url = @end_point + "account/deposits?#{URI.encode_www_form(query)}".chomp('?')
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def deposit(id)
    url = @end_point + "account/deposit/#{id}"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def create_withdrawal(body)
    url = @end_point + "account/withdraw"
    result = RestClient.post(url, body,headers(URI(url).request_uri, body, 'POST'))
    JSON.parse(result.body)
  end

  def withdrawals(query = {})
    url = @end_point + "account/withdrawals?#{URI.encode_www_form(query)}".chomp('?')
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def withdrawal(id)
    url = @end_point + "account/withdrawal?id=#{id}"
    result = RestClient.get(url, headers(URI(url).request_uri, {}, 'GET'))
    JSON.parse(result.body)
  end

  def cancel_withdrawal(id)
    url = @end_point + "account/withdrawals/#{id}"
    result = RestClient.delete(url, headers(URI(url).request_uri, {}, 'DELETE'))
    JSON.parse(result.body)
  end

end

client = CoinfalconExchange.new('YOUR_KEY', 'YOUR_SECRET')

# ap client.fees
# ap client.orderbook('IOT-BTC')
# ap client.my_orders
# ap client.my_trades('IOT-BTC', '2018-03-19T12:48:38')
# ap client.accounts
# ap client.create_order({market: 'BTC-EUR', operation_type: 'market_order', order_type: 'sell', size: '0.01'})
# ap client.order(result['data']['id'])
# ap client.cancel_order('be10a14d-56ba-43d7-8adc-21fca4b317df')
# ap client.order_trades("032bcc91-a387-408b-b75d-f2ec249d5a9d")
# ap client.deposit_address('btc')
# ap client.deposit_address('xrp')
# ap client.create_withdrawal({tag: '123456', amount: '100', address: 'rsBsUMJ41T7vrTGEmspNXGYR4MuUedeKiL', currency: 'xrp'})
# ap client.withdrawal('9b25877a-35ae-4812-8d89-953ed4c55094')
# ap client.withdrawals(currency: 'btc', status: 'completed')
# ap client.cancel_withdrawal(result['data']['id'])
# ap client.deposits(currency: 'btc', status: 'completed')
# ap client.deposit('e30a3ac8-33b1-46ed-8f54-1112417de581')
# -*- coding: utf-8 -*-

import hashlib
import requests
import urllib
import urllib.parse
import json
import hmac
import time

class Coinfalcon():

    def __init__(self, key, secret):
        self.key = key
        self.secret = secret
        self.endpoint = 'https://coinfalcon.com/api/v1'

    def request_path(self, url):
        query = urllib.parse.urlparse(url).query
        if query == '':
            return urllib.parse.urlparse(url).path
        return urllib.parse.urlparse(url).path + '?' + query

    def get_headers(self, method, request_path, body={}):
        timestamp = str(int(time.time()))

        if method == 'GET':
            payload = '|'.join([timestamp, method, request_path])
        else:
            payload = '|'.join([timestamp, method, request_path, json.dumps(body, separators=(',', ':'))])

        print(payload)
        message = bytes(payload, 'utf-8')
        secret = bytes(self.secret, 'utf-8')

        signature = hmac.new(secret, message, hashlib.sha256).hexdigest()
        return {
            "CF-API-KEY": self.key,
            "CF-API-TIMESTAMP": timestamp,
            "CF-API-SIGNATURE": signature
        }

    def create_order(self, body):
        url = self.endpoint + "/user/orders"
        headers = self.get_headers('POST', urllib.parse.urlparse(url).path, body)
        return requests.post(url, headers=headers, data=body).json()

    def cancel_order(self, id):
        url = self.endpoint + "/user/orders/{}".format(id)
        print(url)
        headers = self.get_headers('DELETE', urllib.parse.urlparse(url).path, {})
        return requests.delete(url, headers=headers).json()

    def my_orders(self):
        url = self.endpoint + "/user/orders"
        headers = self.get_headers('GET', urllib.parse.urlparse(url).path)
        return requests.get(url, headers=headers).json()

    def deposit_address(self, currency):
        url = self.endpoint + "/account/deposit_address?currency={}".format(currency)
        headers = self.get_headers('GET', self.request_path(url))
        return requests.get(url, headers=headers).json()

    def orderbook(self, market):
        url = self.endpoint + "/markets/{}/orders".format(market)
        print(url)
        print(requests.get(url).text)
        return requests.get(url).json()

client = Coinfalcon('YOUR_KEY', 'YOUR_SECRET')
# print(client.orderbook('IOT-BTC'))
# print(client.my_orders())
# result = client.create_order({'market': 'BTC-EUR', 'operation_type': 'market_order', 'order_type': 'sell', 'size': '0.1'})
# print(result)
# print(client.cancel_order(result['data']['id']))
# print(client.deposit_address('btc'))

Signing a message

The CF-API-SIGNATURE header is generated by creating a sha256 HMAC using the secret key on the prehash string. If get, use timestamp|method|requestPath. If post, use timestamp|method|requestPath|body.to_json.

🚧

The timestamp only 10 digital, not 13, same value as CF-API-TIMESTAMP.

🚧

The method should be UPPER CASE, for example, GET.

🚧

The requestPath doesn't contain the host, for example, /api/v1/user/orders.

👍

Example for GET

timestamp = 1513411769
method = 'GET'
request_path = '/api/v1/user/orders?market=BTC-EUR'

# payload = '1513411769|GET|/api/v1/user/orders?market=BTC-EUR'
payload = "#{timestamp}|#{method}|#{request_path}"

👍

Example for POST

timestamp = 1513411657
method = 'POST'
request_path = '/api/v1/user/orders'

body = { market: 'IOT-BTC', operation_type: 'market_order', order_type: 'buy', size: '1' }

# payload = '1513411657|POST|/api/v1/user/orders|{"market":"IOT-BTC","operation_type":"market_order","order_type":"buy","size":"1"}'
payload = "#{timestamp}|#{method}|#{request_path}|#{body}"