Skip to content
Last updated on

Wineshipping provides real-time shipment tracking updates through webhooks, enabling you to receive instant notifications about package status changes without polling our API.

Getting Started: Send an email to api@wineshipping.com to enable your event-driven feed and receive bespoke samples of tracking events for your account, include webhook url as well as one for testing if your environment supports that.

API Specification

A complete AsyncAPI 3.0 specification is available for the webhook events:

The AsyncAPI specification provides:

  • Complete message schemas with all fields documented
  • Event payload validation rules
  • Example payloads for each event type
  • Code generation capabilities for webhook handlers
  • Mock server generation for testing

Setup

To enable webhook tracking:

  1. Provide your webhook URL - This should be a publicly accessible HTTPS endpoint
  2. Configure event types - Choose which tracking events you want to receive (see below)
  3. Implement endpoint - Your endpoint must accept HTTP POST requests with JSON payloads
  4. Return success status - Respond with HTTP status codes 200-299 to acknowledge receipt

Important: Your webhook endpoint must respond within a reasonable timeout (recommended: < 10 seconds) and should process events asynchronously to avoid blocking the webhook delivery.

Event Types

Available events include the following. We can configure your event feed to include all or a subset of these event types. The tag field in the posted event data indicates the event type:

  • Pending: New tracking number that is pending to track with last-mile carrier
  • InfoReceived: New tracking number; the last-mile carrier has received the request and is about to pick up the shipment
  • InTransit: The shipment is on its way and has left the warehouse
  • OutForDelivery: Carrier is about to deliver the shipment, or it is ready for pickup
  • AttemptFail: Carrier attempted to deliver but failed, usually leaves a notice and will try to deliver again
  • Delivered: The shipment was delivered successfully
  • AvailableForPickup: The package arrived at a pickup point near the recipient and is available for pickup
  • Exception: Hold, undelivered, returned shipment to sender, or any shipping exceptions
  • Expired: Shipment has no tracking information for 30 days since added

Retry Policy

In case of an unsuccessful event when calling your URL (HTTP response code NOT between 200 and 299), Wineshipping attempts to deliver your webhooks for up to 14 times with exponential backoff using the formula: 2^(number of retry) × 30s

AttemptRetry #Delay (seconds)Cumulative DelayTime Elapsed
1000 secImmediate
213030 sec30 seconds
326090 sec1.5 minutes
43120210 sec3.5 minutes
54240450 sec7.5 minutes
65480930 sec15.5 minutes
769601,890 sec31.5 minutes
871,9203,810 sec~1 hour
983,8407,650 sec~2.1 hours
1097,68015,330 sec~4.3 hours
111015,36030,690 sec~8.5 hours
121130,72061,410 sec~17 hours
131261,440122,850 sec~34 hours
1413122,880245,730 sec~68 hours

Key Points:

  • If the first attempt fails, the 2nd attempt occurs 30 seconds later
  • If the 7th attempt fails, the 8th attempt occurs 1,920 seconds (32 minutes) later
  • After 14 failed attempts (~68 hours), the webhook delivery is permanently abandoned
  • Monitor your webhook endpoint's uptime and performance to avoid missing events

Event Data Structure

Webhook Payload

Event data is posted to your URL via HTTP POST in JSON format. Each webhook event follows the structure defined in the AsyncAPI specification's TrackingUpdatePayload schema.

Root Event Object

FieldTypeDescription
eventstringAlways "tracking_update" for tracking events
event_idstringUnique UUID for this webhook event
is_tracking_first_tagbooleanIndicates if this is the first tracking event for shipment
msgobjectThe tracking message payload (see below)
tsintegerUnix timestamp when the event was generated

Complete Example Payload

