Back to Multichannel Inventory Sync

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

Multichannel Inventory Sync

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

This document is the definitive integration reference for the Multichannel Inventory Sync automation. It covers every tool connected to the two agents (Stock Level Sync Agent and Reorder Alert and Finance Sync Agent), the exact OAuth scopes and API credentials required, field-level mappings between systems, orchestration layout, and the full error-handling and retry matrix. FullSpec uses this document to build, configure, and validate every integration node. No production credentials should be entered until sandbox testing is complete for each connection.

01Tool inventory

Tool
Role in automation
Auth method
Min plan required
Used by agents
Orchestration layer
Hosts all workflows, credential store, and inter-agent handoffs
Internal (platform credentials)
Any self-hosted or cloud tier with webhook support
All
Linnworks
Central inventory source of truth: stock-level reads, return and PO receipt event triggers
OAuth 2.0 (server-side token)
Linnworks Standard or above (API access enabled)
Agent 1
Shopify
Storefront inventory API target: read and write inventory levels per location
OAuth 2.0 (private app token or custom app)
Basic Shopify or above
Agent 1
Amazon Seller Central
Marketplace inventory API target: submit quantity updates via SP-API
OAuth 2.0 + LWA (Login with Amazon)
Individual or Professional seller account with SP-API access
Agent 1
Google Sheets
Audit log writer and reorder threshold reference store
OAuth 2.0 (Google service account)
Google Workspace or personal Google account with Sheets API enabled
Agents 1 and 2
Slack
Low-stock alert delivery to buying team channel
OAuth 2.0 (Bot token, Slack app)
Free tier or above
Agent 2
Xero
Finance inventory journal entry posting
OAuth 2.0 (PKCE flow, Xero app)
Xero Starter or above (accounting API access)
Agent 2
Before you connect anything: create sandbox or staging credentials for every tool listed above and test each connection end-to-end in a non-production environment before any production credentials are entered into the credential store. For Shopify, use a development store. For Xero, use the Xero demo company. For Amazon, use the SP-API sandbox environment. For Linnworks, use a cloned staging account if available. Production cutover happens only after all test cases in the QA plan pass on staging.
Integration and API SpecPage 1 of 4
FS-DOC-05Technical

02Per-tool integration detail

Linnworks

Acts as the single source of truth for on-hand stock quantities. The automation reads current inventory levels per SKU after every triggering event, and also listens for return confirmations and purchase order receipts originating inside Linnworks.

Auth method
OAuth 2.0 server-side flow. Application ID and secret issued from the Linnworks developer portal. Token endpoint: https://api.linnworks.net/api/Auth/AuthorizeByApplication. Access tokens expire after 30 minutes; refresh automatically using the stored refresh token.
Required scopes
StockControl.StockLevels.Read, StockControl.StockLevels.Write, Orders.Read, PurchaseOrders.Read, Returns.Read
Webhook / trigger setup
Linnworks exposes a webhook registration endpoint (POST /api/Webhooks/Register). Register webhooks for events: ORDER_UPDATED, PURCHASE_ORDER_RECEIVED, RETURN_CONFIRMED. Webhook payloads are sent as JSON POST to the orchestration layer inbound URL. Validate the shared HMAC-SHA256 signature header (X-Linnworks-Signature) on every inbound request before processing.
Required configuration
Store the Linnworks Application ID, Application Secret, and refresh token in the credential store (keys: LINNWORKS_APP_ID, LINNWORKS_APP_SECRET, LINNWORKS_REFRESH_TOKEN). The default location ID for the primary warehouse must be stored as LINNWORKS_LOCATION_ID. Do not hardcode any of these values.
Rate limits
Linnworks API allows 500 requests per minute per application. At the current volume of ~320 events per month (approximately 11 events per day), the automation will generate at most 5 to 10 API calls per event burst. No throttling logic is required at this volume; implement a basic 200ms inter-request delay as a precaution.
Constraints
Linnworks must be configured as the authoritative stock source before go-live. If Shopify or Amazon also writes quantities to Linnworks independently, a tiebreaker rule must be defined. The automation does not write quantities back to Linnworks directly; Linnworks is read-only from the automation's perspective unless a return or PO event explicitly instructs an adjustment.
// Input (webhook payload excerpt)
{ "EventType": "ORDER_UPDATED", "OrderId": "LW-00421",
  "Items": [{ "SKU": "TSHIRT-BLK-M", "Quantity": 2 }] }

