import hashlib, hmac, json, secrets, time from urllib import request, parse, error class PayIran: def __init__(self, api_key, api_secret, base_url='https://samanpay.org/v1'): self.api_key=api_key; self.api_secret=api_secret.encode(); self.base_url=base_url.rstrip('/') def _sign(self, method, path, body=''): ts=str(int(time.time())); nonce=secrets.token_hex(12) body_hash=hashlib.sha256(body.encode()).hexdigest() canonical='\n'.join([ts,nonce,method.upper(),path,body_hash]).encode() sig=hmac.new(self.api_secret,canonical,hashlib.sha256).hexdigest() return ts,nonce,sig def request(self, method, path, data=None, headers=None): body='' if data is None else json.dumps(data,separators=(',',':')) sign_path=path.split('?',1)[0] ts,nonce,sig=self._sign(method,sign_path,body) h={'Accept':'application/json','Content-Type':'application/json','X-PIS-Key':self.api_key, 'X-PIS-Timestamp':ts,'X-PIS-Nonce':nonce,'X-PIS-Signature-Version':'2','X-PIS-Signature':sig} h.update(headers or {}) req=request.Request(self.base_url+path,data=body.encode() if body else None,headers=h,method=method) try: with request.urlopen(req,timeout=20) as r: payload=json.loads(r.read()) except error.HTTPError as e: payload=json.loads(e.read()); raise RuntimeError(payload) return payload['data'] def create_payment(self,data,idempotency_key): return self.request('POST','/payments',data,{'Idempotency-Key':idempotency_key}) def get_payment(self,order_id): return self.request('GET','/payments/'+parse.quote(order_id,safe='')) def verify(self,order_id): return self.request('POST','/payments/verify',{'order_id':order_id}) def balance(self): return self.request('GET','/balance') def daily_summary(self,date=None): return self.request('GET','/daily-summary'+(('?date='+parse.quote(date)) if date else '')) def settlements(self): return self.request('GET','/settlements') def create_payout_request(self,data): return self.request('POST','/payout-requests',data) @staticmethod def verify_webhook(raw_body,timestamp,event_id,signature,webhook_secret,max_age=300): if abs(int(time.time())-int(timestamp))>max_age: return False msg=(str(timestamp)+'\n'+event_id+'\n'+raw_body).encode() expected='sha256='+hmac.new(webhook_secret.encode(),msg,hashlib.sha256).hexdigest() return hmac.compare_digest(expected,signature)