baseUrl=rtrim($this->baseUrl,'/'); } private function sign(string $method,string $path,string $body=''): array { $ts=(string)time(); $nonce=bin2hex(random_bytes(12)); $canonical=$ts."\n".$nonce."\n".strtoupper($method)."\n".$path."\n".hash('sha256',$body); return [$ts,$nonce,hash_hmac('sha256',$canonical,$this->apiSecret)]; } public function request(string $method,string $path,?array $data=null,array $extraHeaders=[]): array { $body=$data===null?'':json_encode($data,JSON_UNESCAPED_SLASHES); $signPath=explode('?',$path,2)[0]; [$ts,$nonce,$sig]=$this->sign($method,$signPath,$body); $headers=array_merge([ 'Accept: application/json','Content-Type: application/json', 'X-PIS-Key: '.$this->apiKey,'X-PIS-Timestamp: '.$ts,'X-PIS-Nonce: '.$nonce, 'X-PIS-Signature-Version: 2','X-PIS-Signature: '.$sig, ],$extraHeaders); $ch=curl_init($this->baseUrl.$path); curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_CUSTOMREQUEST=>$method,CURLOPT_HTTPHEADER=>$headers,CURLOPT_TIMEOUT=>20]); if($body!=='')curl_setopt($ch,CURLOPT_POSTFIELDS,$body); $raw=curl_exec($ch); $status=(int)curl_getinfo($ch,CURLINFO_RESPONSE_CODE); curl_close($ch); $json=json_decode((string)$raw,true); if($status<200||$status>=300)throw new RuntimeException(json_encode($json,JSON_UNESCAPED_UNICODE)); return $json['data']??[]; } public function createPayment(array $data,string $idempotencyKey): array {return $this->request('POST','/payments',$data,['Idempotency-Key: '.$idempotencyKey]);} public function getPayment(string $orderId): array {return $this->request('GET','/payments/'.rawurlencode($orderId));} public function verify(string $orderId): array {return $this->request('POST','/payments/verify',['order_id'=>$orderId]);} public function balance(): array {return $this->request('GET','/balance');} public function settlements(): array {return $this->request('GET','/settlements');} public static function verifyWebhook(string $rawBody,string $timestamp,string $eventId,string $signature,string $webhookSecret,int $maxAge=300): bool { if(abs(time()-(int)$timestamp)>$maxAge)return false; $expected='sha256='.hash_hmac('sha256',$timestamp."\n".$eventId."\n".$rawBody,$webhookSecret); return hash_equals($expected,$signature); } }