// Read call
GET /api/Stock/GetStockLevel
  Body: { "skuList": ["TSHIRT-BLK-M"] }

// Output (stock level response excerpt)
{ "SKU": "TSHIRT-BLK-M", "Available": 48, "Location": "Main Warehouse" }
Shopify

Receives updated inventory quantities for each affected SKU after the sync calculation. The automation targets the Shopify Inventory API to set the on-hand quantity at the configured location.

Auth method
OAuth 2.0 custom app. Create a custom app in the Shopify Admin (Apps > Develop apps). Generate an Admin API access token. Store as SHOPIFY_STORE_URL and SHOPIFY_ACCESS_TOKEN in the credential store.
Required scopes
read_inventory, write_inventory, read_products, read_locations
Webhook / trigger setup
Shopify webhooks are registered for orders/paid and orders/cancelled via POST /admin/api/2024-01/webhooks.json. Validate the X-Shopify-Hmac-SHA256 header (HMAC-SHA256 of raw body using SHOPIFY_WEBHOOK_SECRET stored in the credential store). Shopify sends webhooks as HTTP POST with JSON body.
Required configuration
Store SHOPIFY_STORE_URL (e.g. yourcompany.myshopify.com), SHOPIFY_ACCESS_TOKEN, SHOPIFY_LOCATION_ID (the primary fulfilment location ID, retrieved once via GET /admin/api/2024-01/locations.json and stored), and SHOPIFY_WEBHOOK_SECRET in the credential store. Never hardcode.
Rate limits
Shopify REST API enforces 2 requests/second (leaky bucket, 40 request burst). At current volume this is not a concern. The orchestration layer must respect the Retry-After header on any 429 response and implement exponential backoff starting at 1 second.
Constraints
Inventory levels in Shopify are location-specific. The automation must use inventory_item_id (not SKU directly) when calling POST /admin/api/2024-01/inventory_levels/set.json. The mapping from SKU to inventory_item_id must be resolved once per SKU via GET /admin/api/2024-01/products.json and cached in Google Sheets or the credential store.
// Inventory update call
POST /admin/api/2024-01/inventory_levels/set.json
Headers: { X-Shopify-Access-Token: <SHOPIFY_ACCESS_TOKEN> }
Body: {
  "location_id": "<SHOPIFY_LOCATION_ID>",
  "inventory_item_id": "<resolved_item_id>",
  "available": 46
}

// Success response
HTTP 200 { "inventory_level": { "available": 46 } }
Amazon Seller Central (SP-API)

Receives updated quantities via the Amazon Selling Partner API (SP-API) Listings Items API. The automation submits a quantity patch for each affected ASIN/SKU pair. Amazon-side visibility may lag 2 to 5 minutes after submission.

