$method, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30 ]; if ($request !== null) { $options[CURLOPT_POSTFIELDS] = json_encode( $request, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES ); } curl_setopt_array($curl, $options); $response = curl_exec($curl); $status = (int) curl_getinfo($curl, CURLINFO_RESPONSE_CODE); if ($response === false) { $error = curl_error($curl); curl_close($curl); throw new RuntimeException('StarBonding request failed: ' . $error); } curl_close($curl); $result = json_decode($response, true, 512, JSON_THROW_ON_ERROR); if (!is_array($result) || !array_key_exists('success', $result)) throw new RuntimeException('Invalid StarBonding API response.'); if ($status < 200 || $status >= 300 || $result['success'] !== true) { $code = (string) ($result['error_code'] ?? 'HTTP_' . $status); $message = (string) ($result['error'] ?? 'StarBonding API request failed.'); throw new RuntimeException($code . ': ' . $message); } return $result['data']; } function starbonding_idempotency_key(string $operation): string { return $operation . '-' . bin2hex(random_bytes(16)); } /* Load this from protected server configuration. Never expose it to a browser. */ $api_key = getenv('STARBONDING_API_KEY'); if ($api_key === false || $api_key === '') throw new RuntimeException('STARBONDING_API_KEY is not configured.'); $operation = $argv[1] ?? ''; switch ($operation) { case 'services': $data = starbonding_request($api_key, 'GET', 'get.service.list.php'); foreach ($data['services'] as $service) { printf("%d %s %d paise\n", (int) $service['serviceid'], (string) $service['name'], (int) $service['amount_paise']); } break; case 'balance': $data = starbonding_request($api_key, 'GET', 'get.balance.php'); printf("Available: %d paise\n", (int) $data['available_paise']); break; case 'accounts': $page = isset($argv[2]) ? (int) $argv[2] : 1; if ($page < 1) throw new InvalidArgumentException('PAGE must be at least 1.'); $data = starbonding_request($api_key, 'GET', 'get.account.list.php?page=' . $page); foreach ($data['accounts'] as $account) { printf("%d %s %s %s\n", (int) $account['userid'], (string) $account['username'], (string) $account['service_name'], (string) $account['status']); } break; case 'transactions': $endpoint = 'get.transactions.php'; if (isset($argv[2])) $endpoint .= '?userid=' . (int) $argv[2]; $data = starbonding_request($api_key, 'GET', $endpoint); foreach ($data['transactions'] as $transaction) { printf("%d %s %d paise %s\n", (int) $transaction['transid'], (string) $transaction['recordtime'], (int) $transaction['amount_paise'], (string) $transaction['status']); } break; case 'create': if ($argc !== 6) throw new InvalidArgumentException( 'Usage: php partner-api.php create SERVICE_ID IDEMPOTENCY_KEY NAME EMAIL'); $data = starbonding_request($api_key, 'POST', 'create.account.php', [ 'serviceid' => (int) $argv[2], 'name' => $argv[4], 'email' => $argv[5] ], $argv[3]); printf("Created username %s, userid %d\n", (string) $data['account']['username'], (int) $data['account']['userid']); fprintf(STDERR, "Store the returned password securely; do not log it.\n"); break; case 'renew': if ($argc !== 5) throw new InvalidArgumentException( 'Usage: php partner-api.php renew USER_ID SERVICE_ID IDEMPOTENCY_KEY'); $data = starbonding_request($api_key, 'POST', 'renew.account.php', [ 'userid' => (int) $argv[2], 'serviceid' => (int) $argv[3] ], $argv[4]); printf("Renewed until %s\n", (string) $data['account']['validtill']); break; default: fwrite(STDERR, "Usage:\n" . " php partner-api.php services\n" . " php partner-api.php balance\n" . " php partner-api.php accounts [PAGE]\n" . " php partner-api.php transactions [USER_ID]\n" . " php partner-api.php create SERVICE_ID IDEMPOTENCY_KEY NAME EMAIL\n" . " php partner-api.php renew USER_ID SERVICE_ID IDEMPOTENCY_KEY\n"); exit(2); }