Create an agent
Create the rooftop's Vini agent for one agent type. This save completes the "Agent Customization" task.
Save data.agentId from the response: every later call about this agent needs it. This call does not buy a phone number. To turn the agent on or off, see Go-Live.
Auth: Bearer token of a signed-in console user. The console checks it with the identity service, and the configuration store checks it again. The user id is taken from the token. Rate limit: not documented. Processing: synchronous. The call waits for the agent backend and the database write.
Before you call it
agentTypeIdcomes from the rooftop's contracted agents. The console UI reads it from the contracted-agents list.- Get
avatarIdfrom List avatars,tts.voiceIdfrom Browse the voice library, andtts.supportedLanguagesfrom List voice languages. - The rooftop must not already have an active agent of this type. If it does, use Update an agent.
entitymust be one ofsales_inbound,sales_outbound,service_inbound,service_outbound,receptionist,acquisition_outboundorreputation_outbound. The console UI builds it as agent type +_+ call type, orreceptionist.- Send
Authorization: Bearer YOUR_TOKENandContent-Type: application/json.
How the save works
The console forwards the body unchanged to the configuration store (30-second timeout) and returns its status and body unchanged. The configuration store validates the body, then creates the agent in the agent backend first. If that fails, nothing is saved. The agent backend:
- allows one active agent per rooftop and agent type;
- requires
agentNameandtts; - creates a new agent id;
- fills empty first, voicemail and end-call messages from the agent type's defaults;
- sets
transferModetoseamlesswhen it is not sent; - turns off an active receptionist on the rooftop when the new agent is not a receptionist, recall or reputation agent.
Finally, the configuration store saves the whole agent object under the new agent id for this rooftop and agent type. That includes fields it does not forward, such as templateId, areaCode, isReadyToGoLive and fileUrls.
Request body
- Scope it: send
enterpriseId,teamIdandentity. - Keep it a create: do not send
entityConfig.agent.agentIdorteamAgentMappingId. - Describe the agent: send
agentTypeId,agentName,avatarIdandtts, withvoiceIdand at least onesupportedLanguagesentry. - Sales only: send
assertivenessfor sales agents only, as the console UI does.
| Parameter | Type | Required | Description |
|---|---|---|---|
enterpriseId | string | Required | Dealer group. |
teamId | string | Required | Rooftop. |
enterpriseName | string | Optional | Stored with the record. |
teamName | string | Optional | Stored with the record. |
entity | string | Required | Agent type key. See Before you call it. |
entityConfig.agent | object | Required | The agent. Fields below. |
agentTypeId | string | Required | Contracted agent type. |
agentName | string | Required | Name the agent introduces itself with. |
avatarId | string | Required | Avatar. |
tts | object | Required | Voice. Fields below. |
tts.provider | string | Optional | Default: elevenlabs. |
tts.model | string | Optional | Voice model. |
tts.voiceId | string | Required | Voice. |
tts.voiceSettings | object | Optional | stability, similarity_boost, speed (numbers). The console UI sends speed. |
tts.supportedLanguages | string[] | Required | At least one language code. |
agentDescription | string | Optional | Description. |
firstMessage | string | Optional | Greeting during working hours. Default comes from the agent type. |
afterHoursMessage | string | Optional | Greeting after hours. |
voicemailMessage | string | Optional | Voicemail message. Default comes from the agent type. |
endCallMessage | string | Optional | End-of-call message. Default comes from the agent type. |
assertiveness | string | Optional | none, low, medium or high. |
ambientSound | object | Optional | type (office or off) and optional volume (number). |
transferMode | string | Optional | seamless or nudge. Default: seamless. |
transferModeRule | string | Optional | Rule used with nudge. |
reputationConfig | object | Required if | Only for reputation_outbound. Rejected for any other entity. |
templateId, areaCode, isReadyToGoLive, fileUrls | mixed | Optional | Stored only. Not sent to the agent backend. areaCode is 3 characters or null. fileUrls is a string array. |
Sample request
curl -X POST "https://api.spyne.ai/console/v1/product-onboarding/vini/agent" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enterpriseId": "<enterpriseId>",
"teamId": "<teamId>",
"enterpriseName": "Example Motors Group",
"teamName": "Example Motors",
"entity": "sales_inbound",
"entityConfig": {
"agent": {
"agentTypeId": "<agentTypeId>",
"agentName": "Ava",
"avatarId": "<avatarId>",
"firstMessage": "Thanks for calling Example Motors, this is Ava. How can I help?",
"afterHoursMessage": "We are closed right now, but I can still help.",
"voicemailMessage": "Hi, this is Ava from Example Motors. Please call us back.",
"assertiveness": "low",
"ambientSound": { "type": "office", "volume": 0.6 },
"transferMode": "seamless",
"tts": {
"provider": "elevenlabs",
"voiceId": "<voiceId>",
"voiceSettings": { "speed": 1 },
"supportedLanguages": ["en"]
}
}
}
}'import requests
body = {
"enterpriseId": "<enterpriseId>",
"teamId": "<teamId>",
"entity": "sales_inbound",
"entityConfig": {
"agent": {
"agentTypeId": "<agentTypeId>",
"agentName": "Ava",
"avatarId": "<avatarId>",
"transferMode": "seamless",
"tts": {
"provider": "elevenlabs",
"voiceId": "<voiceId>",
"voiceSettings": {"speed": 1},
"supportedLanguages": ["en"],
},
}
},
}
res = requests.post(
"https://api.spyne.ai/console/v1/product-onboarding/vini/agent",
headers={"Authorization": "Bearer YOUR_TOKEN"},
json=body,
)
print(res.status_code, res.json())const res = await fetch('https://api.spyne.ai/console/v1/product-onboarding/vini/agent', {
method: 'POST',
headers: { Authorization: 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' },
body: JSON.stringify({
enterpriseId: '<enterpriseId>',
teamId: '<teamId>',
entity: 'sales_inbound',
entityConfig: {
agent: {
agentTypeId: '<agentTypeId>',
agentName: 'Ava',
avatarId: '<avatarId>',
transferMode: 'seamless',
tts: { provider: 'elevenlabs', voiceId: '<voiceId>', voiceSettings: { speed: 1 }, supportedLanguages: ['en'] },
},
},
}),
});
console.log(res.status, await res.json());Sample response
{
"success": true,
"message": "Agent created successfully",
"data": {
"agentId": "<agentId>",
"entity": "sales_inbound",
"created": true,
"agent": {
"agentTypeId": "<agentTypeId>",
"agentName": "Ava",
"avatarId": "<avatarId>",
"transferMode": "seamless",
"tts": { "provider": "elevenlabs", "voiceId": "<voiceId>", "voiceSettings": { "speed": 1 }, "supportedLanguages": ["en"] },
"agentId": "<agentId>"
}
}
}{
"success": false,
"message": "Validation error",
"errors": [
{ "code": "custom", "path": ["entityConfig", "agent", "avatarId"], "message": "avatarId is required when creating an agent" }
]
}{
"success": false,
"message": "Mapping with agentTypeId '<agentTypeId>' already exists for this team",
"error": "Mapping with agentTypeId '<agentTypeId>' already exists for this team"
}{ "message": "Invalid Token", "error": true, "code": "ERROR_AUTH_401", "details": "", "data": null }{
"success": false,
"message": "Agent was created downstream but no teamAgentMappingId was returned, so the config could not be saved",
"error": "Agent was created downstream but no teamAgentMappingId was returned, so the config could not be saved"
}{ "success": false, "message": "Failed to save agent", "error": "<error message>" }Response parameters (201)
| Parameter | Type | Description |
|---|---|---|
success | boolean | true on success. |
message | string | Agent created successfully. |
data.agentId | string | New agent id (teamAgentMappingId). Use it for every later call about this agent. |
data.entity | string | Agent type key. |
data.created | boolean | true for a create. |
data.agent | object | The stored agent object, including agentId. |
Errors
| Status | Reason | When it happens |
|---|---|---|
400 | Validation error | Missing enterpriseId, teamId, agentTypeId, agentName or avatarId; a bad entity; tts without voiceId or languages; a bad assertiveness or ambientSound.type; reputationConfig on a non-reputation entity. errors lists each problem. |
400 | Message from the agent backend | For example: an agent of this type already exists on the rooftop; agent type not found; agentName or tts missing; transferMode not seamless or nudge. |
401 | Invalid token | Missing or rejected token. The console returns code: ERROR_AUTH_401. The configuration store returns { "status": "401", "message": "Invalid Auth key" }. |
408 | Request timeout | The console could not reach the identity service to check the token. |
500 | Failed to save agent | The database write failed. The agent may already exist in the agent backend. |
500 | No response received from external API | The configuration store did not answer within 30 seconds. |
502 | Bad gateway | The agent backend returned a 5xx or could not be reached, or it returned no agent id. In the second case the agent exists there but is not saved in the configuration store. |
What happens next
- Keep
data.agentId. - The console UI then calls Mark a task done with
taskName: "Agent Customization"and the tab'ssegmentName. The UI shows a success message even if that call fails. - Next task: Assign Number. See Assign a phone number.
Updated about 1 hour ago
