Developer Handover Pack
Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.
Developer Handover Pack
Shipping & Tracking Notification
[YourCompany.com] · Fulfilment Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for the FullSpec team building the Shipping and Tracking Notification automation. It covers the current-state process map, full agent specifications with IO contracts, the end-to-end data flow, and the recommended build stack. Every section is written for the engineer responsible for implementation. Where a decision is still open, it is called out explicitly so it can be resolved before build begins.
01Process snapshot
02Agent specifications
Monitors ShipStation for any order that transitions to a shipped status with a non-null tracking number attached. On detection it immediately fetches the matching Shopify order record to retrieve the customer name, email address, order number, and line item summary. It then assembles the correct carrier tracking URL by mapping the carrier code to the appropriate base URL format and appending the tracking number. The fully assembled data object is passed downstream to the Notification Dispatch Agent. This agent is the entry point for the entire automation and must handle both webhook delivery and polling fallback without duplicating events.
// Input
ShipStation webhook payload or poll response:
order_id : string // ShipStation internal order ID
order_number : string // Human-readable order reference
tracking_number : string // Carrier-assigned tracking number
carrier_code : string // e.g. 'ups', 'fedex', 'usps', 'dhl'
ship_date : ISO8601 // Date/time shipment confirmed
// Processing
Shopify REST GET /orders.json?name={order_number}
-> customer.email : string // Confirmed send address
-> customer.first_name : string
-> order.name : string // Shopify order display name
Carrier URL map lookup (carrier_code -> base_url):
tracking_url = base_url + tracking_number
// Output (structured data object passed to Notification Dispatch Agent)
order_id : string
order_number : string
customer_email : string
customer_name : string
carrier_name : string // Human-readable, e.g. 'UPS'
tracking_number : string
tracking_url : string // Fully formed clickable URL
ship_date : ISO8601
email_valid : boolean // False triggers manual review branch- ShipStation API access requires the Standard plan or above ($45/month confirmed in tooling). Confirm webhook endpoint registration in ShipStation Settings > Integrations > Webhooks before build. The webhook event type must be 'SHIP_NOTIFY'.
- Shopify lookup uses the Admin REST API (API version 2024-01 or later). Confirm the Shopify custom app has read_orders and read_customers scopes granted. The app must be installed on the production store, not a development store, before the order fetch is tested against real data.
- The carrier URL map must be built as a configurable lookup table (not hardcoded) so new carriers can be added without touching workflow logic. Minimum required carrier codes at launch: 'ups', 'fedex', 'usps', 'dhl_express', 'australia_post'. Any unrecognised carrier_code must trigger the error logging path and must NOT produce a tracking_url.
- Deduplication: the agent must store a hash or record of processed order_id values (keyed by order_id + tracking_number) to prevent duplicate sends if a webhook fires more than once for the same shipment event. Recommended: write processed order_id to the error-log Supabase table with a 'sent' status and check before proceeding.
- If customer_email is null, empty, or fails basic format validation (RFC 5321), set email_valid to false and route the record to the manual review branch. Do not attempt to construct or send an email for that record.
- Confirm with the process owner before build: are there any ShipStation order statuses other than 'Shipped' (e.g. partial shipments, split orders) that should also trigger this agent? The current spec assumes a single shipped status per order.
Receives the validated shipment data object from the Shipment Event Listener and executes three sequential actions: it triggers the pre-built Klaviyo transactional flow passing all personalisation variables into the email template, appends a confirmation row to the fulfilment tracker in Google Sheets, and posts a summary message to the designated Slack channel. The agent handles the email_valid false branch by routing incomplete records to a clearly named Google Sheets tab for manual review rather than dropping them silently. All three output actions are attempted independently so a Sheets write failure does not block the Slack post.
// Input (from Shipment Event Listener)
order_id : string
order_number : string
customer_email : string
customer_name : string
carrier_name : string
tracking_number : string
tracking_url : string
ship_date : ISO8601
email_valid : boolean
// On email_valid = false
-> Append to Google Sheets tab 'Manual Review':
[order_id, order_number, customer_email, tracking_number, ship_date, reason: 'invalid_email']
-> Post Slack alert to #fulfilment-alerts: 'Manual review required: {order_number} - invalid email'
-> Stop; no Klaviyo call made
// On email_valid = true
Klaviyo POST /api/events/ (Track API v2):
metric_name : 'Shipment Dispatched'
customer_email : string // Maps to Klaviyo profile identifier
properties:
order_number : string
customer_name : string
carrier_name : string
tracking_number : string
tracking_url : string
ship_date : ISO8601
// Output: Klaviyo
klaviyo_event_id : string // Returned by Klaviyo; store in Sheets row
// Output: Google Sheets (tab 'Notification Log')
[order_id, order_number, customer_email, carrier_name, tracking_number,
tracking_url, ship_date, send_timestamp, klaviyo_event_id, status: 'sent']
// Output: Slack (#fulfilment-notifications)
Message text: 'Tracking notifications sent: {count} orders in last batch.
Latest: {order_number} -> {customer_email} via {carrier_name}.
Manual review queue: {manual_review_count} items.'- Klaviyo transactional flow must be built and approved inside Klaviyo before the automation goes live. The agent only triggers the event via the Klaviyo Track API; it does not construct or send the email itself. Confirm the Klaviyo metric name 'Shipment Dispatched' matches exactly what is configured in the Klaviyo flow trigger. The Klaviyo plan must support transactional/API-triggered flows (Klaviyo Email plan or above; confirm account tier before build).
- The Klaviyo private API key must be scoped to Events: Write. No broader scopes are required for this agent. Store the key in the shared credential store; do not hardcode in workflow nodes.
- Google Sheets integration requires a service account with Editor access to the target spreadsheet. Confirm the spreadsheet ID and the exact tab names ('Notification Log' and 'Manual Review') with the process owner before build. The sheet structure must be column-locked to prevent the owner accidentally reordering headers.
- Slack integration requires a Slack app with the chat:write OAuth scope installed in the target workspace. Confirm the channel name (#fulfilment-notifications for standard batch summary, #fulfilment-alerts for manual review flags) with the process owner. The Slack digest is a per-batch post, not a daily aggregate, unless the process owner requests batching.
- Each output action (Klaviyo, Sheets, Slack) must be wrapped in independent error handling. A failure in the Sheets append must not roll back the Klaviyo send. All failures must write to the error-log table with the order_id, agent name, action, error message, and timestamp.
- Confirm with the process owner before build: is there a Klaviyo suppression list or consent filter that should be checked before sending? If so, the Klaviyo flow itself handles suppression; the automation agent does not need additional logic.
03End-to-end data flow
// ============================================================
// SHIPPING & TRACKING NOTIFICATION: END-TO-END DATA FLOW
// ============================================================
// TRIGGER: ShipStation order status change
// -----------------------------------------------------------------
// ShipStation fires SHIP_NOTIFY webhook (or poll detects status change)
// Event arrives at automation platform webhook endpoint
INBOUND_EVENT {
order_id : 'SS-10042891' // ShipStation internal ID
order_number : '1042' // Display order number
tracking_number : '1Z999AA10123456784' // Carrier tracking number
carrier_code : 'ups' // Normalised carrier code
ship_date : '2024-04-22T09:14:00Z' // ISO8601 UTC
}
// DEDUPLICATION CHECK
// -----------------------------------------------------------------
// Lookup: processed_events WHERE order_id = 'SS-10042891'
// AND tracking_number = '1Z999AA10123456784'
// If found -> HALT (duplicate event, already processed)
// If not found -> continue and mark as 'processing'
// ============================================================
// AGENT 1: Shipment Event Listener
// ============================================================
// Step 1: Shopify order lookup
// GET https://{shop}.myshopify.com/admin/api/2024-01/orders.json
// ?name=%231042&status=any
// Authorization: Basic {base64(api_key:api_secret)}
SHOPIFY_ORDER_RESPONSE {
orders[0].email : 'jane.smith@example.com'
orders[0].customer.first_name : 'Jane'
orders[0].name : '#1042'
orders[0].id : 5678901234567 // Shopify order ID
}
// Step 2: Email validation
// RFC 5321 format check on orders[0].email
// If null or invalid -> set email_valid = false -> branch to manual review
// If valid -> set email_valid = true -> continue
// Step 3: Carrier URL construction
CARRIER_MAP {
'ups' : 'https://www.ups.com/track?tracknum='
'fedex' : 'https://www.fedex.com/fedextrack/?trknbr='
'usps' : 'https://tools.usps.com/go/TrackConfirmAction?tLabels='
'dhl_express' : 'https://www.dhl.com/en/express/tracking.html?AWB='
'australia_post': 'https://auspost.com.au/mypost/track/#/details/'
'[unknown]' : null // triggers error log, halts tracking_url build
}
tracking_url = CARRIER_MAP[carrier_code] + tracking_number
// -> 'https://www.ups.com/track?tracknum=1Z999AA10123456784'
// Step 4: Assemble handoff object
SHIPMENT_DATA_OBJECT {
order_id : 'SS-10042891'
order_number : '#1042'
customer_email : 'jane.smith@example.com'
customer_name : 'Jane'
carrier_name : 'UPS'
tracking_number : '1Z999AA10123456784'
tracking_url : 'https://www.ups.com/track?tracknum=1Z999AA10123456784'
ship_date : '2024-04-22T09:14:00Z'
email_valid : true
}
// ============================================================
// AGENT HANDOFF: Shipment Event Listener -> Notification Dispatch Agent
// SHIPMENT_DATA_OBJECT passed as input payload to Agent 2
// ============================================================
// ============================================================
// AGENT 2: Notification Dispatch Agent
// ============================================================
// BRANCH: email_valid = false
// -----------------------------------------------------------------
// -> Google Sheets append to tab 'Manual Review':
// [order_id, order_number, customer_email, tracking_number,
// ship_date, reason: 'invalid_email', flagged_at: NOW()]
// -> Slack POST to #fulfilment-alerts:
// 'Manual review required: #1042 - invalid email'
// -> HALT (no Klaviyo call)
// BRANCH: email_valid = true
// -----------------------------------------------------------------
// Action A: Klaviyo event track
// POST https://a.klaviyo.com/api/track
// Authorization: Klaviyo-API-Key {private_key}
// Content-Type: application/json
KLAVIYO_PAYLOAD {
data.type : 'event'
data.attributes.metric.name : 'Shipment Dispatched'
data.attributes.profile.email : 'jane.smith@example.com'
data.attributes.properties {
order_number : '#1042'
customer_name : 'Jane'
carrier_name : 'UPS'
tracking_number : '1Z999AA10123456784'
tracking_url : 'https://www.ups.com/track?tracknum=1Z999AA10123456784'
ship_date : '2024-04-22T09:14:00Z'
}
}
KLAVIYO_RESPONSE {
klaviyo_event_id : 'kl_evt_0a1b2c3d4e5f' // stored in log row
}
// Action B: Google Sheets append (tab 'Notification Log')
SHEETS_ROW [
'SS-10042891', // order_id
'#1042', // order_number
'jane.smith@example.com', // customer_email
'UPS', // carrier_name
'1Z999AA10123456784', // tracking_number
'https://www.ups.com/track?...', // tracking_url
'2024-04-22T09:14:00Z', // ship_date
'2024-04-22T09:14:23Z', // send_timestamp (NOW())
'kl_evt_0a1b2c3d4e5f', // klaviyo_event_id
'sent' // status
]
// Action C: Slack digest post (channel: #fulfilment-notifications)
SLACK_MESSAGE {
text: 'Tracking notifications sent: 14 orders in last batch.
Latest: #1042 -> jane.smith@example.com via UPS.
Manual review queue: 0 items.'
}
// ============================================================
// ERROR HANDLING (all agents)
// ============================================================
// Any unhandled exception -> write to Supabase error_log table:
ERROR_LOG_ROW {
event_id : uuid
agent_name : string // 'Shipment Event Listener' | 'Notification Dispatch Agent'
action : string // e.g. 'shopify_fetch' | 'klaviyo_track' | 'sheets_append'
order_id : string
error_message : string
error_code : string
occurred_at : ISO8601
}
// -> Slack POST to #fulfilment-alerts: 'Automation error: {agent_name} | {action} | {order_id}'04Recommended build stack
More documents for this process
Every document generated for Shipping & Tracking Notification.