FS-DOC-05Technical
Integration and API Spec
Refund and Returns Processing
[YourCompany.com] · Customer Support Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for every integration point in the Refund and Returns Processing automation. It covers authentication requirements, required OAuth scopes, webhook and trigger configuration, field mappings between tools, credential-store structure, and error-handling behaviour for each integration. The FullSpec team uses this document to build and configure the orchestration layer. It assumes the reader has API-level familiarity with the tools listed and will be working directly inside the automation platform and each connected service.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by
Zendesk
Helpdesk trigger and ticket resolution
API token (Basic auth over HTTPS)
Suite Team or higher
Agent 1, Agent 2
Shopify
Order lookup and refund initiation
OAuth 2.0 custom app or Admin API key
Basic Shopify or higher
Agent 1, Agent 2
Xero
Credit note creation and reconciliation
OAuth 2.0 (authorization code flow)
Starter or higher (Invoices + Accounts write)
Agent 2
Gmail
Customer notification emails
OAuth 2.0 (Google Workspace)
Google Workspace Business Starter or higher
Agent 2
Slack
High-value case alerts
OAuth 2.0 bot token (Incoming Webhooks)
Free or higher
Agent 2
Workflow automation platform
Orchestration and agent coordination
Internal credential store; per-tool tokens injected at runtime
As selected at build
All agents
Before you connect anything: every integration must be validated against a sandbox or test environment before production credentials are entered into the credential store. For Xero, use the Xero Demo Company. For Shopify, use the development store. For Zendesk, use a staging subdomain. Never run end-to-end tests against live customer data or live financial records.
02Per-tool integration detail
Zendesk
Zendesk serves as both the workflow trigger (new or tagged ticket) and the final resolution step (ticket update and close). The automation platform polls the Zendesk Tickets API for new tickets tagged with a return or refund label, or receives events via a Zendesk webhook. Ticket data is read at trigger and written back at resolution.
Auth method
API token using Basic auth: base64-encode {email}/token:{api_token} and pass in the Authorization header.
Required scopes
tickets:read, tickets:write, users:read. Generate the API token from Admin Center > Apps and Integrations > APIs > Zendesk API.
Webhook / trigger setup
Create a Zendesk Trigger (Admin Center > Objects and Rules > Triggers) that fires on ticket creation or tag addition where tags contain 'return' OR 'refund'. Action: notify active integration via webhook POST to the automation platform's inbound webhook URL. Include X-Zendesk-Webhook-Signature header for signature validation using the shared secret stored in the credential store.
Required configuration
Credential store keys: ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, ZENDESK_API_TOKEN, ZENDESK_WEBHOOK_SECRET. Tags to detect: 'return', 'refund'. Resolution tags to apply on close: 'auto-resolved', 'refund-processed'. Internal note template ID stored as ZENDESK_NOTE_TEMPLATE_ID.
Rate limits
700 requests/minute on Suite Team. At ~124 runs/month (~4/day, ~0.003/second), throttling is not required. Implement a 1-second delay between sequential write calls as a precaution.
Constraints
API token credentials do not support 2FA enforcement bypass; use a dedicated service-account email. Ticket field IDs (custom fields) must be fetched once at build time and stored; do not hardcode.
// Trigger payload (inbound webhook from Zendesk Trigger)
ticket.id : integer
ticket.subject : string
ticket.tags : array<string>
ticket.custom_fields[order_reference] : string
requester.email : string
// Write-back (PATCH /api/v2/tickets/{id})
ticket.status : 'solved'
ticket.tags : append ['auto-resolved','refund-processed']
ticket.comment.body: internal note with refund outcome and reason codeShopify
Shopify is used by Agent 1 to fetch order details for eligibility checking, and by Agent 2 to initiate the refund against the confirmed order. Both operations use the Shopify Admin REST API via a custom app installed on the store.
Auth method
Custom app Admin API access token. Generate from Shopify Admin > Settings > Apps and sales channels > Develop apps. Store token as SHOPIFY_ADMIN_TOKEN.
Required scopes
read_orders, write_orders, read_customers. Assign scopes during custom app configuration. The write_orders scope covers both order reads and refund creation via the Refunds endpoint.
Webhook / trigger setup
No inbound webhook from Shopify required. The automation platform calls Shopify synchronously (GET then POST) when triggered by Zendesk.
Required configuration
Credential store keys: SHOPIFY_STORE_HANDLE, SHOPIFY_ADMIN_TOKEN. Refund reason codes stored as config constants: REFUND_REASON_RETURN, REFUND_REASON_DEFECTIVE. Do not hardcode the store handle.
Rate limits
Shopify REST Admin API uses a leaky-bucket model: 40 requests/second burst, refills at 2 requests/second. At current volume (~4 transactions/day), throttling is not required. Implement retry-after handling for 429 responses using the Retry-After header value.
Constraints
Refunds API requires the order to have at least one fulfilled line item. Partially fulfilled orders must be handled with a partial refund payload specifying exact line item IDs and quantities. Currency must match the order's presentment_currency. Refunds cannot exceed the original order total; validate before calling POST /refunds.json.
// Order fetch (GET /admin/api/2024-01/orders/{order_id}.json)
order.id : integer
order.created_at : ISO8601 datetime
order.financial_status : string
order.line_items[].id : integer
order.line_items[].quantity : integer
order.line_items[].price : decimal string
order.customer.email : string
// Refund creation (POST /admin/api/2024-01/orders/{order_id}/refunds.json)
refund.refund_line_items[].line_item_id : integer
refund.refund_line_items[].quantity : integer
refund.notify : true
refund.note : string (reason code)
// Response
refund.id : integer -> stored for Xero credit note referenceXero
Xero is used by Agent 2 to create a credit note matched to the customer account and original invoice following a successful Shopify refund. The integration uses the Xero Accounting API via an OAuth 2.0 connected app registered in the Xero developer portal.
Auth method
OAuth 2.0 authorization code flow with PKCE. Register a connected app at developer.xero.com. Credential store keys: XERO_CLIENT_ID, XERO_CLIENT_SECRET, XERO_REFRESH_TOKEN, XERO_TENANT_ID. The refresh token must be rotated on each use; the automation platform must persist the latest token pair after every call.
Required scopes
accounting.transactions, accounting.contacts.read. The accounting.transactions scope covers creation and update of credit notes and invoices. Do not request openid or profile unless needed for future user-facing features.
Webhook / trigger setup
No inbound webhook from Xero required. Credit note creation is triggered by the Refund Execution Agent after a confirmed Shopify refund response.
Required configuration
Credential store keys: XERO_CLIENT_ID, XERO_CLIENT_SECRET, XERO_REFRESH_TOKEN, XERO_TENANT_ID, XERO_ACCOUNT_CODE_REFUNDS. The account code for refund transactions (e.g. '200' for Sales) must be confirmed with the finance manager and stored; do not hardcode. Contact lookup uses customer email to match a Xero Contact before posting the credit note.
Rate limits
Xero enforces 60 API calls/minute and 5,000 calls/day per connected app. At ~124 transactions/month (~4/day), throttling is not required. Implement exponential backoff on 429 responses starting at 2 seconds.
Constraints
Credit notes must reference a valid Xero Contact. If no Contact exists for the customer email, the automation must create one before posting the credit note (POST /Contacts). CurrencyCode must match the Shopify order currency. Credit notes cannot be voided via API once approved; the support lead must handle voiding manually in the Xero UI if required.
// Contact lookup (GET /Contacts?where=EmailAddress=="{email}")
Contact.ContactID : GUID -> stored for credit note payload
// Credit note creation (PUT /CreditNotes)
CreditNote.Type : 'ACCRECCREDIT'
CreditNote.Contact.ContactID : GUID
CreditNote.Date : ISO8601 date (today)
CreditNote.LineItems[].Description : string (reason code + order reference)
CreditNote.LineItems[].Quantity : integer
CreditNote.LineItems[].UnitAmount : decimal
CreditNote.LineItems[].AccountCode : XERO_ACCOUNT_CODE_REFUNDS
CreditNote.CurrencyCode : string
CreditNote.Status : 'AUTHORISED'
// Response
CreditNote.CreditNoteID : GUID -> logged to Zendesk internal noteGmail
Gmail is used by Agent 2 to send the customer-facing refund approval email. The integration uses the Gmail API via an OAuth 2.0 service account or delegated user credential tied to a shared support inbox.
Auth method
OAuth 2.0 with delegated domain-wide authority (Google Workspace), or user OAuth consent for a shared mailbox. Credential store keys: GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REFRESH_TOKEN, GMAIL_SENDER_ADDRESS.
Required scopes
https://www.googleapis.com/auth/gmail.send. No read or modify scope is required; the automation only sends outbound email.
Webhook / trigger setup
No inbound webhook from Gmail. Sending is triggered by the Refund Execution Agent after the eligibility decision is confirmed as approved.
Required configuration
Credential store keys: GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REFRESH_TOKEN, GMAIL_SENDER_ADDRESS. Email body templates are stored in the automation platform's config store referenced by GMAIL_TEMPLATE_APPROVAL_ID and GMAIL_TEMPLATE_REJECTION_ID. Template placeholders: {{customer_name}}, {{order_id}}, {{refund_amount}}, {{refund_currency}}, {{estimated_days}}. Do not hardcode template content in workflow nodes.
Rate limits
Gmail API: 250 quota units/second per user; sending a message costs 100 units. At ~4 emails/day, throttling is not required. Daily sending limit is 2,000 messages for Google Workspace; no risk at current volume.
Constraints
Email must be sent from GMAIL_SENDER_ADDRESS to avoid SPF/DKIM failures. The To field must be sourced from the Zendesk ticket requester email; do not use the Shopify customer email as the sole source (validate they match or prefer the Zendesk value). Attachments are not required in the current flow.
// Send message (POST https://gmail.googleapis.com/gmail/v1/users/me/messages/send)
message.raw : base64url-encoded RFC 2822 message
To : ticket.requester.email
From : GMAIL_SENDER_ADDRESS
Subject : 'Your refund for order {{order_id}} has been approved'
Body : rendered GMAIL_TEMPLATE_APPROVAL_ID with field substitutions
// Response
message.id : string -> logged to Zendesk internal note
message.threadId : stringSlack
Slack is used by Agent 2 to post a structured alert to the designated channel when a refund exceeds the configured high-value threshold. The integration uses an incoming webhook URL tied to a dedicated Slack app installed on the workspace.
Auth method
Slack bot OAuth token (xoxb-) with Incoming Webhooks enabled. Credential store keys: SLACK_BOT_TOKEN, SLACK_WEBHOOK_URL, SLACK_ALERT_CHANNEL_ID. The webhook URL is scoped to a single channel at install time.
Required scopes
incoming-webhook, chat:write. If using the Web API (chat.postMessage) instead of the webhook URL, also require channels:read to resolve the channel ID.
Webhook / trigger setup
No inbound webhook from Slack. The automation platform POSTs to SLACK_WEBHOOK_URL or calls chat.postMessage when the refund amount exceeds REFUND_HIGH_VALUE_THRESHOLD (dollar value stored in config, not hardcoded).
Required configuration
Credential store keys: SLACK_BOT_TOKEN, SLACK_WEBHOOK_URL, SLACK_ALERT_CHANNEL_ID. Config key: REFUND_HIGH_VALUE_THRESHOLD (e.g. 150). Message block template stored as SLACK_TEMPLATE_HIGH_VALUE_ALERT_ID.
Rate limits
Slack Incoming Webhooks: 1 message/second per webhook. Slack Web API: tier-2 methods (chat.postMessage) allow 1 request/second. At current volume, throttling is not required.
Constraints
The bot must be invited to SLACK_ALERT_CHANNEL_ID before the first message can be posted. The channel ID (not name) must be stored in the credential store; channel names can change without notice. Message payloads must use Block Kit JSON for structured alerts; plain text is acceptable as a fallback if Block Kit parsing fails.
// POST to SLACK_WEBHOOK_URL (or chat.postMessage)
{
"channel" : SLACK_ALERT_CHANNEL_ID,
"blocks": [
{ "type": "header", "text": { "type": "plain_text", "text": "High-Value Refund Alert" } },
{ "type": "section", "fields": [
{ "type": "mrkdwn", "text": "*Order ID:* {{order_id}}" },
{ "type": "mrkdwn", "text": "*Amount:* ${{refund_amount}}" },
{ "type": "mrkdwn", "text": "*Customer:* {{customer_name}}" },
{ "type": "mrkdwn", "text": "*Reason:* {{reason_code}}" }
]}
]
}
// Response: HTTP 200 'ok'Integration and API SpecPage 1 of 4
FS-DOC-05Technical
03Field mappings between tools
The tables below document the exact field mappings for each agent handoff in the workflow. Source and destination field names are written in monospace to reflect the exact key names used in each API payload. Where a transformation is applied (type cast, concatenation, or conditional logic), it is noted in the destination field column.
Handoff 1: Zendesk ticket to Returns Triage Agent (order lookup in Shopify)
Source tool
Source field
Destination tool
Destination field
Zendesk
`ticket.id`
Shopify / Agent 1 context
`context.zendesk_ticket_id`
Zendesk
`ticket.custom_fields[order_reference]`
Shopify
`order_id` (query param for GET /orders)
Zendesk
`requester.email`
Agent 1 context
`context.customer_email`
Zendesk
`ticket.tags`
Agent 1 context
`context.raw_tags` (array, used to confirm return/refund label)
Zendesk
`ticket.subject`
Agent 1 context
`context.ticket_subject` (used in email template)
Zendesk
`ticket.created_at`
Agent 1 context
`context.ticket_created_at` (ISO8601, used for SLA logging)
Handoff 2: Shopify order data to eligibility engine (Returns Triage Agent)
Source tool
Source field
Destination tool
Destination field
Shopify
`order.id`
Agent 1 context
`context.shopify_order_id`
Shopify
`order.created_at`
Agent 1 eligibility check
`eligibility.order_date` (ISO8601, compared to return window)
Shopify
`order.financial_status`
Agent 1 eligibility check
`eligibility.financial_status` (must be 'paid' or 'partially_paid')
Shopify
`order.line_items[].id`
Agent 2 context
`refund_payload.line_item_ids[]`
Shopify
`order.line_items[].quantity`
Agent 2 context
`refund_payload.quantities[]`
Shopify
`order.line_items[].price`
Agent 2 context
`refund_payload.unit_prices[]`
Shopify
`order.line_items[].product_id`
Agent 1 eligibility check
`eligibility.product_ids[]` (checked against exclusion list)
Shopify
`order.total_price`
Agent 1 context
`context.order_total` (decimal, used for threshold check)
Shopify
`order.currency`
Agent 2 context
`context.currency_code` (passed to Xero and Gmail)
Shopify
`order.customer.first_name`
Gmail
`template_vars.customer_name` (concatenated with last_name)
Shopify
`order.customer.last_name`
Gmail
`template_vars.customer_name` (concatenated with first_name)
Handoff 3: Returns Triage Agent decision to Refund Execution Agent
Source tool
Source field
Destination tool
Destination field
Agent 1 output
`decision.status`
Agent 2 trigger condition
`trigger.approved` (boolean, must equal true to proceed)
Agent 1 output
`decision.reason_code`
Xero + Zendesk
`CreditNote.LineItems[].Description` / `ticket.comment.body`
Agent 1 output
`decision.refund_amount`
Shopify + Xero + Gmail
`refund_payload.amount` / `CreditNote.LineItems[].UnitAmount` / `template_vars.refund_amount`
Agent 1 output
`decision.confidence_score`
Agent 2 context
`context.confidence_score` (logged to internal note only)
Agent 1 output
`context.zendesk_ticket_id`
Zendesk (write-back)
`ticket.id` (target for PATCH)
Agent 1 output
`context.shopify_order_id`
Shopify (refund POST)
`order_id` (path param)
Agent 1 output
`context.customer_email`
Gmail
`message.To`
Handoff 4: Shopify refund confirmation to Xero credit note creation
Source tool
Source field
Destination tool
Destination field
Shopify
`refund.id`
Xero credit note
`CreditNote.Reference` (stored as external reference)
Shopify
`refund.created_at`
Xero credit note
`CreditNote.Date` (ISO8601 date portion only)
Shopify
`refund.transactions[].amount`
Xero credit note
`CreditNote.LineItems[].UnitAmount`
Shopify
`order.currency`
Xero credit note
`CreditNote.CurrencyCode`
Xero
`CreditNote.CreditNoteID`
Zendesk internal note
`ticket.comment.body` (appended as 'Xero CN: {id}')
Handoff 5: Refund Execution Agent to Zendesk ticket resolution
Source tool
Source field
Destination tool
Destination field
Agent 2 output
`outcome.shopify_refund_id`
Zendesk internal note
`ticket.comment.body` (line: 'Shopify refund ID: {id}')
Agent 2 output
`outcome.xero_credit_note_id`
Zendesk internal note
`ticket.comment.body` (line: 'Xero credit note ID: {id}')
Agent 2 output
`outcome.gmail_message_id`
Zendesk internal note
`ticket.comment.body` (line: 'Approval email sent: {id}')
Agent 2 output
`outcome.status`
Zendesk
`ticket.status` set to 'solved'
Agent 2 output
`outcome.tags`
Zendesk
`ticket.tags` appended with ['auto-resolved','refund-processed']
Integration and API SpecPage 2 of 4
FS-DOC-05Technical
04Build stack and orchestration
Orchestration layout
One workflow per agent: Workflow A covers the Returns Triage Agent (Zendesk trigger, Shopify fetch, eligibility check, decision output); Workflow B covers the Refund Execution Agent (triggered by Workflow A approved-decision output, Gmail send, Shopify refund, Xero credit note, Slack alert conditional, Zendesk close). Both workflows share a single credential store. No credentials are stored in workflow node configuration; all secrets are injected at runtime from the credential store by key reference.
Agent 1 trigger mechanism
Webhook (push): Zendesk Trigger posts to the automation platform's inbound webhook URL on ticket creation or tag addition. The webhook payload is validated using HMAC-SHA256 signature verification against ZENDESK_WEBHOOK_SECRET before any processing begins. Fallback: a polling interval of 5 minutes on GET /api/v2/tickets.json?tags=return to catch any missed webhook events.
Agent 2 trigger mechanism
Internal event (push from Workflow A): Workflow A emits a structured approved-decision event containing the full context object. Workflow B is triggered by this internal event; it does not poll any external system. No external webhook is required for Agent 2 activation.
Signature validation
Zendesk webhook: compute HMAC-SHA256 of the raw request body using ZENDESK_WEBHOOK_SECRET; compare to X-Zendesk-Webhook-Signature header value. Reject and log any request where signatures do not match. Slack inbound events (if added in future): validate using X-Slack-Signature with the same pattern using SLACK_SIGNING_SECRET.
Credential store structure
All secrets stored in the automation platform's encrypted credential store. No secret appears in a workflow node, environment variable file, or log output. See code block below for the full key list.
Polling fallback cadence
Zendesk fallback poll: every 5 minutes. Query filters: status=open, tags include 'return' OR 'refund', created_at > last_processed_at. The last_processed_at cursor is persisted in the automation platform's state store to avoid duplicate processing.
Idempotency
All write operations (Shopify refund POST, Xero credit note PUT, Zendesk PATCH, Gmail send) are guarded by an idempotency check. Before each write, the workflow checks whether the operation has already been recorded against the Zendesk ticket ID. If a prior success record exists, the write step is skipped and the existing IDs are used for downstream steps.
Credential store and config key reference. Never log, print, or expose any of these values in workflow output nodes or error messages.
// Credential store: required keys (all values injected at runtime)
// Zendesk
ZENDESK_SUBDOMAIN : string // e.g. 'yourcompany' (no .zendesk.com suffix)
ZENDESK_EMAIL : string // service account email
ZENDESK_API_TOKEN : string // from Admin Center > APIs
ZENDESK_WEBHOOK_SECRET : string // shared secret for HMAC-SHA256 validation
ZENDESK_NOTE_TEMPLATE_ID : string // internal note template reference
// Shopify
SHOPIFY_STORE_HANDLE : string // e.g. 'yourcompany' (no .myshopify.com suffix)
SHOPIFY_ADMIN_TOKEN : string // custom app Admin API access token
// Xero
XERO_CLIENT_ID : string // from Xero developer portal
XERO_CLIENT_SECRET : string // from Xero developer portal
XERO_REFRESH_TOKEN : string // rotated on each token exchange; platform persists latest
XERO_TENANT_ID : string // organisation GUID from GET /connections
XERO_ACCOUNT_CODE_REFUNDS : string // e.g. '200'; confirmed with finance manager
// Gmail
GMAIL_CLIENT_ID : string // Google Cloud Console OAuth 2.0 client
GMAIL_CLIENT_SECRET : string
GMAIL_REFRESH_TOKEN : string // scoped to gmail.send only
GMAIL_SENDER_ADDRESS : string // shared support inbox address
GMAIL_TEMPLATE_APPROVAL_ID : string // template reference in config store
GMAIL_TEMPLATE_REJECTION_ID: string
// Slack
SLACK_BOT_TOKEN : string // xoxb- prefixed bot token
SLACK_WEBHOOK_URL : string // incoming webhook URL for alert channel
SLACK_ALERT_CHANNEL_ID : string // channel ID (not name)
SLACK_SIGNING_SECRET : string // for future inbound event validation
// Workflow config (non-secret, stored in config store not credential store)
REFUND_HIGH_VALUE_THRESHOLD : number // e.g. 150 (USD); confirmed with finance manager
RETURN_WINDOW_DAYS : number // e.g. 30; confirmed with business owner
EXCLUDED_PRODUCT_TAG_LIST : array // e.g. ['final-sale','non-returnable']
The XERO_REFRESH_TOKEN must be updated in the credential store every time it is exchanged. Xero refresh tokens are single-use. If the token is not persisted after each successful token exchange, the next run will fail with a 401 and manual re-authorisation will be required. The automation platform must write the new refresh token back to the credential store as the final step of every Xero API call sequence.
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. If a step cannot be completed after exhausting retries, the automation must log the full error, alert the support team via Slack (using the SLACK_ALERT_CHANNEL_ID), and leave the Zendesk ticket in an open state with an internal note describing what failed. The table below covers all defined failure scenarios across both agents.
Integration
Scenario
Required behaviour
Zendesk (webhook inbound)
Webhook signature validation fails
Reject request with HTTP 401. Log the raw headers and body hash to the error log. Do not process the ticket. Alert via Slack. No retry (invalid signature is not a transient error).
Zendesk (webhook inbound)
Webhook payload missing order_reference field
Route ticket to manual review queue. Post internal note: 'Automation could not extract order reference. Manual review required.' Set ticket tag: 'automation-needs-review'. Alert support lead via Slack.
Shopify (order fetch)
Order not found (404) for provided order_reference
Retry once after 5 seconds. If still 404, post internal note to Zendesk ticket with message 'Order reference not found in Shopify.' Set tag 'automation-needs-review'. Alert support lead via Slack. Do not proceed to eligibility check.
Shopify (order fetch)
Rate limit hit (429 response)
Read Retry-After header value. Wait the specified number of seconds (minimum 2s). Retry up to 3 times with exponential backoff (2s, 4s, 8s). If all retries exhausted, log error and alert via Slack. Leave ticket open.
Shopify (refund POST)
Refund amount exceeds order total (422 validation error)
Do not retry. Log full API error response. Post internal note: 'Refund could not be processed: amount exceeds order total. Manual review required.' Set ticket tag 'automation-failed'. Alert support lead via Slack immediately.
Shopify (refund POST)
Network timeout or 5xx server error
Retry up to 3 times with exponential backoff (5s, 10s, 20s). Before each retry, check idempotency record to confirm no prior successful refund exists for this ticket ID. If all retries fail, alert via Slack and leave ticket open with internal error note.
Xero (token exchange)
Refresh token invalid or expired (401)
Do not retry. Stop workflow execution immediately. Alert the FullSpec team and the process owner via Slack: 'Xero authentication failed. Manual re-authorisation required.' Leave the Zendesk ticket open. Log which ticket ID was being processed so it can be resumed after re-auth.
Xero (credit note creation)
Contact not found for customer email
Attempt to create a new Xero Contact using the customer email and name from context. Retry credit note creation once after contact creation succeeds. If contact creation also fails, log error, post internal note with all refund details for manual Xero entry, and alert finance manager via Slack.
Xero (credit note creation)
5xx or network error
Retry up to 3 times with exponential backoff (5s, 10s, 20s). If all retries fail, post full refund details to Zendesk internal note for manual Xero entry by finance. Alert via Slack. Mark ticket with tag 'xero-manual-required'.
Gmail (send approval email)
Invalid recipient address or bounce (400/5xx)
Log the error and the intended recipient address. Post internal note to Zendesk ticket: 'Customer confirmation email could not be delivered. Manual send required.' Alert support lead. Do not retry automatically for bounce errors. For 5xx from Gmail API, retry once after 10 seconds.
Slack (high-value alert)
Webhook URL returns non-200 or network error
Retry once after 5 seconds. If second attempt fails, log the error but do not block or halt the main workflow. The refund and accounting steps must complete regardless of Slack alert failure. Post a note to the Zendesk ticket: 'Slack alert could not be delivered. Finance team should be notified manually.'
Zendesk (ticket write-back)
PATCH ticket fails (403 permission or 5xx)
Retry up to 2 times with 5-second delay. If retries exhausted, log the full error and all outcome data (refund ID, credit note ID, email ID) to the automation platform's persistent error log. Alert support lead via Slack with all outcome IDs so the ticket can be updated manually. Never discard outcome data on a write-back failure.
All error events must write a structured log entry containing: timestamp (UTC), workflow name, step name, Zendesk ticket ID, error code, error message, and retry count. Log entries must never include raw credential values, customer PII beyond the Zendesk ticket ID, or full API response bodies containing payment data. Contact support@gofullspec.com if any integration point consistently fails after retries are exhausted.
Integration and API SpecPage 4 of 4