269 lines
8.8 KiB
Python
269 lines
8.8 KiB
Python
|
import requests, json, time, hashlib, hmac
|
||
|
|
||
|
|
||
|
class CoinifyAPI:
|
||
|
api_key = None
|
||
|
"""Coinify API key. Get yours at https://www.coinify.com/merchant/api"""
|
||
|
|
||
|
api_secret = None
|
||
|
"""Coinify API secret. Get yours at https://www.coinify.com/merchant/api"""
|
||
|
|
||
|
api_base_url = None
|
||
|
"""Base URL to the Coinify API"""
|
||
|
|
||
|
API_DEFAULT_BASE_URL = "https://api.coinify.com"
|
||
|
|
||
|
def __init__(self, api_key=None, api_secret=None, api_base_url=None):
|
||
|
"""
|
||
|
Create an instance of the CoinifyAPI class.
|
||
|
Provide your API key and API secret.
|
||
|
|
||
|
Set api_base_url to None to use default
|
||
|
"""
|
||
|
self.api_key = api_key
|
||
|
self.api_secret = api_secret
|
||
|
self.api_base_url = api_base_url or self.API_DEFAULT_BASE_URL
|
||
|
|
||
|
def invoices_list(self, limit=None, offset=None, include_expired=None):
|
||
|
"""
|
||
|
Returns an array of your Coinify invoices
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#list-all-invoices
|
||
|
"""
|
||
|
query_params = {}
|
||
|
|
||
|
if limit is not None:
|
||
|
query_params['limit'] = limit
|
||
|
if offset is not None:
|
||
|
query_params['offset'] = offset
|
||
|
if include_expired is not None:
|
||
|
query_params['include_expired'] = include_expired
|
||
|
|
||
|
return self.call_api_authenticated('/v3/invoices', query_params=query_params)
|
||
|
|
||
|
def invoice_create(self, amount, currency, plugin_name, plugin_version,
|
||
|
description=None, custom=None, callback_url=None, callback_email=None,
|
||
|
return_url=None, cancel_url=None, input_currency=None, input_return_address=None):
|
||
|
|
||
|
"""
|
||
|
Create a new invoice.
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#create-an-invoice
|
||
|
"""
|
||
|
params = {
|
||
|
'amount': amount,
|
||
|
'currency': currency,
|
||
|
'plugin_name': plugin_name,
|
||
|
'plugin_version': plugin_version
|
||
|
}
|
||
|
|
||
|
if description is not None:
|
||
|
params['description'] = description
|
||
|
if custom is not None:
|
||
|
params['custom'] = custom
|
||
|
if callback_url is not None:
|
||
|
params['callback_url'] = callback_url
|
||
|
if callback_email is not None:
|
||
|
params['callback_email'] = callback_email
|
||
|
if return_url is not None:
|
||
|
params['return_url'] = return_url
|
||
|
if cancel_url is not None:
|
||
|
params['cancel_url'] = cancel_url
|
||
|
if input_currency is not None:
|
||
|
params['input_currency'] = input_currency
|
||
|
if input_return_address is not None:
|
||
|
params['input_return_address'] = input_return_address
|
||
|
|
||
|
return self.call_api_authenticated('/v3/invoices', 'POST', params)
|
||
|
|
||
|
def invoice_get(self, invoice_id):
|
||
|
"""
|
||
|
Get a specific invoice
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#get-a-specific-invoice
|
||
|
"""
|
||
|
path = '/v3/invoices/%d' % (invoice_id,)
|
||
|
|
||
|
return self.call_api_authenticated(path)
|
||
|
|
||
|
def invoice_update(self, invoice_id, description=None, custom=None):
|
||
|
"""
|
||
|
Update the description and custom data of an invoice
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#update-an-invoice
|
||
|
"""
|
||
|
params = {}
|
||
|
|
||
|
if description is not None:
|
||
|
params['description'] = description
|
||
|
if custom is not None:
|
||
|
params['custom'] = custom
|
||
|
|
||
|
path = '/v3/invoices/%d' % (invoice_id,)
|
||
|
|
||
|
return self.call_api_authenticated(path, 'PUT', params)
|
||
|
|
||
|
def invoice_input_create(self, invoice_id, currency, return_address):
|
||
|
"""
|
||
|
Request for an invoice to be paid with another input currency.
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#pay-with-another-input-currency
|
||
|
"""
|
||
|
params = {
|
||
|
'currency': currency,
|
||
|
'return_address': return_address
|
||
|
}
|
||
|
|
||
|
path = '/v3/invoices/%d/inputs' % (invoice_id,)
|
||
|
|
||
|
return self.call_api_authenticated(path, 'POST', params)
|
||
|
|
||
|
def buy_orders_list(self, limit=None, offset=None, include_cancelled=None):
|
||
|
"""
|
||
|
Returns an array of your Coinify buy orders
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#list-all-buy-orders
|
||
|
"""
|
||
|
|
||
|
query_params = {}
|
||
|
|
||
|
if limit is not None:
|
||
|
query_params['limit'] = limit
|
||
|
if offset is not None:
|
||
|
query_params['offset'] = offset
|
||
|
if include_cancelled is not None:
|
||
|
query_params['include_cancelled'] = include_cancelled
|
||
|
|
||
|
return self.call_api_authenticated('/v3/buys', query_params=query_params)
|
||
|
|
||
|
def buy_order_create(self, amount, currency, btc_address, instant_order=None,
|
||
|
callback_url=None, callback_email=None):
|
||
|
"""
|
||
|
Create a new buy order
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#create-a-buy-order
|
||
|
"""
|
||
|
params = {
|
||
|
'amount': amount,
|
||
|
'currency': currency,
|
||
|
'btc_address': btc_address
|
||
|
}
|
||
|
|
||
|
if instant_order is not None:
|
||
|
params['instant_order'] = instant_order
|
||
|
if callback_url is not None:
|
||
|
params['callback_url'] = callback_url
|
||
|
if callback_email is not None:
|
||
|
params['callback_email'] = callback_email
|
||
|
|
||
|
return self.call_api_authenticated('/v3/buys', 'POST', params)
|
||
|
|
||
|
def buy_order_confirm(self, buy_order_id):
|
||
|
"""
|
||
|
Confirm a buy order
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#buy-order-confirm
|
||
|
"""
|
||
|
path = '/v3/buys/%d/actions/confirm' % (buy_order_id,)
|
||
|
|
||
|
return self.call_api_authenticated(path, 'PUT')
|
||
|
|
||
|
def buy_order_get(self, buy_order_id):
|
||
|
"""
|
||
|
Get a specific buy order
|
||
|
|
||
|
See https://www.coinify.com/docs/api/#get-a-specific-buy-order
|
||
|
"""
|
||
|
path = '/v3/buys/%d' % (buy_order_id,)
|
||
|
|
||
|
return self.call_api_authenticated(path)
|
||
|
|
||
|
def rates_get(self, currency=None):
|
||
|
"""
|
||
|
Return buy and sell rates for all available currencies or for the specified currency.
|
||
|
:param self:
|
||
|
:param currency|None: A 3-char currency code
|
||
|
:return:
|
||
|
"""
|
||
|
if currency is None:
|
||
|
path = '/v3/rates'
|
||
|
else:
|
||
|
path = '/v3/rates/%s' % (currency,)
|
||
|
|
||
|
return self.call_api_authenticated(path)
|
||
|
|
||
|
def balance_get(self):
|
||
|
"""
|
||
|
Get the balance of a merchant
|
||
|
:param path:
|
||
|
:return: An array as described in https://www.coinify.com/docs/api/#check-account-balance . If success,
|
||
|
then the 'data' value contains the balance in BTC and fiat currency and also the base currency
|
||
|
of the merchant that requests it.
|
||
|
"""
|
||
|
path = '/v3/balance'
|
||
|
return self.call_api_authenticated(path)
|
||
|
|
||
|
def input_currencies_list(self):
|
||
|
"""
|
||
|
Receive a list of supported input currencies
|
||
|
"""
|
||
|
|
||
|
return self.call_api('/v3/input-currencies')
|
||
|
|
||
|
def call_api_authenticated(self, path, method='GET', params={}, query_params={}):
|
||
|
"""
|
||
|
Perform an authenticated API call, using the
|
||
|
API key and secret provided in the constructor.
|
||
|
|
||
|
path: API path, WITH a leading slash, e.g. '/v3/invoices'
|
||
|
params: dict with parameters to send with the API call
|
||
|
|
||
|
Returns a dict as described in https://www.coinify.com/docs/api/#response-format,
|
||
|
or None if the HTTP call couldn't be performed correctly.
|
||
|
"""
|
||
|
extra_headers = {
|
||
|
'Authorization': self.generate_authorization_header()
|
||
|
}
|
||
|
|
||
|
return self.call_api(path, method, params, query_params, extra_headers)
|
||
|
|
||
|
def call_api(self, path, method='GET', params={}, query_params={}, headers={}):
|
||
|
"""
|
||
|
Perform an API call
|
||
|
|
||
|
path: API path, WITH a leading slash, e.g. '/v3/invoices'
|
||
|
params: dict with parameters to send with the API call
|
||
|
|
||
|
Returns a dict as described in https://www.coinify.com/docs/api/#response-format,
|
||
|
or None if the HTTP call couldn't be performed correctly.
|
||
|
"""
|
||
|
url = self.api_base_url + path
|
||
|
|
||
|
headers['Content-Type'] = 'application/json'
|
||
|
|
||
|
if self.api_key is not None:
|
||
|
headers['Authorization'] = self.generate_authorization_header()
|
||
|
|
||
|
r = requests.request(method, url, json=params, headers=headers, params=query_params)
|
||
|
return r.json()
|
||
|
|
||
|
def generate_authorization_header(self):
|
||
|
"""
|
||
|
Generate a nonce and a signature for an API call
|
||
|
and wrap those in a HTTP header
|
||
|
"""
|
||
|
# Generate nonce, based on the current Unix timestamp
|
||
|
nonce = str(int(time.time() * 1000000))
|
||
|
|
||
|
# Concatenate nonce and API key
|
||
|
message = nonce + self.api_key
|
||
|
|
||
|
# Compute signature
|
||
|
signature = hmac.new(self.api_secret, msg=message, digestmod=hashlib.sha256).hexdigest()
|
||
|
|
||
|
# Construct the header value
|
||
|
header_value = 'Coinify apikey="%s", nonce="%s", signature="%s"' % (self.api_key, nonce, signature)
|
||
|
|
||
|
return header_value
|
||
|
|