Webhooks API - WhereParcel
Subscribe to real-time parcel tracking updates via webhooks. Get instant notifications when delivery status changes. Automatic retries and event filtering.
/v2/webhooks/register Register webhook (billable)
Overview
Register a webhook for parcel tracking. Supports 2 modes:
- recurring: true - Continuous monitoring until delivery (subscription)
- recurring: false - Query once only (one-time, default) Billable API, supports up to 500 items per registration.
Example Request
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))
}Request Body
| Name | Type | Required | Description |
|---|---|---|---|
trackingItems | array | Required | Tracking items (up to 500) |
trackingItems[].carrier | string | Required | |
trackingItems[].trackingNumber | string | Required | |
trackingItems[].clientId | string | Optional | |
recurring | boolean | Optional | Tracking mode (optional, default: false)
- false: Query once only (default, safe) → webhookEndpointId optional
- true: Continuous monitoring (explicit request required) → webhookEndpointId required |
webhookEndpointId | string | Optional | Pre-registered Webhook Endpoint ID
- Required when recurring: true (validated by middleware)
- Optional when recurring: false
- If provided, sends POST on completion; if omitted, no notification sent
- Must register a Webhook Endpoint first |
Response
Success Response (200)
Webhook registered successfully
Response Body
{
"success": true,
"requestId": "req_abc123xyz",
"subscriptionId": "sub_def456uvw",
"status": "active",
"message": "Webhook registered successfully (recurring mode)"
} Error Response (401)
Authentication failed
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} Error Response (429)
Rate limit exceeded
Response Body
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later."
}
} /v2/webhooks/subscriptions List webhook subscriptions
Overview
Retrieve all registered webhook subscriptions (recurring + one-time). Free API - does not count towards usage quota.
Example Request
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))
}Response
Success Response (200)
Subscription list retrieved successfully
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"
}
] Error Response (401)
Authentication failed
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} /v2/webhooks/subscriptions/{requestId} Get webhook subscription
Overview
Retrieve webhook subscription information for a specific requestId. Free API - does not count towards usage quota.
Example Request
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))
}Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>requestId received during webhook registration</p>
Example: req_abc123xyz |
Response
Success Response (200)
Subscription info retrieved successfully
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"
}
} Error Response (401)
Authentication failed
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} Error Response (404)
requestId not found
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/subscriptions/{requestId} Delete webhook subscription
Overview
Cancel a webhook subscription and stop monitoring. For recurring webhooks, monitoring stops immediately. Free API - does not count towards usage quota.
Example Request
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))
}Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>requestId of the webhook to delete</p>
Example: req_abc123xyz |
Response
Success Response (200)
Subscription deleted successfully
Response Body
{
"deleted": true,
"requestId": "req_abc123xyz",
"message": "Webhook subscription deleted successfully"
} Error Response (401)
Authentication failed
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} Error Response (404)
requestId not found
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/subscriptions/{requestId}/changes List webhook change history
Overview
Retrieve all change history (delivery status changes) for a specific webhook subscription. Free API - does not count towards usage quota.
Example Request
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))
}Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>requestId received during webhook registration</p>
Example: req_abc123xyz |
Response
Success Response (200)
Change history retrieved successfully
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
}
} Error Response (401)
Authentication failed
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} Error Response (404)
requestId not found
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/subscriptions/{requestId}/changes/{changeId} Get single change event
Overview
Retrieve detailed information for a specific change event. Free API - does not count towards usage quota.
Example Request
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))
}Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
requestId | string | Required | <p>requestId received during webhook registration</p>
Example: req_abc123xyz |
changeId | string | Required | <p>Change event ID</p>
Example: change_def456 |
Response
Success Response (200)
Change event retrieved successfully
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"
} Error Response (401)
Authentication failed
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
} Error Response (404)
requestId or changeId not found
Response Body
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found"
}
} /v2/webhooks/results Batch search webhook results
Overview
Search webhook results for multiple parcels at once. Use this to retrieve final results of registered webhooks.
Search methods:
- Search by carrier + trackingNumber
- Search by clientId
- Both methods can be used simultaneously
How it works:
- Searches using trackingIndex/clientIdIndex fields in the tracking_requests collection
- Returns only the latest document when multiple documents exist for the same tracking number
- Batch processed due to Firestore array-contains-any limit (10) (up to 10 queries for 100 items)
Free API - does not count towards usage quota.
Example Request
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))
}Request Body
| Name | Type | Required | Description |
|---|---|---|---|
trackingItems | array | Required | |
Response
Success Response (200)
Batch search completed successfully
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"
}
}
} Error Response (401)
Authentication failed
Response Body
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key"
}
}