{
  "event": "tracking_update",
  "event_id": "555e9daa-f6ca-48a2-b30c-48e23cd0d0d6",
  "is_tracking_first_tag": true,
  "msg": {
    "active": true,
    "aftership_estimated_delivery_date": {
      "estimated_delivery_date": "2026-07-22",
      "confidence_score": null,
      "estimated_delivery_date_min": "2026-07-22",
      "estimated_delivery_date_max": "2026-07-23"
    },
    "android": [],
    "checkpoints": [
      {
        "checkpoint_time": "2026-07-20T15:00:15-05:00",
        "city": null,
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-20T20:00:16+00:00",
        "location": "US, United States",
        "message": "Shipment Ready for UPS",
        "raw_tag": "MP",
        "slug": "ups",
        "state": null,
        "subtag": "InfoReceived_001",
        "subtag_message": "Info Received",
        "tag": "InfoReceived",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-20T15:00:15-05:00",
        "city": null,
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-20T20:12:01+00:00",
        "location": "United States",
        "message": "Updated Delivery Time",
        "raw_tag": "UT",
        "slug": "ups",
        "state": null,
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-20T19:20:01-05:00",
        "city": "Earth City",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-21T00:20:56+00:00",
        "location": "Earth City, MO, US, United States",
        "message": "On the Way",
        "raw_tag": "OR",
        "slug": "ups",
        "state": "MO",
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-20T19:20:01-05:00",
        "city": null,
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-21T00:35:25+00:00",
        "location": "United States",
        "message": "Updated Delivery Date",
        "raw_tag": "UP",
        "slug": "ups",
        "state": null,
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-20T22:09:00-05:00",
        "city": "Earth City",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-21T03:20:46+00:00",
        "location": "Earth City, MO, US, United States",
        "message": "On the Way",
        "raw_tag": "DP",
        "slug": "ups",
        "state": "MO",
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-21T14:59:00-04:00",
        "city": "Orlando",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-21T19:16:38+00:00",
        "location": "Orlando, FL, US, United States",
        "message": "On the Way",
        "raw_tag": "AR",
        "slug": "ups",
        "state": "FL",
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-21T23:04:00-04:00",
        "city": "Orlando",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-22T03:19:39+00:00",
        "location": "Orlando, FL, US, United States",
        "message": "On the Way",
        "raw_tag": "DP",
        "slug": "ups",
        "state": "FL",
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-22T00:50:00-04:00",
        "city": "Clearwater",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-22T05:05:31+00:00",
        "location": "Clearwater, FL, US, United States",
        "message": "On the Way",
        "raw_tag": "AR",
        "slug": "ups",
        "state": "FL",
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-22T05:18:16-04:00",
        "city": "Clearwater",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-22T09:19:53+00:00",
        "location": "Clearwater, FL, US, United States",
        "message": "Preparing for Delivery",
        "raw_tag": "YP",
        "slug": "ups",
        "state": "FL",
        "subtag": "InTransit_001",
        "subtag_message": "In Transit",
        "tag": "InTransit",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-22T10:11:07-04:00",
        "city": "Clearwater",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-22T14:11:17+00:00",
        "location": "Clearwater, FL, US, United States",
        "message": "Out for Delivery",
        "raw_tag": "OT",
        "slug": "ups",
        "state": "FL",
        "subtag": "OutForDelivery_001",
        "subtag_message": "Out for Delivery",
        "tag": "OutForDelivery",
        "zip": null
      },
      {
        "checkpoint_time": "2026-07-22T11:06:54-04:00",
        "city": "BELLEAIR",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-22T15:08:24+00:00",
        "location": "BELLEAIR, FL, 33756, US, United States",
        "message": "Delivery Attempted",
        "raw_tag": "48",
        "slug": "ups",
        "state": "FL",
        "subtag": "AttemptFail_001",
        "subtag_message": "Failed Attempt",
        "tag": "AttemptFail",
        "zip": "33756"
      },
      {
        "checkpoint_time": "2026-07-22T11:08:44-04:00",
        "city": "BELLEAIR",
        "coordinates": [],
        "country_iso3": "USA",
        "country_name": "United States",
        "created_at": "2026-07-22T15:10:23+00:00",
        "location": "BELLEAIR, FL, 33756, US, United States",
        "message": "Delivered",
        "raw_tag": "KB",
        "slug": "ups",
        "state": "FL",
        "subtag": "Delivered_001",
        "subtag_message": "Delivered",
        "tag": "Delivered",
        "zip": "33756"
      }
    ],
    "courier_connection_id": null,
    "courier_destination_country_iso3": "USA",
    "courier_redirect_link": "https://www.ups.com/track?loc=en_US&tracknum=1Z59E877A871526000&requester=WT/trackdetails",
    "courier_tracking_link": "https://www.ups.com/track?loc=en_US&tracknum=1Z59E877A871526000&requester=WT/trackdetails",
    "created_at": "2026-07-20T16:22:03+00:00",
    "custom_estimated_delivery_date": null,
    "custom_fields": {
      "contents": "1xI0001003686(EACH) | 2xZ1883530252(750) | 1xZ2081643956(750) | 2xZ2266944449(750) | 6xZ2477531880(750) | 1xZ2512530726(750)",
      "contents_collateral_units": "1",
      "contents_merch_units": "0",
      "contents_product_units": "12",
      "date_dc": "07/18/2023 16:35:31",
      "date_input": "2026-07-18",
      "dc_cid": "CONT-013922021",
      "dc_oid": "14039199",
      "dc_pool": "DAILY",
      "dc_ship_confirm": "2026-07-20T22:54:40+00:00",
      "dc_ver": "v3",
      "final_mile": "ups",
      "oms_contents": "1xI0001003686(EACH) | 2xZ1883530252(750) | 1xZ2081643956(750) | 2xZ2266944449(750) | 6xZ2477531880(750) | 1xZ2512530726(750)",
      "regulatory_attributes": "FL:123456789",
      "rsd": "2026-07-19",
      "seller_name": "The Winery Name",
      "seller_number": "10000",
      "shipfrom_dc": "ETC01",
      "special_attributes": "icepack",
      "transmission_id": "OiHTFObyOOasdd",
      "transport_zone": "5",
      "tref": "f6c39d42-4afe-4957-9ad3-ea099d492b7c"
    },

    "custom_fields": {
      "container_type_code": "750STNDUP12BTL",
      "contents": "1xF09351(750) | 1xI200OFF-1223(EACH) | 1xI2309WIQ4COUP(EACH) | 1xI2309WITY(EACH) | 1xI24WIMRG-04(EACH) | 1xN01425(750) | 1xN01436(750) | 1xN01457(750) | 2xN01512(750) | 1xN01519(750) | 1xR10555(750) | 1xR10576(750) | 1xR10608(750) | 2xW21651857(750)",
      "contents_collateral_units": "4",
      "contents_merch_units": "0",
      "contents_product_units": "12",
      "date_packed": "2024-04-23T00:23:41+00:00",
      "dc_carrier": "FEX-GRND",
      "dc_oid": "17892793",
      "dc_pool": "DAILY",
      "dc_ship_confirm": "2024-04-23T00:57:38+00:00",
      "dc_ver": "v3",
      "final_mile": "fedex",
      "oms_contents": "1xF09351(750) | 1xI200OFF-1223(EACH) | 1xI2309WIQ4COUP(EACH) | 1xI2309WITY(EACH) | 1xI24WIMRG-04(EACH) | 1xN01425(750) | 1xN01436(750) | 1xN01457(750) | 2xN01512(750) | 1xN01519(750) | 1xR10555(750) | 1xR10576(750) | 1xR10608(750) | 2xW21651857(750)",
      "regulatory_attributes": "",
      "rsd": "2024-04-22",
      "seller_name": "The Winery Name",
      "seller_number": "10000",
      "shipfrom_dc": "VCX01",
      "special_attributes": "hold.location",
      "special_instructions": "",
      "transmission_id": "c15b079f-a1e5-4c4b-9ac1-3db3b4fb7555",
      "transport_zone": "5",
      "tref": "a8da0749-c6ad-4bbd-bf62-acaa2d814555"
    },
    "customer_name": "Jane D.",
    "delivery_time": 3,
    "delivery_type": null,
    "destination_city": "Belleair",
    "destination_country_iso3": "USA",
    "destination_postal_code": "33756-1925",
    "destination_raw_location": "555 Main Street, Belleair, FL, 33756-1925",
    "destination_state": "FL",
    "emails": ["jane@email.com"],
    "expected_delivery": "2026-07-24",
    "first_attempted_at": "2026-07-22T11:06:54-04:00",
    "first_estimated_delivery": {
      "datetime": "2026-07-24",
      "datetime_max": null,
      "datetime_min": null,
      "source": "Carrier EDD",
      "type": "specific"
    },
    "id": "rwfu4vriciwerlkbd1g0y00j",
    "ios": [],
    "language": "en",
    "last_mile_tracking_supported": true,
    "last_updated_at": "2026-07-22T15:10:23+00:00",
    "latest_estimated_delivery": {
      "source": "Carrier EDD",
      "datetime": "2026-07-24",
      "type": "specific",
      "datetime_min": null,
      "datetime_max": null
    },
    "next_couriers": [],
    "note": null,
    "on_time_difference": -2,
    "on_time_status": "early",
    "order_date": "2026-07-18T16:35:31-07:00",
    "order_id": "CONT-013922021",
    "order_id_path": null,
    "order_number": "33516482",
    "order_promised_delivery_date": null,
    "order_tags": [],
    "origin_city": "Earth City",
    "origin_country_iso3": "USA",
    "origin_postal_code": "630451224",
    "origin_raw_location": "Earth City, Missouri",
    "origin_state": "Missouri",
    "path": "deprecated",
    "pickup_location": null,
    "pickup_note": null,
    "return_to_sender": false,
    "shipment_delivery_date": "2026-07-22T11:08:44-04:00",
    "shipment_package_count": null,
    "shipment_pickup_date": "2026-07-20T15:00:15-05:00",
    "shipment_tags": [],
    "shipment_type": "UPS Ground",
    "shipment_weight": 34.6,
    "shipment_weight_unit": "lb",
    "signed_by": null,
    "slug": "ups",
    "smses": ["+18555072501"],
    "source": "api",
    "subscribed_smses": ["+18555072509", "+18555072501"],
    "subscribed_emails": ["jane@email.com", "another_email@email.com"],
    "subtag": "Delivered_001",
    "subtag_message": "Delivered",
    "tag": "Delivered",
    "title": "33516482",
    "tracked_count": 19,
    "tracking_account_number": null,
    "tracking_destination_country": "USA",
    "tracking_key": null,
    "tracking_number": "1Z59E877A871526000",
    "tracking_origin_country": "USA",
    "tracking_postal_code": "33756-1925",
    "tracking_ship_date": "20230720",
    "tracking_state": "FL",
    "unique_token": "deprecated",
    "updated_at": "2026-07-22T15:10:23+00:00"
  },
  "ts": 1690038623
}