Auth method
OAuth 2.0 with Login with Amazon (LWA). Register a Selling Partner application in Seller Central. Store the LWA Client ID, Client Secret, Refresh Token, and AWS credentials (access key, secret key, IAM role ARN) in the credential store. Access tokens expire after 1 hour; refresh before each call batch.
Required scopes
sellingpartnerapi::inventory (SP-API scope, granted at app registration). AWS IAM policy must allow sts:AssumeRole for the SP-API execution role.
Webhook / trigger setup
SP-API does not support outbound webhooks for order events in all marketplaces. The orchestration layer polls the Orders API (GET /orders/v0/orders) on a 5-minute schedule to detect new orders and cancellations. Use the CreatedAfter parameter set to the last successful poll timestamp (stored in the credential store as AMAZON_LAST_POLL_TS).
Required configuration
Store AMAZON_LWA_CLIENT_ID, AMAZON_LWA_CLIENT_SECRET, AMAZON_REFRESH_TOKEN, AMAZON_SELLER_ID, AMAZON_MARKETPLACE_ID (e.g. ATVPDKIKX0DER for US), AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AMAZON_ROLE_ARN, and AMAZON_LAST_POLL_TS in the credential store.
Rate limits
SP-API Listings Items PATCH endpoint: 5 requests/second burst, 2 requests/second restore. Orders API: 0.0167 requests/second (1 per minute). At current volume (approximately 320 events/month across all channels, with Amazon as one channel) polling and update calls are well within limits. Implement a 500ms delay between sequential SKU patches in a single event batch.
Constraints
Amazon SP-API requires Signature Version 4 (SigV4) signing on every request. Use the stored AWS credentials to sign. The Listings Items API requires the ASIN and the seller SKU. The SKU-to-ASIN mapping must be pre-populated in the Google Sheets reference tab (sheet: SKU_MAP) before go-live. Submitted quantity changes are not immediately visible on the live listing; inform the operations team of the expected 2 to 5 minute propagation lag.
// Token refresh
POST https://api.amazon.com/auth/o2/token
Body: { grant_type: refresh_token, refresh_token: <AMAZON_REFRESH_TOKEN>,
        client_id: <AMAZON_LWA_CLIENT_ID>, client_secret: <AMAZON_LWA_CLIENT_SECRET> }

// Quantity patch
PATCH /listings/2021-08-01/items/<AMAZON_SELLER_ID>/<seller_sku>
  ?marketplaceIds=<AMAZON_MARKETPLACE_ID>
Body: { "productType": "PRODUCT", "patches": [
  { "op": "replace", "path": "/attributes/fulfillment_availability",
    "value": [{ "fulfillment_channel_code": "DEFAULT", "quantity": 46 }] }
] }
Google Sheets

Serves two roles: audit log (append one row per sync event) and reference store (reorder thresholds per SKU and the SKU-to-platform-ID mapping table). Both roles use the Google Sheets API v4.

Auth method
OAuth 2.0 via a Google service account. Create a service account in Google Cloud Console, download the JSON key file, and share the target spreadsheet with the service account email (Editor access). Store the service account JSON key as GOOGLE_SERVICE_ACCOUNT_JSON in the credential store.
Required scopes
https://www.googleapis.com/auth/spreadsheets
Webhook / trigger setup
Google Sheets does not push events. The automation writes to Sheets (append and read). No inbound webhook configuration is required for this tool.
Required configuration
Store GOOGLE_SPREADSHEET_ID (the ID from the sheet URL), GOOGLE_AUDIT_SHEET_NAME (sheet tab name, e.g. Audit_Log), GOOGLE_THRESHOLD_SHEET_NAME (e.g. Reorder_Thresholds), and GOOGLE_SKU_MAP_SHEET_NAME (e.g. SKU_Map) in the credential store. Column headers for Audit_Log must be pre-created: Timestamp, Event_Type, SKU, Old_Qty, New_Qty, Channel, Status, Notes. Reorder_Thresholds must have columns: SKU, Reorder_Point, Supplier_Code. SKU_Map must have columns: SKU, Shopify_Inventory_Item_ID, Amazon_ASIN, Linnworks_Stock_Item_ID.
Rate limits
Google Sheets API allows 300 read/write requests per minute per project. Each sync event appends one row (1 write) and may read the threshold sheet (1 read). At 320 events per month this is approximately 640 calls per month, far below the limit. No throttling logic is required.
Constraints
The service account JSON key must never be committed to source control. Rotate the key at least every 12 months. The spreadsheet must be accessible to the service account before the automation goes live. If the spreadsheet is deleted or the service account access is revoked, both agents will fail silently unless error handling routes to a fallback alert.
// Append audit row
POST https://sheets.googleapis.com/v4/spreadsheets/<GOOGLE_SPREADSHEET_ID>
     /values/Audit_Log!A:H:append?valueInputOption=USER_ENTERED
