After building a Voice Agent using our no-code interface, deploy it using our RESTful API to integrate with your existing systems or build custom solutions.
Two Approaches to Triggering Calls
1. API-Based Triggering (Programmatic)
Trigger calls programmatically from your application code.
Process:
- Create a Contact using
/contact/create
- Trigger a call using
/contact/call with the Contact ID
- Receive webhook notifications about call status
Best For:
- Custom applications
- Direct system integration
- Real-time call triggering
- Fine-grained control
Example:
// Create a contact
const contact = await fetch('https://api.thoughtly.com/contact/create', {
method: 'POST',
headers: {
'x-api-token': 'your_api_token',
'team_id': 'your_team_id',
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone_number: '+15551234567',
name: 'John Doe',
email: 'john@example.com'
})
});
// Trigger the call
const call = await fetch('https://api.thoughtly.com/contact/call', {
method: 'POST',
headers: {
'x-api-token': 'your_api_token',
'team_id': 'your_team_id',
'Content-Type': 'application/json'
},
body: JSON.stringify({
contact_id: contact.id,
agent_id: 'your_agent_id'
})
});
2. Automation-Based Triggering (Recommended)
Use Automations to trigger calls via webhooks.
Process:
- Set up an Automation with a webhook trigger
- Send webhook POST requests to trigger calls
- Configure workflow logic in the Thoughtly UI
Best For:
- Team collaboration (non-engineers can modify logic)
- Complex workflows
- No-code/low-code solutions
- Rapid iteration
Benefits:
- Non-technical teams can modify call logic
- No code changes required for workflow updates
- Visual workflow builder for complex scenarios
- Flexible webhook payload for dynamic data
Learn More: Automations Documentation →
Authentication
All API requests require two headers:
{
'x-api-token': 'your_api_token', // Found in dashboard settings
'team_id': 'your_team_id' // Your team identifier
}
Find Your Credentials:
- Log into Thoughtly Dashboard
- Navigate to Settings → Developers
- Copy your API token and Team ID
Security Best Practice: Never expose your API token in client-side code. Always make API calls from your backend server.
Rate Limits
- Limit: 100 requests per minute
- Response:
429 Too Many Requests if exceeded
- Best Practice: Implement exponential backoff for retries
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
Common Integration Patterns
Pattern 1: CRM-Triggered Calls
When a new lead is added to your CRM, trigger a qualification call:
// Webhook from CRM (e.g., Salesforce)
app.post('/webhook/new-lead', async (req, res) => {
const { phone, name, email, company } = req.body;
// Create contact in Thoughtly
const contact = await thoughtly.createContact({
phone_number: phone,
name: name,
email: email,
custom_fields: { company }
});
// Trigger call with qualification agent
await thoughtly.triggerCall({
contact_id: contact.id,
agent_id: 'qualification_agent_id'
});
res.status(200).send('Call triggered');
});
Pattern 2: Calendar-Based Reminders
Send appointment reminders 24 hours before scheduled appointments:
// Daily cron job
cron.schedule('0 9 * * *', async () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
// Get appointments for tomorrow
const appointments = await getAppointments(tomorrow);
// Trigger reminder call for each
for (const apt of appointments) {
await thoughtly.triggerAutomation({
webhook_url: 'your_automation_webhook',
payload: {
contact_phone: apt.phone,
appointment_time: apt.time,
service_name: apt.service
}
});
}
});
Pattern 3: Real-Time Customer Support
Connect voice agent to your support queue:
// When customer requests callback
app.post('/request-callback', async (req, res) => {
const { phone, issue_type, priority } = req.body;
// Create contact with context
const contact = await thoughtly.createContact({
phone_number: phone,
custom_fields: {
issue_type,
priority,
timestamp: new Date().toISOString()
}
});
// Trigger immediate callback
await thoughtly.triggerCall({
contact_id: contact.id,
agent_id: 'support_agent_id',
priority: priority === 'urgent' ? 'high' : 'normal'
});
res.json({ message: 'Callback initiated' });
});
Webhooks: Receiving Call Data
Configure webhooks to receive real-time updates about calls:
// Webhook endpoint to receive call completion data
app.post('/webhook/call-completed', async (req, res) => {
const {
call_id,
agent_id,
duration,
outcome,
transcript,
variables
} = req.body;
// Update your CRM
await crm.updateLead({
phone: variables.phone,
call_outcome: outcome,
call_duration: duration,
last_contacted: new Date()
});
// Send notification to sales team
if (outcome === 'qualified') {
await slack.notify('#sales', `New qualified lead: ${variables.name}`);
}
res.status(200).send('Webhook processed');
});
Learn More: Webhooks Documentation →
SDK & Libraries
JavaScript/TypeScript
npm install @thoughtly/sdk
import { ThoughtlyClient } from '@thoughtly/sdk';
const client = new ThoughtlyClient({
apiToken: process.env.THOUGHTLY_API_TOKEN,
teamId: process.env.THOUGHTLY_TEAM_ID
});
// Create and call
const contact = await client.contacts.create({
phone_number: '+15551234567',
name: 'Jane Doe'
});
await client.calls.trigger({
contact_id: contact.id,
agent_id: 'agent_123'
});
Python
pip install thoughtly-python
from thoughtly import ThoughtlyClient
client = ThoughtlyClient(
api_token=os.getenv('THOUGHTLY_API_TOKEN'),
team_id=os.getenv('THOUGHTLY_TEAM_ID')
)
# Create and call
contact = client.contacts.create(
phone_number='+15551234567',
name='Jane Doe'
)
client.calls.trigger(
contact_id=contact.id,
agent_id='agent_123'
)
API Reference
For complete API documentation, see:
Best Practices
1. Always Validate Phone Numbers
function isValidPhone(phone) {
// E.164 format: +[country code][number]
const regex = /^\+[1-9]\d{1,14}$/;
return regex.test(phone);
}
2. Handle Errors Gracefully
try {
await thoughtly.triggerCall({ contact_id, agent_id });
} catch (error) {
if (error.status === 429) {
// Rate limited - retry later
await queueForRetry({ contact_id, agent_id });
} else if (error.status === 400) {
// Invalid request - log and alert
logger.error('Invalid API request', error);
} else {
// Unexpected error
throw error;
}
}
3. Use Environment Variables
// .env file
THOUGHTLY_API_TOKEN=your_token_here
THOUGHTLY_TEAM_ID=your_team_id_here
THOUGHTLY_AGENT_ID=your_agent_id_here
// In your code
const config = {
apiToken: process.env.THOUGHTLY_API_TOKEN,
teamId: process.env.THOUGHTLY_TEAM_ID,
agentId: process.env.THOUGHTLY_AGENT_ID
};
4. Implement Logging
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'thoughtly.log' })
]
});
logger.info('Call triggered', {
contact_id,
agent_id,
timestamp: new Date()
});
Support & Resources