Open in
Use ThunderPhone with n8n
Install the ThunderPhone node for n8n, connect a server API key, and build a workflow that runs every time a call ends.
n8n is a workflow automation tool. The ThunderPhone package for n8n adds two nodes:
- ThunderPhone Trigger starts a workflow when a call ends (Call Completed) or a call grading run finishes (Call Graded).
- ThunderPhone places outbound calls, adds contacts to campaigns and starts them, gets calls with their transcript and recording, and lists your agents and phone numbers.
It is a verified community node, listed at ThunderPhone on n8n.
Install the node
In the n8n editor, click + to open the nodes panel and search for ThunderPhone. An instance owner may need to set up verified nodes before other users can add them.
On self-hosted n8n, you can also install by package name: open
Settings > Community Nodes and install n8n-nodes-thunderphone. Check community-node risks and your instance policy
before you install.
Create a server API key
- Open the Keys tab
In ThunderPhone, go to Organization → Keys and click Create key.
- Name it
Use a name that says where the key lives, such as "n8n".
- Copy it now
The full
sk_live_...secret is shown once. Copy it before you close the dialog.
Only an admin or owner can create the key, and ThunderPhone treats requests made with it as coming from that person. The trigger and the campaign operations need that person to keep the admin or owner role. Create a server API key covers rotation and revocation.
Add the credential in n8n
- In n8n, create a credential of type ThunderPhone API.
- Paste the key into API Key.
- Save it and run the credential test. The test reads one call from your
organization with
GET /v1/calls?limit=1.
Build a first workflow
This workflow adds a row to a Google Sheet every time a call ends.
- Add the trigger
Add ThunderPhone Trigger, select your ThunderPhone API credential, and set Event to Call Completed.
- Get the call
Add a ThunderPhone node. Set Resource to Call, Operation to Get, and Call ID to the expression
{{ $json.data.call_id }}. The output is the call record plustranscriptsandrecording_url, a short-lived link that isnullwhen the call has no recording. - Append a row
Add a Google Sheets node that appends a row, and map the columns you want from the Get Call output (see the table below).
- Activate the workflow
Save and activate. The trigger registers its Production URL as a webhook endpoint in your ThunderPhone organization. Deactivating the workflow deletes that endpoint.
- Test it
Open an agent in the builder, click Talk, and end the call. Builder test calls are delivered as
web.complete, one of the two events behind Call Completed, so the workflow runs and a row appears.
Useful columns:
| Column | Expression |
|---|---|
| Call ID | {{ $json.call_id }} |
| Direction | {{ $json.direction }} |
| From | {{ $json.from_number }} |
| To | {{ $json.to_number }} |
| Started | {{ $json.start_time }} |
| Duration (s) | {{ $json.duration_seconds }} |
| Status | {{ $json.status }} |
| End reason | {{ $json.end_reason }} |
| Transcript | {{ $json.transcripts.filter(t => typeof t.content === 'string').map(t => t.role + ': ' + t.content).join('\n') }} |
The recording URL expires. Store the call ID and run Get Call again when you need a fresh link.
The trigger outputs the complete event: type, event_id and data. See
telephony.complete / web.complete and
call.graded for every field. Delivery is at least once,
and event_id stays the same across retries of one event, so check it before
a step that must not repeat.
Place outbound calls safely
Place Outbound Call (Resource Outbound Call, Operation Place) takes:
| Field | Meaning |
|---|---|
| Agent Name or ID | A saved agent. The dropdown lists your agents. |
| Phone Number Name or ID | The from number. The dropdown lists only numbers enabled for outbound calls. |
| To Number | Destination in E.164 format, e.g. +14155550199. |
| Variables | JSON object of values for placeholders in the agent prompt. |
| Idempotency Key | A stable ID from the upstream record or event. Required. |
Map the Idempotency Key to an ID from whatever caused the run, such as a
CRM record ID or the trigger's event_id. The node sends
n8n:<node ID>:<your value>, so:
- An automatic retry or Retry execution sends the same key, and
ThunderPhone returns the original call with
idempotent_replay: trueinstead of dialing again. - Two ThunderPhone nodes fed the same record send different keys.
- A blank value fails before any request is sent.
Avoid timestamps, random values, and n8n execution or workflow IDs. A new value on retry places a second real call. The whole key can be at most 128 characters. Reusing a key with a different agent, number or variables fails with a conflict.
Campaigns. Add Contacts (Resource Campaign) adds contacts to a
draft campaign. It takes a Campaign ID and a JSON array of contacts. Each contact needs phone_number; other keys
become call variables. The node fails when every contact is rejected and sets
partial_success: true when only some are. Start requires the checkbox
confirming that the campaign places real calls and spends ThunderPhone
credits. See Outbound campaigns.
Before a workflow starts calls:
- If ThunderPhone asks your organization to confirm that its outbound calls follow the TCPA and other calling laws, an admin must record that confirmation in the dashboard first.
- The from number must be enabled for outbound calls. Numbers you bring from your own carrier qualify once verified. ThunderPhone numbers start inbound-only and can be approved for outbound use: an admin requests it from the Phone Numbers page. See Get a phone number.
- Your organization is responsible for having consent to call each number and for following the calling laws that apply. See Outbound calling laws.
Example workflows
- CRM contacts to a campaign. Add CRM contacts to a draft ThunderPhone campaign, then start the campaign once someone approves the list.
- Completed call to the customer record. On Call Completed, run Get Call and save the transcript and recording link to the matching customer record.
- Low grades to review. On Call Graded, filter on
{{ $json.data.grade.score }}and route low-scoring calls to a review queue with the call ID and grade details. A call can be graded more than once, and each finished grading run fires the trigger, so keep only the latestgraded_atfor each call ID.