Body: { "values": [[
  "2024-06-17T09:14:02Z", "ORDER", "TSHIRT-BLK-M",
  48, 46, "Shopify", "Success", ""
]] }

// Read threshold for SKU
GET https://sheets.googleapis.com/v4/spreadsheets/<GOOGLE_SPREADSHEET_ID>
    /values/Reorder_Thresholds!A:C
Slack

Receives structured low-stock alert messages posted by the Reorder Alert and Finance Sync Agent when any SKU quantity falls at or below its configured reorder threshold.

Auth method
OAuth 2.0 Bot token. Create a Slack app at api.slack.com/apps, add the bot to the workspace, and install to the target channel. Store the Bot OAuth token as SLACK_BOT_TOKEN in the credential store.
Required scopes
chat:write, chat:write.public, channels:read
Webhook / trigger setup
No inbound webhook is required. The automation posts outbound messages using the Slack Web API (chat.postMessage). The target channel ID must be stored as SLACK_BUYING_CHANNEL_ID in the credential store. Obtain the channel ID from the channel settings in Slack (not the channel name, which can be renamed).
Required configuration
Store SLACK_BOT_TOKEN and SLACK_BUYING_CHANNEL_ID in the credential store. The alert message must use Block Kit JSON for consistent formatting. A message template is defined in the orchestration layer workflow configuration, not hardcoded in code.
Rate limits
Slack Tier 3 rate limit: 50+ requests/minute for chat.postMessage. At current volume, the automation will post at most a handful of messages per sync run. No throttling required. Respect the Retry-After header on any 429 response.
Constraints
The bot must be invited to the target channel before any message can be sent. If the channel is private, the bot must be explicitly added. Channel ID changes if the channel is deleted and recreated; SLACK_BUYING_CHANNEL_ID must be updated in the credential store if this happens.
// Post low-stock alert
POST https://slack.com/api/chat.postMessage
Headers: { Authorization: Bearer <SLACK_BOT_TOKEN> }
Body: {
  "channel": "<SLACK_BUYING_CHANNEL_ID>",
  "blocks": [
    { "type": "header", "text": { "type": "plain_text",
        "text": "Low Stock Alert" } },
    { "type": "section", "fields": [
        { "type": "mrkdwn", "text": "*SKU:* TSHIRT-BLK-M" },
        { "type": "mrkdwn", "text": "*Current Qty:* 4" },
        { "type": "mrkdwn", "text": "*Reorder Point:* 10" }
    ] }
  ]
}
Xero

Receives an inventory movement journal entry after each confirmed stock sync. The Reorder Alert and Finance Sync Agent posts a manual journal to Xero recording the change in inventory asset value.

