Sync Agents
Synchronizes the local agent_mappings table with the current state of agents in Ultravox. Imports new agents that do not have local mappings, updates existing mappings with the latest Ultravox configuration, and identifies orphaned mappings whose Ultravox agents no longer exist. Supports multiple sync modes and optional orphan cleanup.
Endpoint
| Property | Value |
|---|---|
| Function Name | agents-sync |
| HTTP Method | POST |
| Authentication | Supabase JWT (Bearer token) |
| Required Role | agency_owner or agency_admin |
Request
Headers
Authorization: Bearer <supabase_jwt_token>
Content-Type: application/json
Body
The body is optional. If omitted or unparseable, defaults are used.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | No | Sync mode. One of "full" (default), "import_only", or "update_only". |
remove_orphans | boolean | No | Whether to delete local mappings for agents that no longer exist in Ultravox. Defaults to false. |
Sync Modes:
| Mode | Imports New Agents | Updates Existing | Detects Orphans |
|---|---|---|---|
full | Yes | Yes | Yes |
import_only | Yes | No (marks as unchanged) | Yes |
update_only | No (marks as unchanged) | Yes | Yes |
Response
Success (200)
{
"success": true,
"message": "Synced 5 agents from Ultravox",
"stats": {
"imported": 2,
"updated": 3,
"skipped": 10,
"errors": 0
}
}
| Field | Description |
|---|---|
stats.imported | Number of new agents imported from Ultravox (new local mappings created). |
stats.updated | Number of existing mappings updated with changed Ultravox configuration. |
stats.skipped | Number of agents that had no changes, or were skipped due to mode restrictions. Also includes orphaned agents in the count logic. |
stats.errors | Number of agents that failed to sync. |
The message field summarizes the count of imported plus updated agents.
Error Responses
| Status | Condition |
|---|---|
| 400 | Ultravox API key is not configured for the agency |
| 401 | Missing or invalid authorization header |
| 403 | User is not associated with an agency |
| 403 | User role is not agency_owner or agency_admin |
| 405 | HTTP method is not POST |
| 500 | Failed to retrieve API credentials |
| 500 | Unexpected server error |
| 502 | Ultravox API returned an error when fetching agents |
Behavior
- Authenticates the user via Supabase JWT and verifies they belong to an agency with the
agency_owneroragency_adminrole. - Parses the optional request body for
modeandremove_orphansoptions. - Retrieves the agency's Ultravox API key by calling the
get_agency_credentialsRPC function. - Fetches all agents from Ultravox by paginating through the
/api/agentsendpoint (100 per page) until nonextcursor remains. - Fetches all existing
agent_mappingsrecords for the agency. - Builds lookup structures: a
Mapof existing mappings keyed byultravox_agent_id, and aSetof all Ultravox agent IDs. - For each Ultravox agent, fetches the full agent details via
GET /api/agents/{agent_id}to obtain the completecallTemplate(since the list endpoint may not include it). - New agents (no existing mapping):
- In
update_onlymode, skipped asunchanged. - Otherwise, inserts a new
agent_mappingsrecord withmanaged_by_virsynset tofalse, the full call template configuration (system_prompt, voice, language_hint, temperature, first_speaker_text, recording_enabled, max_duration_seconds, tools), andlast_synced_attimestamp.
- In
- Existing agents (mapping exists):
- In
import_onlymode, skipped asunchanged. - Otherwise, compares key fields (name, system_prompt, voice, language_hint, temperature) to detect changes.
- If changes are detected, updates the mapping record with the latest Ultravox configuration, sets
last_synced_at, and clearssync_error. - If no changes are detected, only updates
last_synced_atand clearssync_error.
- In
- Orphaned mappings (local mapping exists but Ultravox agent does not):
- Always detected regardless of mode.
- If
remove_orphansistrue: unassigns any phone numbers linked to the orphaned mapping (setsagent_mapping_idtonullinagency_phone_numbers), then deletes the mapping. - Reported in results with action
orphaned.
- Returns a summary with counts of imported, updated, skipped, and errored agents.
Database Tables
| Table | Operation | Description |
|---|---|---|
users | Read | Fetches user profile to determine agency_id and role |
agent_mappings | Read | Fetches all existing mappings for the agency |
agent_mappings | Insert | Creates new mappings for imported agents |
agent_mappings | Update | Updates existing mappings with latest Ultravox config, or updates last_synced_at for unchanged agents |
agent_mappings | Delete | Removes orphaned mappings (when remove_orphans is true) |
agency_phone_numbers | Read | Checks for phone numbers assigned to orphaned mappings |
agency_phone_numbers | Update | Unassigns phone numbers from orphaned mappings |
External APIs
| API | Method | Endpoint | Description |
|---|---|---|---|
| Ultravox | GET | /api/agents?limit=100 | Fetches paginated list of all agents (iterates until all pages consumed) |
| Ultravox | GET | /api/agents/{agent_id} | Fetches full details for each agent (to get complete callTemplate) |
Related Functions
- List Agents -- List agents with merged data (single-page fetch)
- Create Agent -- Create a new agent (creates mapping with
managed_by_virsyn=true) - Assign Agent -- Assign agents to clients/campaigns after syncing
- Delete Agent -- Delete agents and their mappings