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). Recommended for most integrations. Register once and receive push notifications whenever the tracking status changes. Ideal for keeping your database in sync with delivery progress.recurring: false— Query once only (one-time, default). Useful for one-off lookups where you don't need ongoing updates.
Why use webhooks? Polling /v2/track repeatedly wastes your request quota. A single parcel typically has 5–10 status changes over its lifecycle. With webhooks, you receive only those 5–10 updates instead of making hundreds of polling requests.
Billable API, supports up to 500 items per registration.
Example Request
// npm install whereparcel
import { WhereParcel } from 'whereparcel';
const wp = new WhereParcel('wp_test_public_demo_key_do_not_use_in_production', 'sk_test_public_demo_secret_do_not_use_in_production');
const result = await wp.registerWebhook({
"trackingItems": [
{
"carrier": "kr.cj",
"trackingNumber": "123456789012",
"clientId": "order-001"
},
{
"carrier": "de.gls",
"trackingNumber": "48117308687",
"postalCode": "04179",
"clientId": "order-002"
}
],
"recurring": true,
"webhookEndpointId": "endpoint-id-123"
});
console.log(result);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"
},
{
"carrier": "de.gls",
"trackingNumber": "48117308687",
"postalCode": "04179",
"clientId": "order-002"
}
],
"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"
},
{
"carrier": "de.gls",
"trackingNumber": "48117308687",
"postalCode": "04179",
"clientId": "order-002"
}
],
"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"
],
'1' => [
'carrier' => "de.gls",
'trackingNumber' => "48117308687",
'postalCode' => "04179",
'clientId' => "order-002"
]
],
'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"
},
'1': {
'carrier': "de.gls",
'trackingNumber': "48117308687",
'postalCode': "04179",
'clientId': "order-002"
}
},
'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"},{"carrier":"de.gls","trackingNumber":"48117308687","postalCode":"04179","clientId":"order-002"}],"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 | |
trackingItems[].postalCode | string | Optional | |
trackingItems[].phoneNumber | 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
// npm install whereparcel
import { WhereParcel } from 'whereparcel';
const wp = new WhereParcel('wp_test_public_demo_key_do_not_use_in_production', 'sk_test_public_demo_secret_do_not_use_in_production');
const subscriptions = await wp.getSubscriptions();
console.log(subscriptions);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
// npm install whereparcel
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);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
// npm install whereparcel
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);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
// npm install whereparcel
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);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
// npm install whereparcel
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);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
// npm install whereparcel
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": "de.gls",
"trackingNumber": "48117308687",
"postalCode": "04179"
}
]
})
});
const data = await response.json();
console.log(data);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": "de.gls",
"trackingNumber": "48117308687",
"postalCode": "04179"
}
]
}'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": "de.gls",
"trackingNumber": "48117308687",
"postalCode": "04179"
}
]
})
});
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' => "de.gls",
'trackingNumber' => "48117308687",
'postalCode' => "04179"
]
]
];
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': "de.gls",
'trackingNumber': "48117308687",
'postalCode': "04179"
}
}
}
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":"de.gls","trackingNumber":"48117308687","postalCode":"04179"}]}`)
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"
}
}