Auth method
OAuth 2.0 PKCE flow via a Xero app registered at developer.xero.com. The app must be connected to the correct Xero organisation. Store XERO_CLIENT_ID, XERO_CLIENT_SECRET, XERO_REFRESH_TOKEN, and XERO_TENANT_ID in the credential store. Access tokens expire after 30 minutes; refresh before each posting call.
Required scopes
accounting.transactions, accounting.settings.read, offline_access
Webhook / trigger setup
No inbound webhook from Xero is required. The automation posts outbound journal entries. Xero does support outbound webhooks for payment and invoice events, but these are not used in this process.
Required configuration
Store XERO_INVENTORY_ASSET_ACCOUNT_CODE (the Xero account code for the inventory asset ledger, e.g. 630), XERO_COGS_ACCOUNT_CODE (e.g. 310), and XERO_TENANT_ID in the credential store. The journal narration template must be defined in the orchestration layer workflow config. Do not hardcode account codes.
Rate limits
Xero API enforces 60 API calls per minute per connection and a daily limit of 5,000 calls. Each sync event generates one journal POST. At 320 events per month this is approximately 11 calls per day, negligible against both limits. No throttling required.
Constraints
Manual journals in Xero require the JournalLines array to balance (debits equal credits). The automation must calculate the inventory value delta using the unit cost stored in the Google Sheets SKU_Map tab (column: Unit_Cost) before constructing the journal payload. If the unit cost is missing for a SKU, the journal post must be skipped and an error alert sent to the Slack buying channel.
// Token refresh
POST https://identity.xero.com/connect/token
Body: { grant_type: refresh_token, refresh_token: <XERO_REFRESH_TOKEN>,
        client_id: <XERO_CLIENT_ID>, client_secret: <XERO_CLIENT_SECRET> }

// Post manual journal
POST https://api.xero.com/api.xro/2.0/ManualJournals
Headers: { Authorization: Bearer <access_token>,
           Xero-tenant-id: <XERO_TENANT_ID> }
Body: {
  "Narration": "Inventory movement: TSHIRT-BLK-M | ORDER | 2024-06-17",
  "JournalLines": [
    { "LineAmount": -4.50, "AccountCode": "630", "Description": "Stock reduction" },
    { "LineAmount":  4.50, "AccountCode": "310", "Description": "COGS" }
  ]
}
Integration and API SpecPage 2 of 4
FS-DOC-05Technical

03Field mappings between tools

The tables below define the exact field mappings at each agent handoff point. Use the monospace field names exactly as shown when building data transformation steps in the orchestration layer.

Handoff 1: Linnworks webhook payload to Stock Level Sync Agent (trigger ingestion)

Source tool
Source field
Destination tool
Destination field
Linnworks
`EventType`
Orchestration layer
`event_type`
Linnworks
`OrderId`
Orchestration layer
`source_reference_id`
Linnworks
`Items[].SKU`
Orchestration layer
`sku`
Linnworks
`Items[].Quantity`
Orchestration layer
`delta_quantity`
Linnworks
`Items[].Location`
Orchestration layer
`source_location`
Shopify webhook
`line_items[].sku`
Orchestration layer
`sku`
Shopify webhook
`line_items[].quantity`
Orchestration layer
`delta_quantity`
Shopify webhook
`id`
Orchestration layer
`source_reference_id`
Amazon SP-API poll
`OrderItems[].SellerSKU`
Orchestration layer
`sku`
Amazon SP-API poll
`OrderItems[].QuantityOrdered`
Orchestration layer
`delta_quantity`
Amazon SP-API poll
`AmazonOrderId`
Orchestration layer
`source_reference_id`

Handoff 2: Linnworks stock read to quantity calculation (Stock Level Sync Agent internal)

Source tool
Source field
Destination tool
Destination field
Linnworks
`StockItemId`
Sync Agent calc
`linnworks_stock_item_id`
Linnworks
`Available`
Sync Agent calc
`current_qty`
Linnworks
`StockLevel`
Sync Agent calc
`total_qty`
Orchestration layer
`delta_quantity`
Sync Agent calc
`delta_quantity`
Sync Agent calc
`new_qty` (current_qty - delta_quantity)
All channel updates
`quantity_to_push`

Handoff 3: Stock Level Sync Agent to Shopify inventory update

Source tool
Source field
Destination tool
Destination field
Google Sheets SKU_Map
`Shopify_Inventory_Item_ID`
Shopify API
`inventory_item_id`
Google Sheets SKU_Map
`SHOPIFY_LOCATION_ID` (from credential store)
Shopify API
`location_id`
Sync Agent calc
`quantity_to_push`
Shopify API
`available`

