Back to Order Processing & Fulfilment

Integration and API Spec

The reference during the build: every tool connection, auth scope, field mapping, and error-handling rule.

4 pagesPDF · Technical
FS-DOC-05Technical

Integration and API Spec

Order Processing and Fulfilment

[YourCompany.com] · Fulfilment Department · Prepared by FullSpec · [Today's Date]

This document is the authoritative technical reference for every integration point in the Order Processing and Fulfilment automation. It covers authentication, exact API scopes, webhook configuration, field mappings, credential storage, and error handling for all six tools in the stack: Shopify, ShipStation, Linnworks, Xero, Slack, and Gmail, orchestrated through Make. The FullSpec team uses this specification to build, configure, and validate each scenario. No integration should be wired to production credentials until sandbox testing is complete against every section below.

01Tool inventory

Tool
Role in automation
Auth method
Min plan required
Used by agents
Make
Workflow orchestration and agent routing
Native (platform owner)
Core ($29/mo)
All agents
Shopify
Order source and fulfilment status target
OAuth 2.0 / Custom App API key
Basic Shopify or above (webhook support required)
Agent 1 (trigger), Agent 2, Agent 3
ShipStation
Shipment creation and label generation
HTTP Basic (API key + secret)
Starter ($99/mo) or above
Agent 2
Linnworks
Live stock verification and deduction
OAuth 2.0 (application token flow)
Standard or above
Agent 1, Agent 2
Xero
Wholesale invoice creation
OAuth 2.0 (PKCE, offline access)
Starter or above
Agent 3
Slack
Out-of-stock and exception alerts
OAuth 2.0 Bot Token (Slack App)
Free or above
Agent 1
Gmail
Customer tracking confirmation email
OAuth 2.0 (Google Workspace / personal)
Any Gmail account with API enabled
Agent 2
Before you connect anything: create and fully validate every integration in a sandbox or development environment (Shopify development store, ShipStation test mode, Linnworks sandbox, Xero demo company, Slack test workspace, Gmail test account) before any production credentials are entered into the credential store. Never hardcode production keys in Make scenario bodies.

02Per-tool integration detail

Shopify

Order source for Agent 1 trigger and fulfilment status target for Agent 2. Also provides order tag data consumed by Agent 3.

Auth method
OAuth 2.0 via Custom App in the Shopify Admin. Generate API key and secret under Settings > Apps and sales channels > Develop apps. Store both values in the credential store (see Section 04). Do not use legacy private app tokens.
Required scopes
read_orders, write_orders, read_fulfillments, write_fulfillments, read_inventory, read_products
Webhook setup
Subscribe to the orders/paid topic via Shopify Admin API POST /admin/api/2024-04/webhooks.json with format: json and address pointing to the Make webhook receiver URL. Validate the X-Shopify-Hmac-SHA256 header on every inbound request using the shared secret stored in the credential store. If HMAC validation fails, reject with HTTP 401 and log the event.
Required configuration
Shopify Order ID field used as the reconciliation key across all agents. Wholesale or B2B tag string (e.g. 'wholesale' or 'b2b') must be documented and stored as SHOPIFY_WHOLESALE_TAG in the credential store so it can be changed without a scenario edit. Fulfilment location ID must be retrieved via GET /admin/api/2024-04/locations.json and stored as SHOPIFY_LOCATION_ID.
Rate limits
REST Admin API: 2 requests/second (leaky bucket, burst to 40). At 220 orders/month (~7-8 orders/day peak) the automation will not approach the limit. No throttling module is required, but Make's built-in retry-on-429 must be enabled.
Constraints
Webhook delivery is not guaranteed on the free Shopify plan. Confirm the store is on Basic or above. Build a five-minute polling fallback scenario on GET /admin/api/2024-04/orders.json?status=paid&created_at_min={{last_run_timestamp}} as a safety net for missed webhooks.
// Trigger payload (orders/paid webhook)
order.id, order.name, order.email, order.line_items[].sku,
order.line_items[].quantity, order.shipping_address,
order.shipping_lines[].title, order.tags, order.total_price
// Write-back (fulfilment)
POST /admin/api/2024-04/orders/{order_id}/fulfillments.json
{ tracking_number, tracking_company, tracking_url, location_id }
ShipStation

Used exclusively by Agent 2 (Dispatch Agent) to create shipment records, select service levels, and retrieve tracking numbers.

Auth method
HTTP Basic Authentication. Base64-encode api_key:api_secret and pass as the Authorization header. Store api_key as SHIPSTATION_API_KEY and api_secret as SHIPSTATION_API_SECRET in the credential store.
Required scopes
ShipStation uses key-level permissions. Ensure the API key is granted: Orders (read/write), Shipments (read/write), Carriers (read). Verify in ShipStation Settings > Account > API Settings.
Webhook setup
Not used as a trigger in this automation. ShipStation is called synchronously: the scenario POSTs a shipment, then polls GET /shipments?orderNumber={id} until status equals shipped and tracking_number is populated. Set polling interval to 10 seconds with a maximum of six retries before escalating to the error handler.
Required configuration
Courier service-level mapping table must be built at setup time: each Shopify shipping_lines[].title value maps to a ShipStation carrier_code and service_code pair. Store this mapping as a JSON object in the credential store under SHIPSTATION_SERVICE_MAP. Carrier account IDs (carrier_id) are stored as SHIPSTATION_CARRIER_ID_{CARRIER}. Warehouse ID stored as SHIPSTATION_WAREHOUSE_ID.
Rate limits
Sandbox: 30 requests/min. Production: 40 requests/min. At current volume (220 orders/month) peak throughput is well under 1 request/min on average. No throttling needed. Enable Make's error-handling retry module to handle transient 429 responses with a 60-second delay.
Constraints
Labels are not generated by the API call alone; they are queued for printing. Do not treat shipment creation as label confirmation. If an unsupported service level is passed, ShipStation returns 400. The scenario must catch this and route to the error handler with a Slack alert.
// POST /orders/createorder
{ orderNumber, orderDate, orderStatus: 'awaiting_shipment',
  billTo: { name, street1, city, postalCode, country },
  shipTo: { name, street1, city, postalCode, country },
  items: [{ sku, quantity, unitPrice }],
  carrierCode, serviceCode, packageCode: 'package',
  warehouseId }
// GET /shipments?orderNumber={id} response
{ trackingNumber, carrierCode, shipDate }
Linnworks

Used by Agent 1 for real-time stock verification and by Agent 2 for post-dispatch stock deduction.

Auth method
OAuth 2.0 application token flow. Authenticate via POST https://api.linnworks.net/api/Auth/AuthorizeByApplication with ApplicationId and ApplicationSecret to receive a SessionToken valid for 30 minutes. The Make scenario must refresh the token before expiry. Store ApplicationId as LINNWORKS_APP_ID, ApplicationSecret as LINNWORKS_APP_SECRET, and cache the session token in a Make data store variable.
Required scopes
StockItems (read), Inventory (read, write). Granted at the application level in Linnworks Settings > Integration > Applications.
Webhook setup
Linnworks does not natively emit webhooks for stock events. Agent 1 calls the API synchronously on order receipt. No inbound webhook configuration is required.
Required configuration
Linnworks stock location ID stored as LINNWORKS_LOCATION_ID. SKU field in Linnworks must match Shopify line_items[].sku exactly. Any discrepancies in SKU format must be resolved before go-live (e.g. uppercase normalisation). Stock check uses POST /api/Stock/GetStockLevel with an array of StockItemIds resolved from SKUs via GET /api/Inventory/GetInventoryItems.
Rate limits
Linnworks API allows approximately 150 requests/minute per session. At 220 orders/month with an average of 2.5 line items per order, peak demand is under 10 requests/minute. No throttling module required. Implement exponential backoff on 429 and 503 responses (see Section 05).
Constraints
Concurrent stock checks for the same SKU across two near-simultaneous orders must be handled atomically. Make's scenario execution is sequential per webhook, but two webhooks arriving within milliseconds can spawn concurrent runs. Enable Make's 'Sequential processing' option on the webhook module for this scenario to prevent race conditions on low-stock SKUs.
// Stock check: POST /api/Stock/GetStockLevel
{ StockItemIds: ['uuid-sku-1', 'uuid-sku-2'] }
// Response
[ { StockItemId, Available, InOrder, MinimumLevel } ]
// Stock deduction: POST /api/Stock/SetStockLevel
{ StockItemId, LocationId, Level, ChangeSource: 'DISPATCH' }
Xero

Used exclusively by Agent 3 (Finance Agent) to create draft invoices for wholesale and B2B orders.

Auth method
OAuth 2.0 with PKCE, offline access (refresh token). Authenticate via Xero's identity server at https://identity.xero.com/connect/authorize. Store client_id as XERO_CLIENT_ID, client_secret as XERO_CLIENT_SECRET, and the refresh token as XERO_REFRESH_TOKEN. Refresh tokens expire after 60 days of non-use; the Make scenario must refresh the access token on each run and persist the new refresh token.
Required scopes
accounting.transactions, accounting.contacts.read, offline_access
Webhook setup
Not used as a trigger. Agent 3 is triggered by the Shopify wholesale tag condition within Make, not by a Xero event. No inbound Xero webhook is required.
Required configuration
Xero Tenant ID stored as XERO_TENANT_ID (retrieved via GET https://api.xero.com/connections on first auth). Contact lookup uses GET /api.xro/2.0/Contacts?where=Name.Contains("{buyer_name}") to find or create the buyer contact. Account code for sales revenue stored as XERO_SALES_ACCOUNT_CODE (e.g. '200'). Tax type stored as XERO_TAX_TYPE (e.g. 'OUTPUT2'). Invoice reference format: 'SHOPIFY-{order_name}'.
Rate limits
Xero API: 5,000 requests/day, 60 requests/minute. Wholesale orders are a subset of the 220/month total. Even at 50% wholesale, the scenario sends under 5 API calls per day. No throttling needed. Implement retry on 429 with a 65-second delay as per Xero guidance.
Constraints
Xero invoices must be created in DRAFT status only. The scenario must never set Type to AUTHORISED or submit for payment automatically. The operations manager's approval step is a hard human checkpoint. Line-item unit amounts must match Shopify line_items[].price exactly; currency must match the Xero organisation's base currency or a multi-currency add-on must be active.
// POST https://api.xero.com/api.xro/2.0/Invoices
{ Type: 'ACCREC', Status: 'DRAFT',
  Contact: { ContactID: '{xero_contact_id}' },
  Reference: 'SHOPIFY-{order_name}',
  LineItems: [{ Description, Quantity, UnitAmount,
                AccountCode: XERO_SALES_ACCOUNT_CODE,
                TaxType: XERO_TAX_TYPE }] }
Slack

Used by Agent 1 to post structured out-of-stock alerts to the fulfilment channel. Also used by the error handler across all agents for unhandled exception notifications.

Auth method
OAuth 2.0 Bot Token. Install a Slack App in the target workspace, grant the required scopes, and store the bot token as SLACK_BOT_TOKEN in the credential store. Never use the legacy incoming webhook URL for new builds.
Required scopes
chat:write, chat:write.public (if posting to channels the bot has not been explicitly invited to)
Webhook setup
Not an inbound trigger. Make calls POST https://slack.com/api/chat.postMessage with the bot token. No inbound Slack event subscription is configured for this automation.
Required configuration
Fulfilment channel ID stored as SLACK_FULFILMENT_CHANNEL_ID (use channel ID, not name, to avoid breakage on rename). Error/exception channel ID stored as SLACK_ERRORS_CHANNEL_ID. Alert message template stored in Make as a text variable, not hardcoded, so it can be updated without a scenario edit. Message must include: order ID, affected SKUs, quantities short, and a direct Shopify admin order URL.
Rate limits
Slack Tier 3: 50+ requests/minute for chat.postMessage. At current volume this limit is never approached. No throttling required.
Constraints
Bot must be added as a member of both SLACK_FULFILMENT_CHANNEL_ID and SLACK_ERRORS_CHANNEL_ID before the scenario runs. Verify channel membership during setup. If the API returns channel_not_found or not_in_channel, the scenario must log to Make's internal execution log and not silently drop the alert.
// POST https://slack.com/api/chat.postMessage
{ channel: SLACK_FULFILMENT_CHANNEL_ID,
  text: 'Out-of-stock alert',
  blocks: [
    { type: 'section', text: { type: 'mrkdwn',
      text: '*Order {order_name}* | SKUs short: {sku_list}\nQty available: {qty_map}\n<{shopify_admin_url}|View order>' }
    }
  ]
}
Gmail

Used by Agent 2 to send the personalised tracking confirmation email to the customer after ShipStation returns a tracking number.

Auth method
OAuth 2.0. Authenticate via Google's OAuth 2.0 flow at https://accounts.google.com/o/oauth2/auth with the sending Gmail account. Store client_id as GMAIL_CLIENT_ID, client_secret as GMAIL_CLIENT_SECRET, and refresh token as GMAIL_REFRESH_TOKEN. Make's native Gmail module handles token refresh automatically when configured with these credentials.
Required scopes
https://www.googleapis.com/auth/gmail.send
Webhook setup
Not an inbound trigger. Make calls the Gmail send action synchronously after the ShipStation tracking number is confirmed. No Gmail push notification subscription is required.
Required configuration
Sending address stored as GMAIL_FROM_ADDRESS (must match the authenticated account). Email subject template stored as GMAIL_SUBJECT_TEMPLATE (e.g. 'Your order {order_name} has shipped!'). Body template stored as a Make text variable with placeholders: {customer_first_name}, {order_name}, {tracking_number}, {tracking_url}, {carrier_name}. Reply-to address stored as GMAIL_REPLY_TO if different from the sending address. All template variables are stored outside the scenario body for easy updates.
Rate limits
Gmail API: 250 quota units/user/second; sending limit is 500 messages/day for standard Gmail, 2,000/day for Google Workspace. At 220 orders/month (~8/day average, ~30/day peak) the standard Gmail limit is not reached. If future volume exceeds 400 orders/month, migrate to a Google Workspace account.
Constraints
The sending account must have 'Less secure app access' disabled and OAuth used exclusively. Do not use app passwords. If the account has 2-Step Verification enforced (recommended), OAuth is the only valid auth method. Ensure the Gmail account is not subject to a daily send cap imposed by a Google Workspace admin policy.
// Gmail send action (Make module: Gmail > Send an Email)
{ to: order.email,
  from: GMAIL_FROM_ADDRESS,
  replyTo: GMAIL_REPLY_TO,
  subject: 'Your order {order_name} has shipped!',
  content: '{customer_first_name}, your order is on its way.\n
             Carrier: {carrier_name}\n
             Tracking: {tracking_url}' }
Integration and API SpecPage 1 of 4
FS-DOC-05Technical

03Field mappings between tools

The following tables define the exact field translations at each agent handoff point. Field names are shown in their native API form. Any transformation logic (e.g. concatenation, type cast, lookup) is noted in the Destination field column.

Agent 1 handoff: Shopify to Linnworks (stock check)

Source tool
Source field
Destination tool
Destination field
Shopify
order.line_items[n].sku
Linnworks
Inventory.GetInventoryItems: SKU (used to resolve StockItemId)
Shopify
order.line_items[n].quantity
Linnworks
Stock.GetStockLevel: compare against Available (flag if quantity > Available)
Shopify
order.id
Make data store
shopify_order_id (carried as context key through all subsequent steps)
Shopify
order.name
Make data store
shopify_order_name (e.g. '#1042', used in all alert and email templates)

Agent 1 handoff: Shopify + Linnworks to Slack (out-of-stock alert)

Source tool
Source field
Destination tool
Destination field
Shopify
order.name
Slack
blocks[0].text: '{order_name}' placeholder
Shopify
order.id
Slack
blocks[0].text: Shopify admin URL constructed as 'https://{shop}.myshopify.com/admin/orders/{order_id}'
Linnworks
StockItemId (resolved SKU)
Slack
blocks[0].text: '{sku_list}' placeholder (comma-separated list of short SKUs)
Linnworks
Available (per StockItemId)
Slack
blocks[0].text: '{qty_map}' placeholder (SKU: available qty pairs)

Agent 2 handoff: Shopify to ShipStation (shipment creation)

Source tool
Source field
Destination tool
Destination field
Shopify
order.name
ShipStation
orderNumber
Shopify
order.created_at
ShipStation
orderDate (ISO 8601, no transform needed)
Shopify
order.shipping_address.name
ShipStation
shipTo.name
Shopify
order.shipping_address.address1
ShipStation
shipTo.street1
Shopify
order.shipping_address.address2
ShipStation
shipTo.street2 (pass empty string if null)
Shopify
order.shipping_address.city
ShipStation
shipTo.city
Shopify
order.shipping_address.province_code
ShipStation
shipTo.state
Shopify
order.shipping_address.zip
ShipStation
shipTo.postalCode
Shopify
order.shipping_address.country_code
ShipStation
shipTo.country (ISO 3166-1 alpha-2)
Shopify
order.shipping_lines[0].title
ShipStation
carrierCode + serviceCode (via SHIPSTATION_SERVICE_MAP lookup)
Shopify
order.line_items[n].sku
ShipStation
items[n].sku
Shopify
order.line_items[n].quantity
ShipStation
items[n].quantity
Shopify
order.line_items[n].price
ShipStation
items[n].unitPrice (string to float cast)
Shopify
order.email
ShipStation
customerEmail
Make store
SHIPSTATION_WAREHOUSE_ID
ShipStation
warehouseId

Agent 2 handoff: ShipStation to Shopify (tracking writeback)

Source tool
Source field
Destination tool
Destination field
ShipStation
trackingNumber
Shopify
fulfillment.tracking_number
ShipStation
carrierCode
Shopify
fulfillment.tracking_company (mapped via carrier display name lookup)
ShipStation
trackingUrl
Shopify
fulfillment.tracking_url
Make store
SHOPIFY_LOCATION_ID
Shopify
fulfillment.location_id

Agent 2 handoff: ShipStation + Shopify to Gmail (tracking email)

Source tool
Source field
Destination tool
Destination field
Shopify
order.email
Gmail
to
Shopify
order.shipping_address.first_name
Gmail
{customer_first_name} template placeholder
Shopify
order.name
Gmail
{order_name} template placeholder
ShipStation
trackingNumber
Gmail
{tracking_number} template placeholder
ShipStation
trackingUrl
Gmail
{tracking_url} template placeholder
ShipStation
carrierCode
Gmail
{carrier_name} template placeholder (human-readable via lookup)

Agent 2 handoff: Shopify to Linnworks (stock deduction)

Source tool
Source field
Destination tool
Destination field
Shopify
order.line_items[n].sku
Linnworks
Stock.SetStockLevel: StockItemId (resolved via SKU lookup)
Shopify
order.line_items[n].quantity
Linnworks
Stock.SetStockLevel: decrement Level by quantity
Make store
LINNWORKS_LOCATION_ID
Linnworks
Stock.SetStockLevel: LocationId

Agent 3 handoff: Shopify to Xero (draft invoice creation)

Source tool
Source field
Destination tool
Destination field
Shopify
order.name
Xero
Reference (formatted as 'SHOPIFY-{order_name}')
Shopify
order.billing_address.name
Xero
Contact.Name (used for contact lookup or creation)
Shopify
order.line_items[n].title
Xero
LineItems[n].Description
Shopify
order.line_items[n].quantity
Xero
LineItems[n].Quantity
Shopify
order.line_items[n].price
Xero
LineItems[n].UnitAmount (string to float cast)
Make store
XERO_SALES_ACCOUNT_CODE
Xero
LineItems[n].AccountCode
Make store
XERO_TAX_TYPE
Xero
LineItems[n].TaxType
Integration and API SpecPage 2 of 4
FS-DOC-05Technical

04Build stack and orchestration

Orchestration platform
Make (formerly Integromat), Core plan ($29/month). All automation logic is implemented as Make scenarios.
Scenario layout
One scenario per agent: 'FS-01 Order Intake Agent', 'FS-02 Dispatch Agent', 'FS-03 Finance Agent'. Agents are chained via Make's webhook-to-webhook call or a shared Make data store key, not via external message queues.
Credential store
All secrets stored in Make's native Connections (for OAuth tools) and as encrypted Custom Variables (for non-OAuth key/secret pairs and configuration constants). No credential is hardcoded in any module's field. See credential list below.
Agent 1 trigger mechanism
Inbound webhook: Shopify orders/paid webhook posts to Make's dedicated webhook receiver URL for FS-01. X-Shopify-Hmac-SHA256 signature is validated in the first router module. Sequential processing is enabled to prevent concurrent low-stock race conditions. Polling fallback scenario (FS-01-POLL) runs every five minutes using GET /admin/api/2024-04/orders.json?status=paid&created_at_min={{last_checked}} as a safety net.
Agent 2 trigger mechanism
Webhook from Agent 1: on stock-verified order, FS-01 calls FS-02's internal Make webhook URL with the full order payload. FS-02 does not subscribe to Shopify directly. No signature validation is required on this internal call because it never leaves Make's infrastructure (use Make's own scenario chaining module).
Agent 3 trigger mechanism
Webhook from Agent 1: after stock check, FS-01 evaluates order.tags for the SHOPIFY_WHOLESALE_TAG value. If matched, FS-01 calls FS-03's internal Make webhook URL in parallel with FS-02. FS-03 can also be triggered independently by a Shopify order.updated webhook if wholesale tags are added after the initial order creation.
Data persistence
A Make Data Store ('FS-OrderState') holds transient order context (shopify_order_id, processing_stage, last_error) keyed by order ID. Records are written at each stage transition and deleted after successful completion or after 48-hour expiry to bound storage size.
Monitoring
Make's built-in execution history is used as the primary run log. All error-handler routes post to SLACK_ERRORS_CHANNEL_ID with scenario name, order ID, error code, and timestamp. Email alerts from Make's native 'Send an email on error' setting are directed to support@gofullspec.com during the build and handoff period.

Credential store contents (all values stored as Make encrypted Custom Variables or native Connections, never in module field bodies):

All values are placeholders. Replace with real credentials before go-live. Never commit these values to version control.
// Shopify
SHOPIFY_API_KEY              = '<custom_app_api_key>'
SHOPIFY_API_SECRET           = '<custom_app_api_secret>'
SHOPIFY_WEBHOOK_SECRET       = '<hmac_shared_secret>'
SHOPIFY_SHOP_DOMAIN          = '<store>.myshopify.com'
SHOPIFY_LOCATION_ID          = '<fulfilment_location_id>'
SHOPIFY_WHOLESALE_TAG        = 'wholesale'   // or 'b2b' — confirm with owner

// ShipStation
SHIPSTATION_API_KEY          = '<api_key>'
SHIPSTATION_API_SECRET       = '<api_secret>'
SHIPSTATION_WAREHOUSE_ID     = '<warehouse_id>'
SHIPSTATION_CARRIER_ID_UPS   = '<ups_carrier_id>'
SHIPSTATION_CARRIER_ID_USPS  = '<usps_carrier_id>'
SHIPSTATION_SERVICE_MAP      = '{"Standard Shipping":{"carrierCode":"stamps_com","serviceCode":"usps_first_class_mail"}, "Express":{"carrierCode":"ups","serviceCode":"ups_next_day_air"}}'

// Linnworks
LINNWORKS_APP_ID             = '<application_id>'
LINNWORKS_APP_SECRET         = '<application_secret>'
LINNWORKS_LOCATION_ID        = '<primary_warehouse_location_id>'

// Xero
XERO_CLIENT_ID               = '<oauth_client_id>'
XERO_CLIENT_SECRET           = '<oauth_client_secret>'
XERO_REFRESH_TOKEN           = '<offline_refresh_token>'   // updated on every token refresh
XERO_TENANT_ID               = '<xero_organisation_tenant_id>'
XERO_SALES_ACCOUNT_CODE      = '200'
XERO_TAX_TYPE                = 'OUTPUT2'

// Slack
SLACK_BOT_TOKEN              = 'xoxb-<bot_token>'
SLACK_FULFILMENT_CHANNEL_ID  = '<channel_id>'
SLACK_ERRORS_CHANNEL_ID      = '<channel_id>'

// Gmail
GMAIL_CLIENT_ID              = '<oauth_client_id>'
GMAIL_CLIENT_SECRET          = '<oauth_client_secret>'
GMAIL_REFRESH_TOKEN          = '<oauth_refresh_token>'
GMAIL_FROM_ADDRESS           = 'orders@[YourCompany.com]'
GMAIL_REPLY_TO               = 'support@[YourCompany.com]'
GMAIL_SUBJECT_TEMPLATE       = 'Your order {order_name} has shipped!'
The Xero XERO_REFRESH_TOKEN must be written back to the credential store after every successful token refresh. If the Make scenario fails to persist the new refresh token, the next execution will fail authentication. Build a dedicated token-refresh sub-scenario that runs every 50 minutes and updates the stored value.
Integration and API SpecPage 3 of 4
FS-DOC-05Technical

05Error handling and retry logic

Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. All error routes must post to SLACK_ERRORS_CHANNEL_ID with at minimum: scenario name, order ID, failing module, HTTP status code, and error message body. Make's 'Break' error-handling directive is used for retryable errors; 'Ignore' is never used on integration modules.

Integration
Scenario
Required behaviour
Shopify webhook (inbound)
HMAC signature validation fails
Reject with HTTP 401. Do not process the payload. Post to SLACK_ERRORS_CHANNEL_ID with raw header values for forensic review. Do not retry.
Shopify webhook (inbound)
Missed webhook (no delivery within 5 min of order creation)
Polling fallback scenario (FS-01-POLL) picks up unprocesed paid orders on its next 5-minute cycle. Deduplicate by order ID in the FS-OrderState data store before processing.
Linnworks: stock check
API returns 401 (session token expired)
Re-authenticate immediately via POST /api/Auth/AuthorizeByApplication. Retry the failed request once with the new token. If re-auth fails, post to SLACK_ERRORS_CHANNEL_ID and halt the order's processing. Write status 'auth_failure' to FS-OrderState.
Linnworks: stock check
API returns 429 or 503
Exponential backoff: wait 2 s, 4 s, 8 s, 16 s, then 32 s before each retry (maximum 5 attempts). If all retries fail, post to SLACK_ERRORS_CHANNEL_ID. Do not proceed to ShipStation. Mark order as 'stock_check_failed' in FS-OrderState.
Linnworks: stock deduction (Agent 2)
API call fails after dispatch
Retry with exponential backoff up to 3 times. If all retries fail, post a critical alert to SLACK_ERRORS_CHANNEL_ID specifying the order ID and SKUs that were NOT decremented so a team member can manually adjust stock. Do not roll back the ShipStation shipment.
ShipStation: shipment creation
API returns 400 (invalid service level or missing field)
Do not retry. Log the full request body and error response to SLACK_ERRORS_CHANNEL_ID. Flag the order in FS-OrderState as 'dispatch_failed_validation'. A team member must create the ShipStation shipment manually and trigger the tracking writeback sub-scenario.
ShipStation: shipment creation
API returns 429 or 5xx
Retry up to 4 times with a 60-second fixed delay (ShipStation rate limit window is 60 s). If all retries fail, post to SLACK_ERRORS_CHANNEL_ID and set order state to 'dispatch_failed_transient'. Add to a manual review queue.
ShipStation: tracking number poll
Tracking number not returned within 6 polls (60 s total)
Post to SLACK_ERRORS_CHANNEL_ID with order ID. Pause the scenario for 5 minutes, then retry the polling cycle once more. If still unresolved after 2 full cycles, escalate to manual and mark order state as 'tracking_pending'.
Shopify: fulfilment writeback
API returns 422 (order already fulfilled or location mismatch)
Check if fulfilment already exists via GET /fulfillments. If duplicate, skip and continue to Gmail send. If location mismatch, post to SLACK_ERRORS_CHANNEL_ID with the location_id conflict detail. Do not retry blindly.
Gmail: send tracking email
API returns 400 or 429
Retry up to 3 times with a 30-second delay. If all retries fail, post to SLACK_ERRORS_CHANNEL_ID with the customer email address and order name so the team can send the confirmation manually. Do not let the failure block Linnworks stock deduction.
Xero: draft invoice creation
Contact not found and contact creation fails
Post to SLACK_ERRORS_CHANNEL_ID specifying the buyer name and Shopify order reference. Create the invoice with a placeholder contact ('UNKNOWN-{order_name}') in DRAFT status so no data is lost. Flag for manual contact resolution by the operations manager.
Xero: draft invoice creation
OAuth refresh token expired or revoked
Post a critical alert to SLACK_ERRORS_CHANNEL_ID. Do not attempt to create the invoice. The FullSpec team must re-authorise the Xero connection and update XERO_REFRESH_TOKEN in the credential store before the next wholesale order is processed. Affected orders are queued in FS-OrderState under status 'xero_auth_failed'.
Slack: alert delivery (any agent)
chat.postMessage returns channel_not_found or not_in_channel
Log the failure to Make's execution history. Attempt delivery to SLACK_ERRORS_CHANNEL_ID as a fallback. If that also fails, send an alert email via Make's native error email setting to support@gofullspec.com. Unhandled exceptions must never fail silently.
All error states written to the FS-OrderState data store are reviewed as part of the weekly health check during the first four weeks post-go-live. The FullSpec team will review Make execution logs and resolve any recurring error patterns. Contact support@gofullspec.com for urgent escalations.
Integration and API SpecPage 4 of 4

More documents for this process

Every document generated for Order Processing & Fulfilment.

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