웹훅 API - WhereParcel
실시간 택배 추적 업데이트를 웹훅으로 자동 수신. 배송 상태 변경 시 즉시 알림. 자동 재시도 및 이벤트 필터링 지원.
/v2/webhooks/register 웹훅 등록 (과금 대상)
개요
택배 추적을 위한 웹훅을 등록합니다. 2가지 모드를 지원합니다:
- recurring: true - 배송 완료까지 계속 모니터링 (구독형)
- recurring: false - 1회만 조회 (일회성, 기본값) 과금 대상 API이며, 최대 500건까지 한 번에 등록 가능합니다.
요청 예제
curl -X POST https://api.whereparcel.com/v2/webhooks/register \
-H "Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production" \
-H "Content-Type: application/json" \
-d '{
"trackingItems": [
{
"carrier": "kr.cj",
"trackingNumber": "123456789012",
"clientId": "order-001"
}
],
"recurring": true,
"webhookEndpointId": "endpoint-id-123"
}'const response = await fetch('https://api.whereparcel.com/v2/webhooks/register', {
method: 'POST',
headers: {
"Authorization": "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production",
"Content-Type": "application/json"
},
body: JSON.stringify({
"trackingItems": [
{
"carrier": "kr.cj",
"trackingNumber": "123456789012",
"clientId": "order-001"
}
],
"recurring": true,
"webhookEndpointId": "endpoint-id-123"
})
});
const data = await response.json();
console.log(data);<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereparcel.com/v2/webhooks/register');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$headers = [
'Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = [
'trackingItems' => [
'0' => [
'carrier' => "kr.cj",
'trackingNumber' => "123456789012",
'clientId' => "order-001"
]
],
'recurring' => true,
'webhookEndpointId' => "endpoint-id-123"
];
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);import requests
import json
url = 'https://api.whereparcel.com/v2/webhooks/register'
headers = {
'Authorization': 'Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type': 'application/json'
}
data = {
'trackingItems': {
'0': {
'carrier': "kr.cj",
'trackingNumber': "123456789012",
'clientId': "order-001"
}
},
'recurring': True,
'webhookEndpointId': "endpoint-id-123"
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.whereparcel.com/v2/webhooks/register"
payload := []byte(`{"trackingItems":[{"carrier":"kr.cj","trackingNumber":"123456789012","clientId":"order-001"}],"recurring":true,"webhookEndpointId":"endpoint-id-123"}`)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
req.Header.Add("Authorization", "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}요청 본문
| Name | Type | Required | Description |
|---|---|---|---|
trackingItems | array | Required | 추적 항목 (최대 500개) |
trackingItems[].carrier | string | Required | |
trackingItems[].trackingNumber | string | Required | |
trackingItems[].clientId | string | Optional | |
recurring | boolean | Optional | ⭐ 추적 모드 (선택적, 기본값: false)
- false: 1회만 조회 (기본값, 안전함) → webhookEndpointId 선택적
- true: 계속 모니터링 (명시적 요청 필요) → webhookEndpointId 필수 |
webhookEndpointId | string | Optional | 사전 등록된 Webhook Endpoint ID
- recurring: true일 때 필수 (미들웨어 검증)
- recurring: false일 때 선택적
- 있으면 완료 시 POST 전송, 없으면 전송 안함
- 먼저 Webhook Endpoint를 등록해야 함 |
응답
성공 응답 (200)
웹훅 등록 성공
Response Body
{
"success": true,
"requestId": "req_abc123xyz",
"subscriptionId": "sub_def456uvw",
"status": "active",
"message": "Webhook registered successfully (recurring mode)"
} 오류 응답 (401)
인증 실패
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} 오류 응답 (429)
요청 한도 초과
Response Body
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later."
}
} /v2/webhooks/subscriptions 웹훅 구독 목록 조회
개요
등록한 모든 웹훅 구독(구독형 + 일회성)을 조회합니다. 무료 API로 사용량이 차감되지 않습니다.
요청 예제
curl -X GET https://api.whereparcel.com/v2/webhooks/subscriptions \
-H "Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production" \
-H "Content-Type: application/json"const response = await fetch('https://api.whereparcel.com/v2/webhooks/subscriptions', {
method: 'GET',
headers: {
"Authorization": "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data);<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereparcel.com/v2/webhooks/subscriptions');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$headers = [
'Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);import requests
import json
url = 'https://api.whereparcel.com/v2/webhooks/subscriptions'
headers = {
'Authorization': 'Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
result = response.json()
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.whereparcel.com/v2/webhooks/subscriptions"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}응답
성공 응답 (200)
구독 목록 조회 성공
Response Body
[
{
"requestId": "req_abc123xyz",
"trackingItemCount": 2,
"trackingItems": [
{
"carrier": "kr.cj",
"trackingNumber": "300718039335",
"clientId": "order-001",
"latestStatus": "delivered"
},
{
"carrier": "kr.lotte",
"trackingNumber": "410259694563",
"latestStatus": "in_transit"
}
],
"recurring": true,
"webhookEndpointId": "endpoint_xyz789",
"isActive": true,
"createdAt": "2026-02-05T10:00:00.000Z",
"updatedAt": "2026-02-05T14:30:00.000Z"
},
{
"requestId": "req_def456uvw",
"trackingItemCount": 1,
"trackingItems": [
{
"carrier": "kr.post",
"trackingNumber": "1234567890123",
"latestStatus": "out_for_delivery"
}
],
"recurring": false,
"isActive": false,
"progress": {
"total": 1,
"completed": 1,
"succeeded": 1,
"failed": 0,
"percentage": 100
},
"createdAt": "2026-02-04T09:00:00.000Z",
"updatedAt": "2026-02-04T09:05:00.000Z",
"completedAt": "2026-02-04T09:05:00.000Z"
}
] 오류 응답 (401)
인증 실패
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} /v2/webhooks/subscriptions/{requestId} 단일 웹훅 구독 조회
개요
특정 requestId의 웹훅 구독 정보를 조회합니다. 무료 API로 사용량이 차감되지 않습니다.
요청 예제
curl -X GET https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId} \
-H "Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production" \
-H "Content-Type: application/json"const response = await fetch('https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}', {
method: 'GET',
headers: {
"Authorization": "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data);<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$headers = [
'Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);import requests
import json
url = 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}'
headers = {
'Authorization': 'Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
result = response.json()
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}경로 매개변수
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>웹훅 등록 시 받은 requestId</p>
Example: req_abc123xyz |
응답
성공 응답 (200)
구독 정보 조회 성공
Response Body
{
"success": true,
"data": {
"requestId": "req_abc123xyz",
"trackingItemCount": 1,
"trackingItems": [
{
"carrier": "kr.cj",
"trackingNumber": "123456789012",
"latestStatus": "in_transit"
}
],
"recurring": true,
"webhookEndpointId": "endpoint-id-123",
"isActive": true,
"createdAt": "2026-02-05T10:00:00.000Z",
"updatedAt": "2026-02-05T10:00:00.000Z"
}
} 오류 응답 (401)
인증 실패
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} 오류 응답 (404)
requestId를 찾을 수 없음
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/subscriptions/{requestId} 웹훅 구독 삭제
개요
웹훅 구독을 취소하고 모니터링을 중지합니다. 구독형(recurring) 웹훅의 경우 즉시 중지됩니다. 무료 API로 사용량이 차감되지 않습니다.
요청 예제
curl -X DELETE https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId} \
-H "Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production" \
-H "Content-Type: application/json"const response = await fetch('https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}', {
method: 'DELETE',
headers: {
"Authorization": "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data);<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$headers = [
'Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);import requests
import json
url = 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}'
headers = {
'Authorization': 'Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type': 'application/json'
}
response = requests.delete(url, headers=headers)
result = response.json()
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("Authorization", "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}경로 매개변수
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>삭제할 웹훅의 requestId</p>
Example: req_abc123xyz |
응답
성공 응답 (200)
구독 삭제 성공
Response Body
{
"deleted": true,
"requestId": "req_abc123xyz",
"message": "Webhook subscription deleted successfully"
} 오류 응답 (401)
인증 실패
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} 오류 응답 (404)
requestId를 찾을 수 없음
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/subscriptions/{requestId}/changes 웹훅 변경 이력 조회
개요
특정 웹훅 구독의 모든 변경 이력(배송 상태 변경)을 조회합니다. 무료 API로 사용량이 차감되지 않습니다.
요청 예제
curl -X GET https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes \
-H "Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production" \
-H "Content-Type: application/json"const response = await fetch('https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes', {
method: 'GET',
headers: {
"Authorization": "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data);<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$headers = [
'Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);import requests
import json
url = 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes'
headers = {
'Authorization': 'Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
result = response.json()
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}경로 매개변수
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>웹훅 등록 시 받은 requestId</p>
Example: req_abc123xyz |
응답
성공 응답 (200)
변경 이력 조회 성공
Response Body
{
"events": [
{
"eventId": "evt_abc123",
"requestId": "req_abc123xyz",
"webhookUrl": "https://myapp.com/webhooks/whereparcel",
"event": "status.changed",
"payload": {
"trackingNumber": "300718039335",
"carrier": {
"code": "kr.cj",
"name": "CJ대한통운"
},
"previousStatus": "in_transit",
"currentStatus": "out_for_delivery",
"trackingData": {
"carrier": "kr.cj",
"carrierName": "CJ대한통운",
"trackingNumber": "300718039335",
"status": "out_for_delivery",
"statusText": "배달 출발",
"events": [
{
"timestamp": "2026-02-05T09:15:00+09:00",
"status": "out_for_delivery",
"statusText": "배달 출발",
"location": "서울 강남구 센터"
}
]
},
"timestamp": "2026-02-05T09:15:00+09:00"
},
"status": "delivered",
"deliveryAttempts": 1,
"createdAt": "2026-02-05T09:15:00.000Z",
"updatedAt": "2026-02-05T09:16:00.000Z"
},
{
"eventId": "evt_def456",
"requestId": "req_abc123xyz",
"webhookUrl": "https://myapp.com/webhooks/whereparcel",
"event": "status.delivered",
"payload": {
"trackingNumber": "300718039335",
"carrier": {
"code": "kr.cj",
"name": "CJ대한통운"
},
"previousStatus": "out_for_delivery",
"currentStatus": "delivered",
"trackingData": {
"carrier": "kr.cj",
"carrierName": "CJ대한통운",
"trackingNumber": "300718039335",
"status": "delivered",
"statusText": "배달완료",
"events": [
{
"timestamp": "2026-02-05T14:30:00+09:00",
"status": "delivered",
"statusText": "배달완료",
"location": "서울 강남구"
}
]
},
"timestamp": "2026-02-05T14:30:00+09:00"
},
"status": "delivered",
"deliveryAttempts": 1,
"createdAt": "2026-02-05T14:30:00.000Z",
"updatedAt": "2026-02-05T14:31:00.000Z"
}
],
"pagination": {
"limit": 20,
"nextCursor": "cursor_xyz789",
"hasMore": false
}
} 오류 응답 (401)
인증 실패
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} 오류 응답 (404)
requestId를 찾을 수 없음
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/subscriptions/{requestId}/changes/{changeId} 단일 변경 이벤트 조회
개요
특정 변경 이벤트의 상세 정보를 조회합니다. 무료 API로 사용량이 차감되지 않습니다.
요청 예제
curl -X GET https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes/{changeId} \
-H "Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production" \
-H "Content-Type: application/json"const response = await fetch('https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes/{changeId}', {
method: 'GET',
headers: {
"Authorization": "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production",
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data);<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes/{changeId}');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$headers = [
'Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);import requests
import json
url = 'https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes/{changeId}'
headers = {
'Authorization': 'Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
result = response.json()
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.whereparcel.com/v2/webhooks/subscriptions/{requestId}/changes/{changeId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}경로 매개변수
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>웹훅 등록 시 받은 requestId</p>
Example: req_abc123xyz |
changeId | string | Required | <p>변경 이벤트 ID</p>
Example: change_def456 |
응답
성공 응답 (200)
변경 이벤트 조회 성공
Response Body
{
"eventId": "evt_abc123",
"requestId": "req_abc123xyz",
"webhookUrl": "https://myapp.com/webhooks/whereparcel",
"event": "status.changed",
"payload": {
"trackingNumber": "300718039335",
"carrier": {
"code": "kr.cj",
"name": "CJ대한통운"
},
"previousStatus": "in_transit",
"currentStatus": "out_for_delivery",
"trackingData": {
"carrier": "kr.cj",
"carrierName": "CJ대한통운",
"trackingNumber": "300718039335",
"status": "out_for_delivery",
"statusText": "배달 출발",
"events": [
{
"timestamp": "2026-02-05T09:15:00+09:00",
"status": "out_for_delivery",
"statusText": "배달 출발",
"location": "서울 강남구 센터"
},
{
"timestamp": "2026-02-05T08:00:00+09:00",
"status": "in_transit",
"statusText": "배송 중",
"location": "서울 송파구 센터"
}
]
},
"timestamp": "2026-02-05T09:15:00+09:00"
},
"status": "delivered",
"deliveryAttempts": 1,
"maxAttempts": 3,
"createdAt": "2026-02-05T09:15:00.000Z",
"updatedAt": "2026-02-05T09:16:00.000Z"
} 오류 응답 (401)
인증 실패
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} 오류 응답 (404)
requestId 또는 changeId를 찾을 수 없음
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/results 웹훅 결과 배치 검색
개요
여러 택배의 웹훅 결과를 한 번에 검색합니다. 등록한 웹훅의 최종 결과를 조회할 때 사용합니다.
검색 방식:
- carrier + trackingNumber로 검색
- clientId로 검색
- 두 방식을 동시에 사용 가능
동작 방식:
- tracking_requests 컬렉션에서 trackingIndex/clientIdIndex 필드를 사용하여 검색
- 같은 송장번호가 여러 문서에 있을 경우 최신 문서만 반환
- Firestore array-contains-any 제한(10개)으로 인해 배치 처리 (최대 100개 조회 시 10번 쿼리)
무료 API로 사용량이 차감되지 않습니다.
요청 예제
curl -X POST https://api.whereparcel.com/v2/webhooks/results \
-H "Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production" \
-H "Content-Type: application/json" \
-d '{
"trackingItems": [
{
"carrier": "kr.cj",
"trackingNumber": "300718039335"
},
{
"carrier": "kr.lotte",
"trackingNumber": "410259694563"
}
]
}'const response = await fetch('https://api.whereparcel.com/v2/webhooks/results', {
method: 'POST',
headers: {
"Authorization": "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production",
"Content-Type": "application/json"
},
body: JSON.stringify({
"trackingItems": [
{
"carrier": "kr.cj",
"trackingNumber": "300718039335"
},
{
"carrier": "kr.lotte",
"trackingNumber": "410259694563"
}
]
})
});
const data = await response.json();
console.log(data);<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereparcel.com/v2/webhooks/results');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$headers = [
'Authorization: Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = [
'trackingItems' => [
'0' => [
'carrier' => "kr.cj",
'trackingNumber' => "300718039335"
],
'1' => [
'carrier' => "kr.lotte",
'trackingNumber' => "410259694563"
]
]
];
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);import requests
import json
url = 'https://api.whereparcel.com/v2/webhooks/results'
headers = {
'Authorization': 'Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production',
'Content-Type': 'application/json'
}
data = {
'trackingItems': {
'0': {
'carrier': "kr.cj",
'trackingNumber': "300718039335"
},
'1': {
'carrier': "kr.lotte",
'trackingNumber': "410259694563"
}
}
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.whereparcel.com/v2/webhooks/results"
payload := []byte(`{"trackingItems":[{"carrier":"kr.cj","trackingNumber":"300718039335"},{"carrier":"kr.lotte","trackingNumber":"410259694563"}]}`)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
req.Header.Add("Authorization", "Bearer wp_test_public_demo_key_do_not_use_in_production:sk_test_public_demo_secret_do_not_use_in_production")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}요청 본문
| Name | Type | Required | Description |
|---|---|---|---|
trackingItems | array | Required | |
응답
성공 응답 (200)
배치 검색 성공
Response Body
{
"results": {
"kr.cj:300718039335": {
"source": "webhook",
"data": {
"carrier": "kr.cj",
"carrierName": "CJ대한통운",
"trackingNumber": "300718039335",
"status": "delivered",
"statusText": "배달완료",
"events": [
{
"timestamp": "2026-02-05T14:30:00+09:00",
"status": "delivered",
"statusText": "배달완료",
"location": "서울 강남구"
},
{
"timestamp": "2026-02-05T09:15:00+09:00",
"status": "out_for_delivery",
"statusText": "배달 출발",
"location": "서울 강남구 센터"
}
]
},
"requestId": "sub_abc123xyz",
"createdAt": "2026-02-05T10:00:00.000Z"
},
"clientId:order-002": {
"source": "webhook",
"data": {
"carrier": "kr.lotte",
"carrierName": "롯데택배",
"trackingNumber": "410259694563",
"status": "in_transit",
"statusText": "배송 중",
"events": [
{
"timestamp": "2026-02-05T12:00:00+09:00",
"status": "in_transit",
"statusText": "배송 중",
"location": "경기 성남시"
}
]
},
"requestId": "sub_def456uvw",
"createdAt": "2026-02-05T10:00:00.000Z"
}
}
} 오류 응답 (401)
인증 실패
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key"
}
}