Handoff 4: Stock Level Sync Agent to Amazon SP-API inventory update

Source tool
Source field
Destination tool
Destination field
Orchestration layer
`sku`
Amazon SP-API
`seller_sku` (path param)
Google Sheets SKU_Map
`Amazon_ASIN`
Amazon SP-API
`asin` (reference)
Credential store
`AMAZON_SELLER_ID`
Amazon SP-API
`sellerId` (path param)
Credential store
`AMAZON_MARKETPLACE_ID`
Amazon SP-API
`marketplaceIds` (query param)
Sync Agent calc
`quantity_to_push`
Amazon SP-API
`fulfillment_availability[].quantity`

Handoff 5: Stock Level Sync Agent to Google Sheets audit log

Source tool
Source field
Destination tool
Destination field
Orchestration layer
`timestamp` (ISO 8601)
Google Sheets Audit_Log
`Timestamp` (col A)
Orchestration layer
`event_type`
Google Sheets Audit_Log
`Event_Type` (col B)
Orchestration layer
`sku`
Google Sheets Audit_Log
`SKU` (col C)
Sync Agent calc
`current_qty`
Google Sheets Audit_Log
`Old_Qty` (col D)
Sync Agent calc
`quantity_to_push`
Google Sheets Audit_Log
`New_Qty` (col E)
Orchestration layer
`channel` (Shopify/Amazon/Linnworks)
Google Sheets Audit_Log
`Channel` (col F)
Orchestration layer
`push_status` (Success/Anomaly/Error)
Google Sheets Audit_Log
`Status` (col G)
Orchestration layer
`error_message` (if any)
Google Sheets Audit_Log
`Notes` (col H)

Handoff 6: Stock Level Sync Agent to Reorder Alert and Finance Sync Agent

Source tool
Source field
Destination tool
Destination field
Google Sheets Audit_Log
`SKU` (col C)
Reorder Agent
`sku`
Google Sheets Audit_Log
`New_Qty` (col E)
Reorder Agent
`updated_qty`
Google Sheets Reorder_Thresholds
`Reorder_Point`
Reorder Agent
`reorder_threshold`
Google Sheets SKU_Map
`Unit_Cost`
Reorder Agent
`unit_cost`

Handoff 7: Reorder Alert and Finance Sync Agent to Slack

Source tool
Source field
Destination tool
Destination field
Reorder Agent
`sku`
Slack Block Kit body
`fields[0].text` (SKU value)
Reorder Agent
`updated_qty`
Slack Block Kit body
`fields[1].text` (Current Qty value)
Reorder Agent
`reorder_threshold`
Slack Block Kit body
`fields[2].text` (Reorder Point value)
Google Sheets Reorder_Thresholds
`Supplier_Code`
Slack Block Kit body
`fields[3].text` (Supplier value)

Handoff 8: Reorder Alert and Finance Sync Agent to Xero

Source tool
Source field
Destination tool
Destination field
Reorder Agent
`sku`
Xero ManualJournal
`Narration` (included in text)
Reorder Agent
`event_type`
Xero ManualJournal
`Narration` (included in text)
Orchestration layer
`timestamp`
Xero ManualJournal
`Narration` (date portion)
Reorder Agent calc
`delta_quantity * unit_cost`
Xero ManualJournal
`JournalLines[0].LineAmount` (inventory asset debit/credit)
Credential store
`XERO_INVENTORY_ASSET_ACCOUNT_CODE`
Xero ManualJournal
`JournalLines[0].AccountCode`
Credential store
`XERO_COGS_ACCOUNT_CODE`
Xero ManualJournal
`JournalLines[1].AccountCode`
Integration and API SpecPage 3 of 4
FS-DOC-05Technical

04Build stack and orchestration

