PHP에서 cURL 확장 또는 Guzzle HTTP 클라이언트를 활용해 택배 조회 API를 연동하는 방법을 단계별로 안내합니다. 기본 cURL부터 Laravel 프레임워크 연동까지 다양한 환경에 맞는 예제를 제공합니다.

PHP 연동이 쉬운 이유
• PHP cURL은 대부분의 서버에 기본 설치됨 — 별도 라이브러리 없이 즉시 연동 가능
• Guzzle을 사용하면 더 깔끔한 코드 작성 가능
• Laravel HTTP 파사드로 프레임워크 네이티브 연동 지원

1. API 키 설정

API 키와 Secret Key는 회원가입 후 대시보드에서 발급받을 수 있습니다. 환경 변수 또는 설정 파일에 저장하세요.

# .env
DELIVERY_API_KEY=pk_live_xxxxxxxxxxxxxxxx
DELIVERY_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxx
<?php
// config.php
$apiKey = getenv('DELIVERY_API_KEY');
$secretKey = getenv('DELIVERY_SECRET_KEY');

// or load from .env file manually
// $apiKey = trim(file_get_contents(__DIR__ . '/.env.api_key'));
⚠️ Secret Key 보안 주의
Secret Key는 서버에서만 사용하세요. 프론트엔드 코드나 GitHub 등 공개 저장소에 노출되지 않도록 주의하세요. .env 파일은 반드시 .gitignore에 추가하세요.

2. cURL로 조회하기 (기본)

PHP에 기본 내장된 cURL 확장을 사용하는 가장 기본적인 방법입니다. 별도 라이브러리 설치 없이 바로 사용할 수 있습니다.

<?php
$apiKey = getenv('DELIVERY_API_KEY');
$secretKey = getenv('DELIVERY_SECRET_KEY');

$ch = curl_init('https://api.deliveryapi.co.kr/v1/tracking/trace');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer ' . $apiKey . ':' . $secretKey,
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'items' => [
            [
                'courierCode' => 'cj',
                'trackingNumber' => '1234567890',
            ],
        ],
    ]),
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);

3. 응답 처리

API 응답은 JSON 형식입니다. json_decode()로 파싱한 후 각 결과의 success 필드를 확인하세요.

<?php
// Check overall HTTP status
if ($httpCode !== 200) {
    echo "HTTP Error: " . $httpCode;
    exit;
}

// Check individual result
$result = $data['data']['results'][0];

if ($result['success']) {
    $tracking = $result['data'];
    echo "Status: " . $tracking['deliveryStatusText'] . "\n";    // "배송중"
    echo "Location: " . $tracking['progresses'][0]['location'];   // "서울 허브"
} else {
    echo "Error: " . $result['error']['code'];                    // "NOT_FOUND"
}

개별 조회 건이 실패해도 전체 HTTP 요청은 200으로 응답합니다. 반드시 result['success']로 건별 성공 여부를 확인하세요.

4. 다건 조회

items 배열에 여러 항목을 넣으면 한 번의 API 호출로 최대 50건까지 동시 조회할 수 있습니다. clientId에 주문번호를 넣으면 응답에서 쉽게 매칭할 수 있습니다.

<?php
$ch = curl_init('https://api.deliveryapi.co.kr/v1/tracking/trace');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer ' . $apiKey . ':' . $secretKey,
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'items' => [
            ['courierCode' => 'cj',     'trackingNumber' => '1111111111', 'clientId' => 'order_001'],
            ['courierCode' => 'lotte',  'trackingNumber' => '2222222222', 'clientId' => 'order_002'],
            ['courierCode' => 'hanjin', 'trackingNumber' => '3333333333', 'clientId' => 'order_003'],
        ],
    ]),
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
$summary = $data['data']['summary'];

echo "Total: {$summary['total']}, Success: {$summary['successful']}, Failed: {$summary['failed']}\n";

foreach ($data['data']['results'] as $result) {
    if ($result['success']) {
        echo "[{$result['clientId']}] {$result['data']['deliveryStatusText']}\n";
    }
}

5. Guzzle 사용하기

Guzzle은 PHP에서 가장 널리 사용되는 HTTP 클라이언트 라이브러리입니다. Composer로 설치하세요.

composer require guzzlehttp/guzzle
<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.deliveryapi.co.kr']);

$response = $client->post('/v1/tracking/trace', [
    'headers' => [
        'Authorization' => 'Bearer ' . $apiKey . ':' . $secretKey,
    ],
    'json' => [
        'items' => [
            ['courierCode' => 'cj', 'trackingNumber' => '1234567890'],
        ],
    ],
]);

$data = json_decode($response->getBody(), true);

Guzzle을 사용하면 json 옵션으로 자동 JSON 인코딩이 되어 코드가 한결 깔끔해집니다.

6. Laravel 연동

Laravel의 Http 파사드를 사용하면 프레임워크 스타일에 맞는 깔끔한 코드를 작성할 수 있습니다. API 키는 config/services.php에 설정하세요.

<?php
// app/Services/DeliveryService.php
namespace App\Services;

use Illuminate\Support\Facades\Http;

class DeliveryService
{
    private string $baseUrl = 'https://api.deliveryapi.co.kr';

    public function track(string $courierCode, string $trackingNumber): array
    {
        $apiKey = config('services.delivery.api_key');
        $secretKey = config('services.delivery.secret_key');

        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $apiKey . ':' . $secretKey,
        ])->post($this->baseUrl . '/v1/tracking/trace', [
            'items' => [
                [
                    'courierCode' => $courierCode,
                    'trackingNumber' => $trackingNumber,
                ],
            ],
        ]);

        return $response->json();
    }
}

// Usage in controller
// $service = new DeliveryService();
// $data = $service->track('cj', '1234567890');

7. 에러 처리

네트워크 오류, 인증 실패, 요청 한도 초과 등 다양한 에러 상황에 대비하세요. HTTP 상태 코드별로 적절히 처리하는 것이 중요합니다.

<?php
function trackPackage(string $courierCode, string $trackingNumber): array
{
    $apiKey = getenv('DELIVERY_API_KEY');
    $secretKey = getenv('DELIVERY_SECRET_KEY');

    $ch = curl_init('https://api.deliveryapi.co.kr/v1/tracking/trace');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $apiKey . ':' . $secretKey,
        ],
        CURLOPT_POSTFIELDS => json_encode([
            'items' => [
                ['courierCode' => $courierCode, 'trackingNumber' => $trackingNumber],
            ],
        ]),
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);
    curl_close($ch);

    // Network error
    if ($curlError) {
        throw new \RuntimeException('cURL error: ' . $curlError);
    }

    // HTTP error handling
    switch ($httpCode) {
        case 200:
            return json_decode($response, true);
        case 401:
            throw new \RuntimeException('Authentication failed — check API keys');
        case 429:
            throw new \RuntimeException('Rate limit exceeded — retry later');
        default:
            throw new \RuntimeException("HTTP error: {$httpCode}");
    }
}

다음 단계

지금 바로 시작하세요!

무료 플랜으로 월 30,000건까지 사용 가능합니다.

무료로 시작하기 →