This guide shows you how to automatically write every completed HuskyVoiceAI call into a Google Sheet using n8n. You’ll end up with a clean, searchable call log that your team can filter, share, and report on.
What you’ll build
HuskyVoiceAI → (call.completed webhook) → n8n → Google Sheets (Append Row)
You’ll log:
Call ID, status, direction, number dialed
call_duration_seconds (numeric)
Agent name
Analytics (sentiment, interest level, summary, next steps)
Recording URL
Transcript (flattened into one field)
Prerequisites
HuskyVoiceAI account with Webhooks enabled
n8n (Cloud or self-hosted)
Google account access to Google Sheets
A Google Sheet (or permission to create one)
Reliability note: HuskyVoiceAI retries failed webhooks (up to 3 times). Your n8n webhook should return 2xx within 10 seconds.
Step 1 — Create your Google Sheet (Call Log template)
Create a new Google Sheet named: HuskyVoice Call Log
In row 1, paste these headers:
event_id
event_type
created_at
call_id
status
direction
call_to
duration_seconds
agent_name
sentiment
interest_level
summary
next_steps
recording_url
call_transcript
triggered_at
completed_at
✅ Keep duration_seconds numeric so you can chart and aggregate it in Sheets.
Step 2 — Create the n8n workflow
2.1 Add a Webhook trigger node
In n8n, click New Workflow
Add node: Webhook
Configure:
HTTP Method: POST
Path: huskyvoice/call-events
Response Mode: On Received (respond immediately)
Go back to the workflow as data is stored automatically
You will see a Test URL and a Production URL.
Use Test URL while setting up, then switch to Production URL later.
2.2 Connect HuskyVoiceAI webhook to n8n
In HuskyVoiceAI:
Go to Webhooks
Add a new webhook endpoint
Paste your n8n Webhook Test URL
Select events:
call.completed
(Optional later) call.failed
Save
Now trigger a test call (or any call) so HuskyVoiceAI sends a call.completed event.
Back in n8n:
Click Execute workflow (Test mode)
Trigger a call in HuskyVoiceAI
You should see the webhook node receive payload data
Step 3 — Normalize fields (Set node)
Add a Edit Fields (Set) node after the Webhook.
3.1 Configure the Set node
Use these expressions exactly (right side):
event_id → {{$json.event_id}}
event_type → {{$json.event_type}}
created_at → {{$json.created_at}}
call_id → {{$json.data.call_id}}
status → {{$json.data.status}}
direction → {{$json.data.call_direction}}
call_to → {{$json.data.call_to}}
✅ duration_seconds (number):
duration_seconds → {{ Number($json.data.call_duration_seconds) }}
agent_name → {{$json.data.agent_name}}
sentiment → {{$json.data.call_analytics?.sentiment || ""}}
interest_level → {{$json.data.call_analytics?.interest_level || ""}}
summary → {{$json.data.call_analytics?.summary || ""}}
next_steps → {{$json.data.call_analytics?.next_steps || ""}}
recording_url → {{$json.data.call_recording}}
3.2 Flatten transcript into a single text field
Add this field:
And finally:
Step 4 — Append to Google Sheets
Add a node after Set: Google Sheets
4.1 Connect your Google account
In the Google Sheets node, click Credentials
Connect your Google account (OAuth)
4.2 Configure the node
Operation: Append
Document: select your HuskyVoice Call Log
Sheet: select the worksheet (e.g., Sheet1)
4.3 Map fields to columns
Map each header column to the matching Set output field:
Run another test call — you should see a new row appear.
Step 5 — Go live (Production URL)
Once testing works:
Optional: Add basic filtering
If you only want to log certain calls, insert an IF node between Webhook → Set.
Examples:
Only outbound calls
Condition:
{{$json.data.call_direction}} equals outbound
Only log calls longer than 10 seconds
Condition:
{{ Number($json.data.call_duration_seconds) }} is greater than 10
Because webhooks can retry, a rare failure could result in duplicate rows if n8n is slow or Sheets errors temporarily.
Two easy options:
Option A — Use Google Sheets “Lookup” before append
Add a Google Sheets node before Append:
Operation: Lookup
Lookup column: event_id
Lookup value: {{$json.event_id}}
Add an IF node:
If lookup found → do nothing
If lookup not found → Append row
Option B — Add a “Unique” tab and dedupe manually
If you want to keep it super simple, just log everything and use Sheets filters/unique logic later. (Option A is better.)
Security (Optional): Verify webhook signature
If your webhook configuration enables signatures, HuskyVoiceAI will send:
Header: X-Webhook-Signature (HMAC-SHA256)
In n8n you can verify this using a Code node (before Set), using your signing secret stored in credentials/environment variables.
If you want, I’ll provide the exact n8n Code node snippet for signature verification based on your final header format.
Troubleshooting
Webhook is not receiving anything
Ensure your n8n webhook URL is publicly accessible
Confirm HuskyVoiceAI webhook endpoint saved correctly
Check n8n execution logs (Webhook node should show incoming request)
Google Sheets “permission denied”
Reconnect Google credentials
Confirm your Google account has edit access to the Sheet
Transcript is empty
Some calls may not contain transcript. The workflow safely logs an empty string.
Duration shows as text in Sheets
Ensure Set node uses:
{{ Number($json.data.call_duration_seconds) }}
Example call.completed payload (trimmed)
{
"event_id": "evt_5a221b43-8f16-423e-98ee-63c6d80426a4",
"event_type": "call.completed",
"created_at": "2026-02-17T08:27:16.281Z",
"data": {
"call_id": "e5ba3853-0873-4b73-95e5-81814e532956",
"status": "completed",
"call_direction": "outbound",
"call_to": "+917531082106",
"call_duration_seconds": 16,
"agent_name": "OutboundTestProd",
"call_recording": "https://studio.huskyvoice.ai/spark/calls/e5ba3853-0873-4b73-95e5-81814e532956",
"call_analytics": {
"summary": "The user started the call with a simple greeting...",
"sentiment": "neutral",
"interest_level": "low_interest",
"next_steps": "No specific action recommended"
},
"call_transcript": [
{ "speaker": "user", "text": "Hello." }
]
}
}