Orchestration layout
Two discrete workflows, one per agent. Workflow 1: Stock Level Sync Agent. Workflow 2: Reorder Alert and Finance Sync Agent. The two workflows share a single credential store. Workflow 2 is triggered by the successful completion event of Workflow 1 (via an internal queue or event bus provided by the orchestration platform), not by a direct API call between agents.
Workflow 1 trigger mechanism
Multi-source webhook listener (Shopify orders/paid, Shopify orders/cancelled, Linnworks ORDER_UPDATED, Linnworks RETURN_CONFIRMED, Linnworks PURCHASE_ORDER_RECEIVED). Each inbound webhook payload is validated for HMAC-SHA256 signature before any processing begins. Amazon order events are detected via a scheduled poll (every 5 minutes) of the SP-API Orders endpoint using the stored AMAZON_LAST_POLL_TS cursor. After each poll the cursor is updated in the credential store.
Workflow 2 trigger mechanism
Internal event trigger fired by Workflow 1 upon successful completion of the Google Sheets audit row append. The trigger payload passes the sku, updated_qty, event_type, unit_cost, and reorder_threshold fields directly to Workflow 2. No external webhook or polling is involved between the two workflows.
Signature validation
Shopify: compare HMAC-SHA256(raw_body, SHOPIFY_WEBHOOK_SECRET) against X-Shopify-Hmac-SHA256 header. Linnworks: compare HMAC-SHA256(raw_body, LINNWORKS_WEBHOOK_SECRET) against X-Linnworks-Signature header. Requests that fail signature validation are rejected with HTTP 401 and logged to the error table. No processing occurs on an unsigned or incorrectly signed payload.
Credential store structure
All secrets stored in the orchestration platform's native encrypted credential/secret store. No credentials in workflow logic, environment variable files, or source control. See code block below for the full credential key list.
Error routing
All workflow errors route to a dedicated internal error handler node. The error handler posts a plain-text Slack message to SLACK_BUYING_CHANNEL_ID with the workflow name, failed step, error message, and timestamp. Unhandled exceptions must never fail silently.
Logging
Every successful sync event appends one row to Google Sheets Audit_Log. Every error event is written to a separate Google Sheets tab (Error_Log) with columns: Timestamp, Workflow, Step, SKU, Error_Code, Error_Message, Retry_Count, Resolution.
Idempotency
Each workflow execution stores a source_reference_id (order ID, return ID, or PO ID) and checks it against the last 500 processed IDs held in a lightweight in-memory or platform-native deduplication store. If a duplicate ID is received (e.g. a webhook replay), the execution is skipped and logged.
All keys must be present and valid before go-live. Rotate Linnworks and Xero tokens at least every 90 days.
// Credential store: complete key list
// (all values stored as encrypted secrets, never hardcoded)

// Linnworks
LINNWORKS_APP_ID
LINNWORKS_APP_SECRET
LINNWORKS_REFRESH_TOKEN
LINNWORKS_LOCATION_ID
LINNWORKS_WEBHOOK_SECRET

// Shopify
SHOPIFY_STORE_URL
SHOPIFY_ACCESS_TOKEN
SHOPIFY_LOCATION_ID
SHOPIFY_WEBHOOK_SECRET

// Amazon Seller Central (SP-API)
AMAZON_LWA_CLIENT_ID
AMAZON_LWA_CLIENT_SECRET
AMAZON_REFRESH_TOKEN
AMAZON_SELLER_ID
AMAZON_MARKETPLACE_ID
AMAZON_ROLE_ARN
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AMAZON_LAST_POLL_TS

// Google Sheets
GOOGLE_SERVICE_ACCOUNT_JSON
GOOGLE_SPREADSHEET_ID
GOOGLE_AUDIT_SHEET_NAME
GOOGLE_THRESHOLD_SHEET_NAME
GOOGLE_SKU_MAP_SHEET_NAME

// Slack
SLACK_BOT_TOKEN
SLACK_BUYING_CHANNEL_ID