Date and Time Formats

Dates and times provided by carriers vary in precision by event. Your webhook handler should be able to parse multiple formats:

  • YYYY-MM-DD - Date only (e.g., 2026-07-22)
  • YYYY-MM-DDTHH:MM:SS - Date and time without timezone (e.g., 2026-07-22T11:08:44)
  • YYYY-MM-DDTHH:MM:SS+TIMEZONE - Full ISO 8601 with timezone (e.g., 2026-07-22T11:08:44-04:00)

Recommendation: Use a robust date/time parsing library that handles multiple ISO 8601 formats automatically.

Key Message Fields

The most commonly used fields in the msg object for tracking applications:

FieldDescription
tagPrimary tracking status (Delivered, InTransit, etc.)
subtagDetailed status code (e.g., Delivered_001)
tracking_numberCarrier tracking number
order_idYour order identifier
order_numberCustomer-facing order number
slugCarrier identifier (ups, fedex, usps, etc.)
checkpointsArray of all tracking events from carrier
last_updated_atMost recent update timestamp
shipment_delivery_dateActual delivery timestamp (null until delivered)
expected_deliveryExpected delivery date
destination_*Destination address fields (city, state, postal_code)
custom_fieldsCustom metadata specific to your shipment

Understanding Checkpoints

The checkpoints array contains the complete tracking history from the carrier. Each checkpoint represents a scan or status update:

{
  "checkpoint_time": "2026-07-22T11:08:44-04:00",
  "tag": "Delivered",
  "subtag": "Delivered_001",
  "message": "Delivered",
  "location": "BELLEAIR, FL, 33756, US, United States",
  "city": "BELLEAIR",
  "state": "FL",
  "zip": "33756"
}

Checkpoints are ordered chronologically and can be used to:

  • Display detailed tracking timeline to customers
  • Calculate transit time between events
  • Identify delivery exceptions or delays
  • Determine exact delivery location

Implementation Best Practices

1. Idempotency

Implement idempotent webhook processing using the event_id field:

// Example: Check if event was already processed
if (await db.eventExists(payload.event_id)) {
  return { statusCode: 200, body: 'Already processed' };
}

// Process the event
await processTrackingUpdate(payload);

// Store event_id to prevent duplicate processing
await db.saveEventId(payload.event_id);

Why: Network issues or retries may cause the same event to be delivered multiple times.

2. Asynchronous Processing

Respond to webhooks immediately, then process asynchronously:

app.post('/webhooks/tracking', async (req, res) => {
  // Validate and acknowledge immediately
  res.status(200).json({ received: true });
  
  // Queue for background processing
  await queue.add('process-tracking', req.body);
});

Why: Keeps webhook delivery fast and prevents timeouts during heavy processing.

