add vendor folder with coinify sdk files from 9569fa65fc1d65d62d78cf141a54e9ff053885d3
9569fa65fc/coinify_callback.py
https://raw.githubusercontent.com/CoinifySoftware/python-sdk/9569fa65fc1d65d62d78cf141a54e9ff053885d3/coinify_api.py
This commit is contained in:
parent
ce534cff55
commit
83ccef5c7d
0
vendor/__init__.py
vendored
Normal file
0
vendor/__init__.py
vendored
Normal file
268
vendor/coinfy_api.py
vendored
Normal file
268
vendor/coinfy_api.py
vendored
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
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
|
||||||
|
|
23
vendor/coinify_callback.py
vendored
Normal file
23
vendor/coinify_callback.py
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import hashlib, hmac
|
||||||
|
|
||||||
|
class CoinifyCallback:
|
||||||
|
"""
|
||||||
|
Class to validate callbacks from Coinfy
|
||||||
|
"""
|
||||||
|
|
||||||
|
ipn_secret = None
|
||||||
|
"""Coinify IPN callback secret. Get yours at https://www.coinify.com/merchant/ipn"""
|
||||||
|
|
||||||
|
def __init__( self, ipn_secret ):
|
||||||
|
self.ipn_secret = ipn_secret
|
||||||
|
|
||||||
|
def validate_callback( self, callback_raw, signature ):
|
||||||
|
"""
|
||||||
|
Validates a callback and it's signature based on the IPN secret given in the constructor.
|
||||||
|
|
||||||
|
callback_raw must contain the raw JSON POST data sent with the callback (before any JSON decoding)
|
||||||
|
signature must contain the signature as extracted from the 'X-Coinify-Callback-Signature' header,
|
||||||
|
which should be a 64-byte hexadecimal string
|
||||||
|
"""
|
||||||
|
return signature == hmac.new(self.ipn_secret, msg=callback_raw, digestmod=hashlib.sha256).hexdigest()
|
||||||
|
|
Loading…
Reference in a new issue