createInvoice('ORDER-1001', '10.50', ['callback_url'=>..., 'return_url'=>..., 'network'=>'TRC20']); * header('Location: ' . $inv['pay_url']); * * // callback.php * $event = $gw->verifyWebhook(); // throws on bad signature */ class UsdtGateway { private $base, $key, $secret; public function __construct($baseUrl, $apiKey, $apiSecret) { $this->base = rtrim($baseUrl, '/'); $this->key = $apiKey; $this->secret = $apiSecret; } /** amount STRING रखें, जैसे "10.50" (signature उसी string पर बनता है) */ public function createInvoice($orderId, $amount, array $opts = []) { $amount = (string)$amount; $f = ['api_key' => $this->key, 'order_id' => $orderId, 'amount' => $amount]; foreach (['network', 'callback_url', 'return_url', 'page'] as $k) if (!empty($opts[$k])) $f[$k] = $opts[$k]; $f['sign'] = hash_hmac('sha256', $this->key . '|' . $orderId . '|' . $amount, $this->secret); $r = $this->request('POST', '/api/create.php', $f); if (empty($r['success'])) throw new RuntimeException('Gateway: ' . ($r['error'] ?? 'unknown_error')); return $r; } public function getInvoice($invoiceId) { $q = http_build_query(['api_key' => $this->key, 'invoice_id' => $invoiceId, 'sign' => hash_hmac('sha256', $invoiceId, $this->secret)]); $r = $this->request('GET', '/api/status.php?' . $q); if (empty($r['success'])) throw new RuntimeException('Gateway: ' . ($r['error'] ?? 'unknown_error')); return $r; } /** Webhook verify: signature + timestamp (replay) check. सफल पर decoded array लौटाता है */ public function verifyWebhook($rawBody = null, $headers = null, $tolerance = 600) { $rawBody = $rawBody ?? file_get_contents('php://input'); $ts = $headers['X-Gateway-Timestamp'] ?? $_SERVER['HTTP_X_GATEWAY_TIMESTAMP'] ?? ''; $sig = $headers['X-Gateway-Signature'] ?? $_SERVER['HTTP_X_GATEWAY_SIGNATURE'] ?? ''; if (abs(time() - (int)$ts) > $tolerance) throw new RuntimeException('webhook_timestamp_out_of_range'); if (!hash_equals(hash_hmac('sha256', $ts . '.' . $rawBody, $this->secret), $sig)) throw new RuntimeException('webhook_bad_signature'); $d = json_decode($rawBody, true); if (!is_array($d)) throw new RuntimeException('webhook_bad_json'); return $d; } private function request($method, $path, array $fields = []) { $ch = curl_init($this->base . $path); $o = [CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => 20]; if ($method === 'POST') { $o[CURLOPT_POST] = 1; $o[CURLOPT_POSTFIELDS] = $fields; } curl_setopt_array($ch, $o); $raw = curl_exec($ch); $err = curl_error($ch); curl_close($ch); if ($raw === false) throw new RuntimeException('Gateway unreachable: ' . $err); $j = json_decode($raw, true); if (!is_array($j)) throw new RuntimeException('Gateway returned invalid response'); return $j; } }