export type TrackingInputFieldName = 'destination_country' | 'postal_code' | 'email' | 'phone' | 'additional_fields.house_number' | 'additional_fields.bc_code' | 'additional_fields.address_key' | 'additional_fields.consignee_info' | 'additional_fields.customer_token' | 'additional_fields.vessel' | 'additional_fields.voyage'; export type TrackingInputRequirements = {required?: Array | undefined, any_of?: Array | undefined, conditional?: Array | undefined}; export type TransportMode = 'parcel' | 'postal' | 'express' | 'road_freight' | 'air_cargo' | 'ocean_container'; export type FlightLeg = {flight_number?: string | undefined, origin?: string | undefined, destination?: string | undefined, status?: string | undefined, scheduled_departure_date?: string | undefined, scheduled_departure?: string | undefined, scheduled_arrival?: string | undefined, actual_departure?: string | undefined, actual_arrival?: string | undefined, pieces?: number | undefined, weight?: number | undefined, weight_unit?: string | undefined, volume?: number | undefined, volume_unit?: string | undefined}; export type TrackingEvent = {state?: string | undefined, location?: string | undefined, date?: string | undefined, event_code?: string | undefined, station?: string | undefined, timezone?: string | undefined, pieces?: number | undefined, weight?: number | undefined, weight_unit?: string | undefined, volume?: number | undefined, volume_unit?: string | undefined, flight_number?: string | undefined, flight_origin?: string | undefined, flight_destination?: string | undefined, scheduled_departure_date?: string | undefined, scheduled_departure?: string | undefined, scheduled_arrival?: string | undefined, actual_departure?: string | undefined, actual_arrival?: string | undefined, uld_number?: string | undefined, carrier?: number | undefined}; export type Carrier = {slug?: string | undefined, name?: string | undefined}; export type ShipmentAttribute = {l?: string | undefined, val?: string | undefined, code?: string | undefined} | {[key: string]: unknown}; export type ExternalTracking = {slug?: string | undefined, url?: string | undefined, trackingId?: string | undefined, method?: string | undefined}; export type Shipment = {trackingId?: string | undefined, error?: string | undefined, accepted_fields?: (Array<'postal_code' | 'email' | 'phone'>) | undefined, input_requirements?: TrackingInputRequirements | undefined, status?: string | undefined, origin?: string | undefined, destination?: string | undefined, originCode?: string | undefined, destinationCode?: string | undefined, transportMode?: TransportMode | undefined, fromAirport?: string | undefined, toAirport?: string | undefined, fromPort?: string | undefined, toPort?: string | undefined, pieces?: number | undefined, weight?: number | undefined, weight_unit?: string | undefined, volume?: number | undefined, volume_unit?: string | undefined, flight_legs?: Array | undefined, states?: Array | undefined, services?: Array | undefined, detectedCarrier?: Carrier | undefined, detected?: Array | undefined, attributes?: Array | undefined, externalTracking?: Array | undefined} | {[key: string]: unknown}; export type DeliveryCompletionScope = 'carrier_acceptance_to_delivery' | 'airport_to_airport' | 'airport_to_availability' | 'port_to_port' | 'port_to_availability' | 'port_to_gate_out'; export type DeliveryEstimateRoute = {origin_dimension?: ('city' | 'admin1' | 'country' | 'airport' | 'port' | null) | undefined, origin_key?: (string | null) | undefined, destination_dimension?: ('city' | 'admin1' | 'country' | 'airport' | 'port' | null) | undefined, destination_key?: (string | null) | undefined, carrier_specific?: boolean | undefined}; export type DeliveryEstimateRange = {min?: number | undefined, max?: number | undefined}; export type DeliveryEstimateRemaining = {mean?: (number | null) | undefined, median?: number | undefined, min?: number | undefined, max?: number | undefined} | null; export type DeliveryEstimateWindow = {from?: string | undefined, to?: string | undefined} | null; export type DeliveryEstimateValues = {mean_days: number, median_days: number, typical_days: DeliveryEstimateRange, remaining_status: 'not_requested' | 'estimated' | 'insufficient_censored_data' | 'insufficient_tail_data', remaining_days?: DeliveryEstimateRemaining | undefined, estimated_delivery_at?: DeliveryEstimateWindow | undefined}; export type DeliveryEstimateConfidence = {level: 'low' | 'medium' | 'high', score: number, sample_count: number, effective_sample_count: number, remaining_effective_sample_count?: number | undefined, minimum_remaining_effective_sample_count?: number | undefined, survival_subject_count?: number | undefined, survival_completed_count?: number | undefined, survival_censored_count?: number | undefined, survival_risk_set?: number | undefined, survival_minimum_subject_count?: number | undefined, survival_minimum_completed_count?: number | undefined, survival_cohort_age_days?: number | undefined, survival_minimum_maturation_days?: number | undefined, lookback_days: number, last_observation_at?: (string | null) | undefined, freshness_days?: number | undefined, fallback_level: number}; export type DeliveryEstimateInsufficientData = {code: 'INSUFFICIENT_DATA', message: string, available_sample_count: number, minimum_sample_count: number}; export type DeliveryEstimateResult = {client_reference?: string | undefined, carrier_slug: string, transport_mode: TransportMode, completion_scope: DeliveryCompletionScope, route_scope_used?: string | undefined, route?: DeliveryEstimateRoute | undefined, estimate?: DeliveryEstimateValues | undefined, confidence?: DeliveryEstimateConfidence | undefined, model?: ({version?: string | undefined, unit?: 'calendar_days' | undefined, histogram_bucket_hours?: number | undefined, remaining_method?: ('kaplan_meier_right_censored_v1' | 'completed_tail_guard_v1') | undefined}) | undefined, error?: DeliveryEstimateInsufficientData | undefined}; export type TrackingResult = {tracking_number: string, state: 'processing' | 'completed', from_cache: boolean, shipment?: Shipment | undefined, delivery_estimate?: DeliveryEstimateResult | undefined}; export type RejectedShipment = {index: number, tracking_number?: string | undefined, code: 'INVALID_TRACKING_NUMBER' | 'DESTINATION_COUNTRY_REQUIRED' | 'INVALID_ADDITIONAL_FIELDS', message: string}; export type ErrorObject = {code: 'MISSING_API_KEY' | 'INVALID_API_KEY' | 'INVALID_PARAMS' | 'INVALID_TRACKING_NUMBER' | 'DESTINATION_COUNTRY_REQUIRED' | 'INVALID_WEBHOOK_URL' | 'INVALID_CURSOR' | 'UNCONFIRMED_ACCOUNT' | 'SUBSCRIPTION_NOT_FOUND' | 'SUBSCRIPTION_INACTIVE' | 'SUBSCRIPTION_LIMIT_REACHED' | 'INVALID_SUBSCRIPTION_STATE' | 'FORBIDDEN' | 'NO_SHIPMENTS' | 'NO_REQUEST_FOUND' | 'MISSING_REQUEST_ID' | 'INVALID_REQUEST_ID' | 'INVALID_DELIVERY_ESTIMATE_REQUEST' | 'BATCH_TOO_LARGE' | 'INVALID_TRANSPORT_MODE' | 'RATE_LIMITED' | 'BUSY' | 'SERVER_ERROR', message: string, limit?: number | undefined, current?: number | undefined, requested_new?: number | undefined, available?: number | undefined, confirmation_url?: string | undefined, confirmation_expires_at?: string | undefined, rejected?: Array | undefined}; export type WebhookPayload = {event: 'shipment_completed' | 'batch_completed' | 'tracking_error', request_id: string, timestamp: string, done: boolean, result?: TrackingResult | undefined, results?: Array | undefined, error?: ErrorObject | undefined}; export type CreateApiParcelsWebhookArgs = {'Parcels-Signature': string, body: WebhookPayload}; export type CreateApiParcelsWebhookOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; /** * Receive tracking webhook * * POST /parcels-webhook */ export const createApiParcelsWebhook = async (args: CreateApiParcelsWebhookArgs, options?: CreateApiParcelsWebhookOptions) => { const {baseUrl = "https://your-domain.example", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") if (args['Parcels-Signature'] != null) headers.set("Parcels-Signature", String(args['Parcels-Signature'])) const url = `${baseUrl.replace(/\/+$/, '')}/parcels-webhook${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return undefined };