true, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 45, CURLOPT_FOLLOWLOCATION => false, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_HTTPHEADER => [ 'Accept: application/json', 'X-VR-Key: ' . $key, 'X-VR-Timestamp: ' . $timestamp, 'X-VR-Nonce: ' . $nonce, 'X-VR-Signature-Version: 2', 'X-VR-Signature: ' . $signature, ], ]); $raw = curl_exec($ch); $httpStatus = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); $transportError = curl_error($ch); curl_close($ch); if ($raw === false) throw new RuntimeException($transportError); $result = json_decode($raw, true, 512, JSON_THROW_ON_ERROR); if ($httpStatus !== 200 || empty($result['ok'])) { throw new RuntimeException('HTTP ' . $httpStatus . ': ' . ($result['error']['code'] ?? 'request_failed')); } // Upsert local billing products by supplier_pid; keep every offered cycle. $products = []; foreach ($result['plans'] as $plan) { $products[] = [ 'supplier_pid' => (int) $plan['pid'], 'name' => $plan['name'], 'group' => $plan['group'], 'prices' => $plan['prices'], 'provisioning' => $plan['provisioning'], ]; } echo json_encode(['currency' => $result['currency'], 'products' => $products], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . PHP_EOL;