Create an agent

Create the rooftop's Vini agent for one agent type. This save completes the "Agent Customization" task.

POSThttps://api.spyne.ai/console/v1/product-onboarding/vini/agent
AuthBearer token (console user)Rate limitNot documentedProcessingSynchronous; waits for the agent backend and the database write

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

  • agentTypeId comes from the rooftop's contracted agents. The console UI reads it from the contracted-agents list.
  • Get avatarId from List avatars, tts.voiceId from Browse the voice library, and tts.supportedLanguages from List voice languages.
  • The rooftop must not already have an active agent of this type. If it does, use Update an agent.
  • entity must be one of sales_inbound, sales_outbound, service_inbound, service_outbound, receptionist, acquisition_outbound or reputation_outbound. The console UI builds it as agent type + _ + call type, or receptionist.
  • Send Authorization: Bearer YOUR_TOKEN and Content-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 agentName and tts;
  • creates a new agent id;
  • fills empty first, voicemail and end-call messages from the agent type's defaults;
  • sets transferMode to seamless when 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

Requiredalways sendOptionalcan be left outRequired ifrequired only in the case described
Request checklist
  1. Scope it: send enterpriseId, teamId and entity.
  2. Keep it a create: do not send entityConfig.agent.agentId or teamAgentMappingId.
  3. Describe the agent: send agentTypeId, agentName, avatarId and tts, with voiceId and at least one supportedLanguages entry.
  4. Sales only: send assertiveness for sales agents only, as the console UI does.
ParameterTypeRequiredDescription
enterpriseIdstringRequiredDealer group.
teamIdstringRequiredRooftop.
enterpriseNamestringOptionalStored with the record.
teamNamestringOptionalStored with the record.
entitystringRequiredAgent type key. See Before you call it.
entityConfig.agentobjectRequiredThe agent. Fields below.
agentTypeIdstringRequiredContracted agent type.
agentNamestringRequiredName the agent introduces itself with.
avatarIdstringRequiredAvatar.
ttsobjectRequiredVoice. Fields below.
tts.providerstringOptionalDefault: elevenlabs.
tts.modelstringOptionalVoice model.
tts.voiceIdstringRequiredVoice.
tts.voiceSettingsobjectOptionalstability, similarity_boost, speed (numbers). The console UI sends speed.
tts.supportedLanguagesstring[]RequiredAt least one language code.
agentDescriptionstringOptionalDescription.
firstMessagestringOptionalGreeting during working hours. Default comes from the agent type.
afterHoursMessagestringOptionalGreeting after hours.
voicemailMessagestringOptionalVoicemail message. Default comes from the agent type.
endCallMessagestringOptionalEnd-of-call message. Default comes from the agent type.
assertivenessstringOptionalnone, low, medium or high.
ambientSoundobjectOptionaltype (office or off) and optional volume (number).
transferModestringOptionalseamless or nudge. Default: seamless.
transferModeRulestringOptionalRule used with nudge.
reputationConfigobjectRequired ifOnly for reputation_outbound. Rejected for any other entity.
templateId, areaCode, isReadyToGoLive, fileUrlsmixedOptionalStored 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)

ParameterTypeDescription
successbooleantrue on success.
messagestringAgent created successfully.
data.agentIdstringNew agent id (teamAgentMappingId). Use it for every later call about this agent.
data.entitystringAgent type key.
data.createdbooleantrue for a create.
data.agentobjectThe stored agent object, including agentId.

Errors

StatusReasonWhen it happens
400Validation errorMissing 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.
400Message from the agent backendFor example: an agent of this type already exists on the rooftop; agent type not found; agentName or tts missing; transferMode not seamless or nudge.
401Invalid tokenMissing or rejected token. The console returns code: ERROR_AUTH_401. The configuration store returns { "status": "401", "message": "Invalid Auth key" }.
408Request timeoutThe console could not reach the identity service to check the token.
500Failed to save agentThe database write failed. The agent may already exist in the agent backend.
500No response received from external APIThe configuration store did not answer within 30 seconds.
502Bad gatewayThe 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's segmentName. The UI shows a success message even if that call fails.
  • Next task: Assign Number. See Assign a phone number.

Did this page help you?