Back to Shipping & Tracking Notification

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

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

Step
Name
Description
1
Check for New Shipments
Fulfilment Coordinator opens ShipStation manually each morning and afternoon to identify orders assigned a tracking number. Owner: Fulfilment Coordinator. Time cost: 15 min/cycle.
2 BOTTLENECK
Export Shipped Orders List
Coordinator exports or hand-copies newly shipped orders including tracking numbers and carrier names into a Google Sheet or notepad. Root cause of data lag and transcription errors. Time cost: 20 min/cycle.
3
Match Orders to Customer Emails
For each shipped order the coordinator looks up the customer email in Shopify to confirm the correct send address. Time cost: 15 min/cycle.
4 BOTTLENECK
Build Tracking Links
Coordinator constructs the carrier tracking URL by hand, appending the tracking number to the carrier base URL one by one. Highest error rate in the process. Time cost: 20 min/cycle.
5
Draft and Personalise Notification Email
A Gmail template is opened and the coordinator manually fills in customer name, order number, carrier name, and tracking link for each order. Time cost: 30 min/cycle.
6
Send Notification Emails
Each email is sent individually in Gmail; at high volumes this means dozens of manual send actions per session. Time cost: 20 min/cycle.
7
Log Notification in Tracker Sheet
Coordinator marks each order row in Google Sheets as Notified with a timestamp. Time cost: 15 min/cycle.
8
Handle Failed or Bounced Notifications
Customer Service Rep investigates and resends any bounced or undeliverable emails, often requiring alternate contact lookup. Time cost: 20 min/cycle.
9 BOTTLENECK
Respond to WISMO Support Tickets
Customers who never received tracking email the support queue; a rep retrieves the tracking number and replies individually. Downstream consequence of steps 2 and 4 errors. Time cost: 25 min/cycle.
Time cost summary: Total manual time per cycle is 180 minutes (3 hours). At two cycles per day across a 5-day week this equates to approximately 6 hours of manual labour per week, or 300 hours per year at the assumed rate of $29/hr, totalling $9,100/year. The automation replaces steps 1 through 7 entirely. Steps 8 and 9 are reduced in frequency but remain human-owned for genuine exceptions.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Shipment Event Listener

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.

Trigger
ShipStation order status changes to 'Shipped' with a non-null tracking number, detected via webhook (primary) or timed poll every 10 minutes (fallback).
Tools
ShipStation (order event source and tracking data), Shopify (order and customer detail lookup).
Replaces steps
Steps 1, 2, 3, and 4: manual shipment checking, order export, customer email matching, and tracking URL construction.
Estimated build
14 hours. Complexity: Moderate.
// 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.
Notification Dispatch Agent

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.

Trigger
A valid structured shipment data object is received from the Shipment Event Listener with email_valid set to true.
Tools
Klaviyo (transactional email dispatch), Google Sheets (notification audit log and manual review tab), Slack (daily dispatch digest).
Replaces steps
Steps 5, 6, and 7: email drafting and personalisation, individual email sending, and Google Sheets notification logging.
Estimated build
10 hours. Complexity: Moderate.
// 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.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow with field names at every stage. All field names match the Shopify Admin REST API 2024-01 and Klaviyo Events API v2 responses.
// ============================================================
// 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}'
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation platform (not yet specified; selection to be confirmed at project kickoff). Recommended pattern: one workflow per agent (two workflows total), plus a shared credential store accessible by both. No agent-specific credential duplication. Workflow naming convention: '[Client]-ShipmentEventListener' and '[Client]-NotificationDispatchAgent'.
Webhook configuration
Register the automation platform's inbound webhook URL in ShipStation under Settings > Integrations > Webhooks. Event type: SHIP_NOTIFY. Payload format: JSON. The webhook URL must use HTTPS and include a static secret header (X-ShipStation-Signature) validated at the workflow entry node. Enable polling fallback (10-minute interval) during initial testing before the webhook is confirmed stable in production.
Templating approach
All email content and layout is owned entirely within Klaviyo. The automation platform passes only the variable data payload (order_number, customer_name, carrier_name, tracking_url, ship_date) to the Klaviyo Track API. No email HTML or Liquid templating is constructed inside the workflow. Klaviyo manages suppression lists, unsubscribe handling, and template versioning independently.
Error logging
A Supabase table named 'automation_error_log' stores all workflow exceptions with fields: event_id (uuid primary key), agent_name, action, order_id, error_message, error_code, occurred_at. A Slack alert fires to #fulfilment-alerts for every new error row. The FullSpec team reviews the error log weekly during the first 30 days post-launch. After 30 days, alerts are sufficient and the log is reviewed on demand.
Testing approach
All agent builds are tested in sandbox environments before connecting to production systems. ShipStation provides a sandbox mode; Shopify testing uses a development store with cloned order data. Klaviyo testing uses a dedicated test profile with a FullSpec email address to confirm template rendering without triggering real customer sends. Google Sheets logging is tested against a duplicate staging spreadsheet. The final two-day parallel run fires the automation alongside the existing manual process to confirm output parity before the manual process is retired.
Estimated total build time
Shipment Event Listener: 14 hours. Notification Dispatch Agent: 10 hours. End-to-end integration testing, parallel run validation, error log setup, and handover documentation: 4 hours. Total: 28 hours across a 4-week delivery schedule.
Credential pre-requisites before any build node is activated: (1) ShipStation API key and secret with webhook write access confirmed. (2) Shopify custom app installed on the production store with read_orders and read_customers scopes. (3) Klaviyo private API key scoped to Events: Write, and the 'Shipment Dispatched' transactional flow approved and active in Klaviyo. (4) Google Sheets service account JSON with Editor access to the target spreadsheet. (5) Slack app with chat:write scope installed in the target workspace. All credentials are stored in the shared credential store only. Contact support@gofullspec.com if any credential cannot be obtained before the scheduled build start date.
Open decisions to resolve before build week 2: confirm the full list of active ShipStation carrier codes in use; confirm whether partial shipments or split orders should trigger the agent; confirm Google Sheets spreadsheet ID and exact tab names; confirm Slack channel names for standard digest and error alerts; confirm whether a Klaviyo suppression or consent check is required at the flow level.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Shipping & Tracking Notification.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View