3. Validation

Validate incoming webhook payloads against the AsyncAPI schema:

  • Verify required fields are present (event, event_id, msg, ts)
  • Check that event equals "tracking_update"
  • Validate that msg.tracking_number matches expected format
  • Consider implementing webhook signature verification (contact support)

4. Error Handling

Implement graceful error handling:

try {
  await processTrackingUpdate(payload);
  return { statusCode: 200 };
} catch (error) {
  // Log error for debugging
  logger.error('Webhook processing failed', { error, event_id: payload.event_id });
  
  // Return 200 if it's a client error (won't fix with retry)
  if (error instanceof ValidationError) {
    return { statusCode: 200, body: 'Invalid payload' };
  }
  
  // Return 5xx for server errors (will trigger retry)
  return { statusCode: 500, body: 'Server error' };
}

Important: Only return non-2xx status codes for temporary failures where a retry might succeed.

5. Monitoring

Monitor your webhook endpoint health:

  • Track webhook delivery success/failure rates
  • Monitor processing latency
  • Alert on consecutive failures
  • Log all event_id values for troubleshooting
  • Track tag distribution to understand delivery patterns

6. Testing

Use the AsyncAPI specification to:

  • Generate mock webhook servers for development
  • Create test fixtures for each event type
  • Validate your webhook handler against the schema
  • Generate code stubs in your preferred language

7. Database Design

Consider storing:

  • Complete webhook payload (for audit trail)
  • event_id (for idempotency)
  • tracking_number (indexed for lookups)
  • order_id and order_number (indexed for customer queries)
  • tag (for filtering/reporting)
  • checkpoints array (for detailed history)
  • Processing status and timestamps

Webhook vs. Polling

Webhooks offer significant advantages over polling the GetDetails API:

AspectWebhooks (Event-Driven)Polling (GetDetails API)
LatencyReal-time (seconds)Delayed by polling interval
EfficiencyPush-based, no wasted requestsMany requests return no new data
Rate LimitsNot subject to rate limitingSubject to API rate limits
CostNo API calls requiredConsumes API quota
ScalabilityScales with eventsScales with polling frequency × count
RecommendedYes, for all implementationsOnly for initial setup or backfill

Recommendation: Use webhooks as your primary tracking mechanism and only use GetDetails API for:

  • Initial historical data retrieval
  • Backfilling missed events
  • Manual troubleshooting

Schema Documentation

For complete field definitions and data types, refer to:

Getting Help

If you need assistance with webhook implementation:

  • Review the AsyncAPI specification for complete schema details
  • Email api@wineshipping.com for:
    • Webhook endpoint configuration
    • Sample event data specific to your account
    • Webhook signature implementation details
    • Troubleshooting delivery issues