token = $token; $this->isLive = $isLive; // URLs from the OpenAPI spec $this->baseUrl = $this->isLive ? 'https://apis.usps.com/prices/v3' : 'https://apis-tem.usps.com/prices/v3'; } /** * Call Domestic Prices v3 API * Endpoint: /base-rates/search */ public function getDomesticRate($payload) { return $this->post('/base-rates/search', $payload); } /** * Call International Prices v3 API * Endpoint: /base-rates/search (Under International Base path) * Note: The spec shows a different base URL for International */ public function getInternationalRate($payload) { // International uses a different base URL structure in the spec $intlBaseUrl = $this->isLive ? 'https://apis.usps.com/international-prices/v3' : 'https://apis-tem.usps.com/international-prices/v3'; return $this->post('/base-rates/search', $payload, $intlBaseUrl); } private function post($endpoint, $payload, $overrideUrl = null) { $url = ($overrideUrl ? $overrideUrl : $this->baseUrl) . $endpoint; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $this->token, 'Content-Type: application/json', 'Accept: application/json' ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (curl_errno($ch)) { $error = curl_error($ch); return ['error' => 'CURL Error: ' . $error]; } $data = json_decode($response, true); // Check for HTTP errors (400, 401, 403, etc) if ($httpCode >= 400) { $msg = isset($data['error']['message']) ? $data['error']['message'] : 'Unknown Error'; if (isset($data['error']['errors'][0]['detail'])) { $msg .= ' - ' . $data['error']['errors'][0]['detail']; } return ['error' => "HTTP $httpCode: $msg"]; } return $data; } }