// Xero
XERO_CLIENT_ID
XERO_CLIENT_SECRET
XERO_REFRESH_TOKEN
XERO_TENANT_ID
XERO_INVENTORY_ASSET_ACCOUNT_CODE
XERO_COGS_ACCOUNT_CODE

05Error handling and retry logic

Unhandled exceptions must never fail silently. Every integration point has a defined failure behaviour. Any error that does not match a known scenario must still route to the Slack error alert and write to the Error_Log sheet before the workflow terminates.
Integration
Scenario
Required behaviour
Linnworks webhook ingest
HMAC signature validation fails
Reject with HTTP 401. Log to Error_Log. Do not process payload. No retry. Alert Slack error channel.
Linnworks API: stock level read
HTTP 401 (token expired)
Attempt token refresh using LINNWORKS_REFRESH_TOKEN. Retry the read once after refresh. If refresh fails, halt workflow, log error, alert Slack.
Linnworks API: stock level read
HTTP 429 (rate limited) or HTTP 503 (service unavailable)
Retry with exponential backoff: 1s, 2s, 4s (max 3 attempts). If all retries fail, halt workflow, log error, alert Slack. Do not push stale quantities to channels.
Sync Agent: quantity calculation
Calculated new_qty is below zero
Do not push update to any channel. Write anomaly row to Audit_Log with Status = Anomaly. Post structured Slack alert to SLACK_BUYING_CHANNEL_ID listing SKU, current_qty, and delta. Await manual resolution. Resume only if manually re-triggered.
Shopify: inventory level set
HTTP 422 (inventory_item_id not found or location mismatch)
Log error to Error_Log with sku and attempted inventory_item_id. Alert Slack. Do not retry automatically. Requires SKU_Map correction before next run.
Shopify: inventory level set
HTTP 429 (rate limited)
Respect Retry-After header. Wait the specified duration then retry once. If second attempt fails, log and alert Slack. Continue processing remaining SKUs in the batch.
Amazon SP-API: quantity patch
HTTP 403 (LWA token expired or invalid)
Attempt LWA token refresh. Retry patch once. If refresh or retry fails, log to Error_Log, alert Slack, and continue processing remaining SKUs. Log which ASINs were not updated.
Amazon SP-API: order poll
HTTP 429 (rate limited on Orders endpoint)
Respect the x-amzn-RateLimit-Limit header. Skip this poll cycle and resume on the next scheduled poll (5 minutes). Do not update AMAZON_LAST_POLL_TS for the skipped cycle so no events are missed.
Google Sheets: audit log append
HTTP 403 (service account access revoked)
Log error to orchestration platform internal log. Alert Slack error channel immediately. Halt Workflow 2 trigger (do not attempt Slack or Xero posts without an audit trail). Requires credential fix before workflow can resume.
Slack: chat.postMessage
HTTP 429 (rate limited) or network timeout
Retry after Retry-After duration or 5 seconds (whichever is longer). Retry up to 3 times. If all retries fail, write missed alert details to Error_Log sheet. Do not block the Xero post on a Slack failure.
Xero: ManualJournal post
Missing unit_cost for SKU in Google Sheets SKU_Map
Skip the journal post for this SKU. Write to Error_Log with sku and error reason unit_cost_missing. Alert Slack with SKU name and instruction to populate Unit_Cost in SKU_Map before the next run.
Xero: ManualJournal post
HTTP 401 (token expired) or HTTP 403 (tenant access revoked)
Attempt token refresh using XERO_REFRESH_TOKEN. Retry once. If refresh fails, log to Error_Log, alert Slack, and queue the journal details to a Pending_Xero_Posts tab in Google Sheets for manual review and reposting.
Contact support@gofullspec.com if any integration credential needs rotating, a new channel or SKU scope is being added, or a persistent error pattern appears in the Error_Log that is not covered by the scenarios above.
Integration and API SpecPage 4 of 4

More documents for this process

Every document generated for Multichannel Inventory Sync.

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